Why can't I compare Vector LocalScale?

I was trying to make a grid of objects I can essentially turn on and off using raycasting.

I thought I could maybe use instead of tags or references to gameobjects, the localScale/size of an object, so if I had a bunch of objects all the same size when I clicked on one it would increase their size and when clicked again it would decrease their size. and just compare is local scale to old size or new size.

This is the code I thought might work for it, it doesn’t obviously but I’m unsure why I can’t make it work, is comparing Vector3’s together too much hassle? I there a better way to make a bunch of switches without storing references to objects? Or any other suggestion?

if (Input.GetMouseButtonDown(0)) {
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast (ray, out hit))
            {
                if (hit.collider.tag == "Box")    
                {
                    size = new Vector3 (0.8f, 0.8f, 0.8f);
                    oldSize = new Vector3 (0.5f, 0.5f, 0.5f);
                    selectedObject = hit.transform.gameObject;

                    if (selectedObject.transform.localScale == oldSize)
                    {
                        selectedObject.transform.localScale = size;
                    }

                    if (selectedObject.transform.localScale == size)
                    {
                        selectedObject.transform.localScale = oldSize;
                    }

                }

            }
        }

Here’s the whole thing if you need more context, it’s basically the instantiate objects in a circle script with a few tweaks:

using UnityEngine;
using System.Collections;

public class Circles : MonoBehaviour 
{

    //public Transform transformer;
    //public GameObject[] prefab;
    public int numberOfObjects = 20;
    public float scale = 9;
    private int currentRes;

    private int currentObj = 0;
    private GameObject[] objects = null;
    public GameObject objectsToInstantiate;
    public int poolSize = 0;
    public GameObject ballParent;
    GameObject selectedObject;
    private Vector3 size;
    private Vector3 oldSize;

    void Start()
    {
        objects = new GameObject[poolSize];

        for (int i = 0; i < poolSize; i++)
        {
            objects[i] = Instantiate (objectsToInstantiate) as GameObject;
            objects[i].transform.parent = ballParent.transform;
            objects[i].SetActive (false);
        }
    }

    void ClearObjs()
    {
        for (int i = 0; i < poolSize; i++)
        {
            objects[i].SetActive (false);
        }
    }

    void Update()
    {
        if (currentRes != numberOfObjects)
        {
            ClearObjs ();
            CreateStuff();
        }

        if (Input.GetMouseButtonDown(0)) {
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast (ray, out hit))
            {
                if (hit.collider.tag == "Plane")    
                {
                    size = new Vector3 (0.8f, 0.8f, 0.8f);
                    oldSize = new Vector3 (0.5f, 0.5f, 0.5f);
                    selectedObject = hit.transform.gameObject;

                    if (selectedObject.transform.localScale == oldSize)
                    {
                        selectedObject.transform.localScale = size;
                    }

                    if (selectedObject.transform.localScale == size)
                    {
                        selectedObject.transform.localScale = oldSize;
                    }

                }

            }
        }
    }

    void CreateStuff() {

        currentRes = numberOfObjects;

        for (int i = 0; i < numberOfObjects; i++)
        {
            float angle = (i * Mathf.PI * 2 / numberOfObjects);
            float x = Mathf.Cos (angle) * scale;
            float y = Mathf.Sin (angle) * scale;
            Vector3 pos = new Vector3(x, y, 0);
            ActivateObj(pos);
              transform.parent = gameObject.transform;
        }
    }

    void ActivateObj(Vector3 pos)
    {
        if (objects[currentObj].activeInHierarchy == false)
        {
            objects[currentObj].SetActive (true);
            objects[currentObj].transform.position = pos;
        }
        currentObj++;
        if(currentObj >= poolSize) currentObj = 0;
    }
}

Vectors are made up of 3 floats.

Floats suffer from floating point error.

So comparing floats gets a little whishy washy.

Damn it, I thought it would be fine as I’d labelled them 0.5 and 0.8! Is there a way to work around this?

I could use a bool but I don’t know the best way to store the appropriate references for each object. Could I label each object with an int and compare is it on or off? It just baffles me how to store the state from the object.

If you’re looking for an alternative to tags to mark objects, what I do is make empty classes (scripts) and drop them on the objects. I like it because if I ever want to have more than one tag on something, it’s just a matter of dropping another object on it.

So instead of this:

if (selectedObject.transform.localScale == oldSize)
{
    //Do something
}

