Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to test for collision without using strings

Discussion in 'Scripting' started by tibor698, Jan 19, 2014.

  1. tibor698

    tibor698

    Joined:
    Nov 26, 2012
    Posts:
    84
    How to test for collision without using strings or tags ? Currently I am using:

    Code (csharp):
    1.  
    2. if(collision.gameObject.name == "Bullet")
    3. {
    4.     Destroy(gameObject);
    5. }
    Is it maybe better to use define or enum or something else ?
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    You could do GetComponent if that gameobject has a "Bullet" script.

    Or you could reverse the logic and the bullet deal damage to a specific interface implementation.
     
  3. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    I've been using enums, and ironically, I think it was LightStriker who said they are more efficient than comparing strings.

    So, for example, this would be on any object:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TypeDefinition : MonoBehaviour {
    5.  
    6.     public enum ObjectTypes{
    7.         Pickup,
    8.         Exit,
    9.         Button,
    10.         Accelerator,
    11.         InstantBoost,
    12.         JumpBoost
    13.     }
    14.  
    15.     public ObjectTypes typeOfObject;
    16. }
    17.  
    18.  
    You would then select the typeOfObject in the Inspector. Then, when testing for collisions, you would do something like this:
    Code (csharp):
    1.     void OnTriggerEnter(Collider hit){    // when entering an object with a Trigger...
    2.  
    3.         TypeDefinition typeDefinitionComponent = hit.gameObject.GetComponent<TypeDefinition> ();
    4.     //    ObjectTypes ObjectType = TypeDefinition.ObjectTypes;
    5.         if (typeDefinitionComponent != null){
    6.         switch(typeDefinitionComponent.typeOfObject){
    7.             case TypeDefinition.ObjectTypes.Pickup: // if it is a common pickup
    8.                 pickCount++;                        // Increase total pickups counted by one
    9.                 hit.gameObject.SetActive(false);    // Deactivate pickup to "pick up"
    10.             break;
    11.            
    12.             case TypeDefinition.ObjectTypes.Exit:    // if it is the exit
    13.                 pickCount++;                        // still counts as a pickup
    14.                 freezeClock = true;                    // Freeze clock for effect
    15.                 winTime = guiTime;
    16.                 winTimeText = textTime;                // Set winTimeText to now, since delay is here
    17.                 StartCoroutine(WinLevelDelay(1));    // WinLevel stuff in one second for effect
    18.                 hit.gameObject.SetActive(false);    // Deactivate pickup to "pick up"
    19.             break;
    20.  
    21.             case TypeDefinition.ObjectTypes.Button:
    22.                 hit.transform.parent.parent.GetComponent<Control_Button>().Activate();
    23.             break;
    24.  
    25.             case TypeDefinition.ObjectTypes.Accelerator:
    26.                 hit.transform.GetComponent<Control_Accel>().Accelerate();
    27.             break;
    28.            
    29.             case TypeDefinition.ObjectTypes.InstantBoost:
    30.                 hit.transform.GetComponent<Control_Boost>().Boost();
    31.             break;
    32.            
    33.             case TypeDefinition.ObjectTypes.JumpBoost:
    34.                 hit.transform.GetComponent<Control_JBoost>().Fly();
    35.             break;
    36.         } // close switch
    37.         } // close if != null
    38.     }
    I actually copied my code-in-progress as I was too lazy to make pseudo-code.. And I know this works 100% ;)
     
  4. TheShane

    TheShane

    Joined:
    May 26, 2013
    Posts:
    136
    Is that actually faster than comparing strings though? Now you're doing a GetComponent() every time anything enters the trigger.

    Checking strings for equality isn't an expensive task. You can frequently determine it after the first character, and almost always after two. You still have two conditional statements even after you've done the GetComponent().

    I like the code, and setting up enums for categories of objects with meaningful names can make code much easier to read and follow. I'm just wondering if it's actually any faster.

    Have you tried doing any timing on the two methods? The overhead for either method may be negligible in the grand scheme of things depending on how often you have objects setting off triggers.
     
  5. tibor698

    tibor698

    Joined:
    Nov 26, 2012
    Posts:
    84
    LightStriker what do you think is better to destroy the game object in this script or the reverse way you mentioned in a bullet script ?

    MDragon thx. I think I will use enums.
     
  6. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    @tibor: No problem. Also, I have no idea what bullet script you're talking about, but in the AngryBots project example, they use (if I recall correctly) 4 inactive bullets. When you fire, it sets them active and fires them one by one, cycling through them. You should check that out (if I'm even talking about the right thing ;) ).

    Just in case you're referring to the GetComponent inside the switches, those were a later design choice due to having the script rely on the object itself (easier to play animations, customize the individual object, etc).

    For the GetComponent part... I'm not so sure it's that expensive compared to strings. As a few others said, comparing strings is relatively expensive while comparing enums is relatively inexpensive. Also, remember that you're going to access the gameObject one way or another. The GetComponent is additional overheard (accessing-wise) compared to, say, hit.transform.name, but it's also not accessing via a string.

    In the end, I guess it depends on comparing strings (and accessing the name property) vs comparing enums and accessing a component's variable.
     
  7. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    For sure getting a component and comparing an enum is slower than just comparing strings (unless the strings are reallllly long), however speed isn't the only reason for avoiding strings.

    --Eric
     
  8. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Just like Eric said;

    Comparing two Enum is like comparing int, it is blazing fast. 2-4ms for 1 million of iteration.

    Comparing string - let's say 8 characters - is about ten times slower. 30-45ms for 1 millions test.

    Getting a component of a GameObject is about five times slower again... ~200 ms for 1 million Get.

    But string got another issue, they are very hard to maintain properly. If you chance an enum but forget to change it where you test it, the code won't compile. If you change a string but forget to update your code, you will have to search why the behaviour just stopped working.

    However, as you may have notice, you'll never get 1,000,000 operation of any of the above in your game. At that point, you should choose the best design/maintainability/readability over the best performance, unless you're sure you will perform that operation thousand of times per frame!