Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Using c# class extension for checking tags

Discussion in 'Scripting' started by theblitz, Sep 15, 2016.

  1. theblitz

    theblitz

    Joined:
    Aug 22, 2016
    Posts:
    11
    Not sure if this is the right place to post as it is not a question but a suggestion:

    I am new to Unity but have already noticed a lot of work is based on checking tags of objects to see what we have collided with. This tends to get messy and is open to easy mistakes because of typos.
    It can take ages to notice you have accidentally used a a lower case in comparing a tag or some other smal typos.
    So, what I have done is to use the c# class-extension feature.

    So, for example, if I have two objects with tags in my game I create special code to check them.
    First I create a script (c#) which inherits from object.
    In that script I have methods that check the tag and return true or false. The methods are defined so that c# sees them as extensions.

    For example, in one game I have two objects with tags: Player and Coin.

    So my class reads:

    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections;

    public static class TagsController: object {

    private const string TagPlayer = "Player";
    private const string TagCoin = "Coin";

    public static bool IsPlayer(this GameObject gameObject)
    {
    return gameObject.tag.Equals(TagPlayer);
    }

    public static bool IsPlayer(this Collidercollider)
    {
    return IsPlayer(collider.gameObject);
    }


    public static bool IsCoin(this GameObject gameObject)
    {
    return gameObject.tag.Equals(TagCoin);
    }

    public static bool IsCoin(this Collider collider)
    {
    return IsCoin(collider.gameObject);
    }

    }
    Then to use it all you have to do is:
    if (gameObject.IsPlayer())
    if (collider.IsPlayer())

    and so on.

    In this way the string tag is only held in one place and the code looks MUCH nicer.
     
    Last edited: Sep 15, 2016
  2. CrymX

    CrymX

    Joined:
    Feb 16, 2015
    Posts:
    179
    I don't like using string for multiples reasons, you can't rename them, the typo... So i use enumeration :

    Code (csharp):
    1.  
    2. public enum TagEnum
    3. {
    4. Player ="Player",
    5. Coin ="Coin"
    6. }
    7.  
    8. if(gameObject.Tag == tagEnum.Player.ToString())
    9. {
    10.  
    11. }
    12.  
     
  3. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    It's fine for two tags, but gets exponentially larger for every additional tag. I doubt this is a scalable solution. It's not really making anything neater, its transferring the messiness from one script to another. Its the equivalent of sweeping filth under the rug.

    Another way is to find if an object has a certain component. So a computer enemy would have an AI component for example. The script would serve its function and as an identifier. You'd have to work with inheritance however, so it is a little restrictive for small projects.

    CrymX's solution is probably as general as it can get. Only the enum will grow in size while the rest stay the same.

    I would advise to not use tags though. Becoming dependent on tags destroys the interchangeable nature of scripts between projects. I personally like picking something from one project, and placing it into another without too much hassle of finding out why something doesn't work, and tags are always forgotten. Even worse, the list of tags are different from project to project. I hate them.

    I guess something that will be more helpful is giving us context. What are you trying to achieve which has made you resort to using tags. Collision layers can replace the usage of tags if the goal is differentiating what collides with what.
     
    Last edited: Sep 15, 2016
  4. theblitz

    theblitz

    Joined:
    Aug 22, 2016
    Posts:
    11
    The reason I am working with tags is simply because that what all the examples and tutorials seem to do.
    Not sure what you mean by CrymX's solution.

    I know that it seems a lot but remember that you are storing all the tags in one central place and only need to make changes there.
    When you create a new tag all you need to do is create the two methods and you are done.

    And code like
    gameObject.IsPlayer()
    definitely looks better than
    gameObject.tag == "Player"

    And far less error prone.
     
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    If you're going to go that route then you might as well make a class full of string constants and save the overhead of the ToString calls in every use.
    Code (csharp):
    1.  
    2. public class GameConstants
    3. {
    4.     public const string PlayerTag = "Player";
    5. }
    6.  
    7. if (gameObject.CompareTag(GameConstants.PlayerTag))
    8. {
    9.  
    10. }
    11.  
     
    CrymX likes this.
  6. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    I'm not the only person replying your thread

    Hopefully you can find out for yourself alternatives to using tags. They will become a pain to use with or without your supposed cleaner solution. Again I ask what you are trying to achieve so I can see if an alternative to tags can be used.
     
  7. theblitz

    theblitz

    Joined:
    Aug 22, 2016
    Posts:
    11
    For some reason I didn't notice his reply. :(
     
  8. theblitz

    theblitz

    Joined:
    Aug 22, 2016
    Posts:
    11
    The main idea is for use in scripts which are attached to colliders.
    You many need to do different things depending on what has "collided" with it or what it has collided with.
     
  9. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    There's 2 scenarios in what you just mentioned:
    A) Only the player collides with a coin and not the enemy.
    B) Enemy transforms coin into poison on touch. Player collects coin on touch.(as an example)

    "A" can be done with Collision layers. Simply let the collectibles collision layer not interact with the enemy layer.

    "B" requires checks.
     
  10. theblitz

    theblitz

    Joined:
    Aug 22, 2016
    Posts:
    11
    My case where I used it was in the Space Shooter example.
    I added shields to the player's ship.

    The strength of the shields is reduced when hit but the drop in the strength depends on what hit it (and asteroid or an enemy shot).
    I used one script and checked what hit it. Seemed to be the simplest way to go.

    I am new to all this so it could be I am simply going around it the wrong way around.
     
  11. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    There isn't an absolute right way, just how roundabout, scalable, or generally applicable the solution is.
    There is a wrong way though, usually it just outright doesn't work.

    In this case, I would make a "Damager" script to attach to the objects the shield will collide with.
    In the "Damager" script is the amount of damage the object will cause.
    Then your shield script, if it still needs to, check for the Damager script using GetComponent<Damager>().
    If the script doesn't exist, nothing will happen.
    If the script does exist, the shied takes the damage it should receive from the object with the "Damager" script.

    This is scalable since the number of scripts and lines never change even with 2 or 10 or infinite variety of objects. The "Damager" can be used to affect shield and health if there is health. There is no need to depend on tags either.
     
    Timelog and theblitz like this.
  12. theblitz

    theblitz

    Joined:
    Aug 22, 2016
    Posts:
    11
    I really like that idea.
    Much less code and definitely more object-oriented.
    Damage is controlled by the giver rather than the receiver.
     
  13. CrymX

    CrymX

    Joined:
    Feb 16, 2015
    Posts:
    179
    That sound pretty cool and better for perfomances than enum, thank you KelsoMRK