You might try something like this (untested):

//Assuming for simplicity that x/y/z scales are all the same:

float tempLocalScaleX = selectedObject.transform.localScale

if (Mathf.Approximately(tempLocalScaleX,oldSize.x)) //<---Don't forget the ".x" at the end of "oldSize" so these are floats instead of Vector3's
{
     //Do something
}

Haven’t tried this myself, but something along these lines might work.

1 Like

I have a habit of doing

if((VectorA - VectorB).sqrMagnitude > threshold)
1 Like

You can check if each component (x,y,z) are nearly equal.

Or from my VectorUtil class I do this:

        public static bool FuzzyEquals(this Vector3 a, Vector3 b)
        {
            return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), 0f, MathUtil.EPSILON_SQR);
        }

Note, my MathUtil.FuzzyEqual is pretty much identical to Mathf.Approximately

I’ve almost got it working, I’ve used a bool array the size of gameObjects array and labelled each of the objects name with an int, and then checked through the array to see if true or false, has been clicked has not been clicked, I think I’ve got the logic without going into MathF, I’ve read somewhere it’s fairly consumptive doing many of those operations, I think the bool array might be quicker

using UnityEngine;
using System.Collections;

public class EuclideanCircles : MonoBehaviour {

    //public Transform transformer;
    //public GameObject[] prefab;
    public int numberOfObjects = 20;
    public float scale = 9;
    private int currentRes;

    private int currentObj = 0;
    private GameObject[] objects = null;
    public GameObject objectsToInstantiate;
    public int poolSize = 0;
    public GameObject ballParent;
    GameObject selectedObject;
    private Vector3 size;
    private Vector3 oldSize;
    private bool[] boolers;
    int index;

    void Start()
    {
        objects = new GameObject[poolSize];

        for (int i = 0; i < poolSize; i++)
        {
            objects[i] = Instantiate (objectsToInstantiate) as GameObject;
            objects[i].transform.parent = ballParent.transform;
            objects[i].SetActive (false);
        }
    }

    void ClearObjs()
    {
        for (int i = 0; i < poolSize; i++)
        {
            objects[i].SetActive (false);
        }
    }

    void Update()
    {
        if (currentRes != numberOfObjects)
        {
            boolers = new bool[numberOfObjects];
            ClearObjs ();
            CreateStuff();
        }

        if (Input.GetMouseButtonDown(0)) {
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast (ray, out hit))
            {
                if (hit.collider.tag == "Plane")    
                {
                    index = int.Parse (hit.collider.name);
                    Debug.Log (index);

                    size = new Vector3 (0.8f, 0.8f, 0.8f);
                    oldSize = new Vector3 (0.5f, 0.5f, 0.5f);
                    selectedObject = hit.transform.gameObject;

                    if (boolers[index] == false)
                        {
                        selectedObject.transform.localScale = size;
                        boolers[index] = true;
                        }

                        else
                        {
                        selectedObject.transform.localScale = oldSize;
                        boolers [index] = false;
                        }
                }
            }
        }
    }

    void CreateStuff() {

        currentRes = numberOfObjects;

        for (int i = 0; i < numberOfObjects; i++)
        {
            float angle = (i * Mathf.PI * 2 / numberOfObjects);
            float x = Mathf.Cos (angle) * scale;
            float y = Mathf.Sin (angle) * scale;
            Vector3 pos = new Vector3(x, y, 0);
            ActivateObj(pos);
              transform.parent = gameObject.transform;
        }
    }

    void ActivateObj(Vector3 pos)
    {
        if (objects[currentObj].activeInHierarchy == false)
        {
            objects[currentObj].SetActive (true);
            objects[currentObj].name = currentObj + "";
            objects[currentObj].transform.position = pos;
        }
        currentObj++;
        if(currentObj >= poolSize) currentObj = 0;
    }
}

EDIT: Sorted.

Thanks for all the responses! I love how there’s so many ways to do the same thing!

My habit now, I’m not sure if it’s the right or wrong way but I label the names when I instantiate stuff, and then you can add x,y and whatever else striaght to the name and then Split and parse.

 point.name =  x + "/" + y;

and then go:

string[] lines = name.Split(new char[]{'/'});
        column = int.Parse(lines[0]);
        row = int.Parse(lines[1]);

Works pretty well for my needs when you don’t want to put a script on each object. I work hardest at being lazy!!

Whatever works. :slight_smile: