Search Unity

How to check if two objects are equal?

Discussion in 'Scripting' started by calmcarrots, Jul 17, 2015.

  1. calmcarrots

    calmcarrots

    Joined:
    Mar 7, 2014
    Posts:
    654
    So I have a pool filled with various bullet types. I use this function to get a bullet out of the pool:

    Code (csharp):
    1. public class GameController : MonoBehaviour
    2. {
    3.     public static GameController current;
    4.     public GameObject redProjectile;
    5.  
    6.     public GameObject GetPooledObject(GameObject obj)
    7.     {
    8.         for (int i = 0; i < pooledObjects.Count; i++)
    9.         {
    10.             if (!pooledObjects[i].activeSelf && Equals(pooledObjects[i], obj))
    11.                 return pooledObjects[i];
    12.         }
    13.         return null;
    14.     }
    15. }
    And here is when it gets called:

    Code (csharp):
    1. GameObject p = GameController.current.GetPooledObject(GameController.current.redProjectile);

    As you could see, GetPooledObject is in the GameController class. GameController also has a variable type of redProjectile. Basically, I want to get the first inactive red projectile from the pool of objects but this is not working well. Im not sure how exactly to do this. Do you recommend doing it some other way?
     
  2. calmcarrots

    calmcarrots

    Joined:
    Mar 7, 2014
    Posts:
    654
    Yo, Im still at this.... Anybody got any ideas or suggestions?

    EDIT: Well thanks for the overwhelming amount of help! I solved it on my own 4 hours after I asked this question! Wow! Thanks!! :D
     
    Last edited: Jul 17, 2015
  3. Kokumo

    Kokumo

    Joined:
    Jul 23, 2010
    Posts:
    416
    I'm late... but well, looks like it works :p.

    Could be very useful for future developers to read your solution... so I would suggest you to share with us your how you solved it.

    Thanks!
     
  4. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    My suggestion would be to expose some property you could check. Enums are a good candidate for this.

    But if you have to do run time type checking it's always worth asking if there is a better way. Perhaps using a seperate pool for each projectile type.
     
  5. Duugu

    Duugu

    Joined:
    May 23, 2015
    Posts:
    241
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Depends on the use case. If there is one and only one red projectile, this would work. If the intent is to grab any red projectile then thy will all have different IDs.

    That said if each object is unique a dictionary would probably make a better choice.
     
    calmcarrots likes this.
  7. HandOfPriam

    HandOfPriam

    Joined:
    Aug 19, 2010
    Posts:
    34
    I wrote an object pool system that did what you are looking for. Since GameObject is a class, which are reference types, any equality based check will compare the memory locations of the two operands. You can compare GameObjects' properties, but there isn't really a way to apply this to an object pool. What you want to do is create some sort of container class for your objects which tracks whether or not they are currently in use.

    Something like:
    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class PooledGameObject {
    4.  
    5.     public GameObject gameObject;
    6.     public bool inUse;
    7.  
    8.     public PooledGameObject (GameObject prefab) {
    9.         gameObject = Instantiate (prefab) as GameObject;
    10.         inUse = false;
    11.     }
    12. }
    13.  
    Change your array to store instances of these pooled objects. When you call your GetPooledObject method, you can iterate through your array and return the first object that's not in use according to the container class.
     
    Last edited: Jul 17, 2015
  8. calmcarrots

    calmcarrots

    Joined:
    Mar 7, 2014
    Posts:
    654
    Well the thing about putting a script on the pooled object and then using GetComponent to see if it is being used is a bit inefficient for my game. I am doing a mini "projectile" hell rpg game. (not bullets :p). I decided just to use create a string constant in the GameController class that would name each projectile.

    Code (csharp):
    1. public const string BLUE_NAME = "Blue_P";
    2. public const string RED_NAME = "Red_P";
    3. public const string GREEN_NAME = "Green_p";
    When I spawn each projectile, I change its name to one of the constants depending on the type of projectile. Here is the new code for pulling out a certain projectile:

    Code (csharp):
    1. public GameObject GetPooledProjectile(string name)
    2. {
    3.     for (int i = 0; i < pooledProjectiles.Count; i++)
    4.     {
    5.         if (!pooledProjectiles[i].activeSelf && pooledProjectiles[i].name == name)
    6.             return pooledProjectiles[i];
    7.     }
    8.     return null;
    9. }
    Calling the function from another class:
    Code (csharp):
    1. GameObject p = GameController.current.GetPooledProjectile(GameController.BLUE_NAME);
    Honestly, Im not happy with the solution of using names to determine its type but this is just a placeholder. I need to figure out a way of actually which object was instantiated from which variable. It works I guess.

    PS Im surprised the Equals function did not work as a solution for this. Does anybody know how to properly use the Equals function??
     
  9. calmcarrots

    calmcarrots

    Joined:
    Mar 7, 2014
    Posts:
    654
    Correct, Im not trying to get each unique ID. Doing so would be equal to `insantiatedObject == prefabVariable`, which would return false. I am trying to figure out if the actual object came from that one variable.
     
  10. HandOfPriam

    HandOfPriam

    Joined:
    Aug 19, 2010
    Posts:
    34
    Unity does not provide ways to determine this. You'll have to implement your own system to determine where the Game Object came from. If you check the code I posted above, you'll notice that it's not a MonoBehaviour. You never access it with GetComponent. Here's a slightly updated version that will let you compare the original reference object:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class PooledGameObject {
    5.  
    6.     public GameObject prefab;
    7.     public GameObject gameObject;
    8.     public bool inUse;
    9.  
    10.     public PooledGameObject (GameObject obj) {
    11.         prefab = obj;
    12.         gameObject = Instantiate (prefab) as GameObject;
    13.         inUse = false;
    14.     }
    15. }
    16.  
    Now, I don't have your pool code, so I'm assuming you're using an array of GameObjects like this:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Pool : MonoBehaviour {
    5.  
    6.     public GameObject prefab;
    7.     public GameObject pooledObjects[];
    8.  
    9.     void Start () {
    10.         pooledObjects = new GameObject[num];
    11.         for (int i = 0; i < num; i++) {
    12.             pooledObjects[i] = Instantiate (prefab) as GameObject;
    13.         }
    14.     }
    15. }
    16.  
    What I suggested would make the code look like this:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Pool : MonoBehaviour {
    5.  
    6.     public GameObject prefab;
    7.     public PooledGameObject pooledObjects[];
    8.  
    9.     void Start () {
    10.         pooledObjects = new PooledGameObject[num];
    11.         for (int i = 0; i < num; i++) {
    12.             pooledObjects[i] = new PooledGameObject (prefab);
    13.         }
    14.     }
    15. }
    16.  
    And would make your code look like this:
    Code (csharp):
    1. public class GameController : MonoBehaviour
    2. {
    3.     public static GameController current;
    4.     public GameObject redProjectile;
    5.  
    6.     public GameObject GetPooledObject(GameObject obj)
    7.     {
    8.         for (int i = 0; i < pooledObjects.Count; i++)
    9.         {
    10.             if (!pooledObjects[i].inUse && Equals(pooledObjects[i].prefab, obj))
    11.                 pooledObjects[i].inUse = true;
    12.                 return pooledObjects[i].gameObject;
    13.         }
    14.         return null;
    15.     }
    16. }
    17.  
    If you would rather use another approach, you could try comparing an object by its tag. Just tag the objects that you want to pool with their own tags, and check that in the loop.
     
    Last edited: Jul 17, 2015
    calmcarrots likes this.
  11. calmcarrots

    calmcarrots

    Joined:
    Mar 7, 2014
    Posts:
    654
    Oh interesting implementation. I will take a look at this and let you know what comes up
     
  12. HandOfPriam

    HandOfPriam

    Joined:
    Aug 19, 2010
    Posts:
    34
    Sorry, had a couple of typos in there (was on my phone). They should be fixed up now.