1
\$\begingroup\$

In my game there's a Unit class, which all soldiers use. Not all soldiers have special abilities which require unique class components (like Stealth class). Special abilities either exist on a unit from the start, or never.

Special classes like Stealth are monobehaviour classes which provide specific functionality, and the fact a unit is or is not Stealth will need referenced by other classes. For example, the classes which handle unit shooting and detection must check whether a unit in proximity is stealth. I'm wondering what is the best way to handle this case with Unity, given components?

Right now the Unit class' Start function checks if the special class exists, and assigns a private boolean to true. This boolean can only get accessed by a get function. Does this make sense for more easily readable and secure code? Or is it overengineering?

private bool isStealth;

if (GetComponent<Stealth>())
{
    isStealth = true;
}

public bool IsStealth()
{
    return isStealth;
}
\$\endgroup\$
2
  • \$\begingroup\$ What does the Stealth class look like? \$\endgroup\$
    – Ed Marty
    Commented Jun 17, 2018 at 18:33
  • \$\begingroup\$ @EdMarty edited, does this help? Stealth will be monobehaviour which does things like fading a unit in or out of stealth mode, which has implications in many other classes like unit detection and shooting. \$\endgroup\$
    – user83633
    Commented Jun 18, 2018 at 7:18

2 Answers 2

1
\$\begingroup\$

Your solution is fine. Although “secure coding” is not what you’re doing so much as “decoupled coding” which is a laudable goal.

An even more decoupled alternative is to have the solution be more generic, so that the Unit class need not know about the Stealth class at all, for example by using an enum. It can then be extended if the Unit has other properties set up via Components without needing to modify the Unit class (more than trivially) for each property.

For example (warning: untested):

[Flags]
public enum UnitProperty {
    Stealth = 1,
    Boss = 2,
    Slow = 4,
    MadeOfJelly = 8,
    //etc.
}

public interface UnitPropertySource {
    UnitProperty GetProperty();
}

public class Stealth : MonoBehaviour, UnitPropertySource {
    public UnitProperty GetProperty() {
        return UnitProperty.Stealth;
    }
    //other stealthy stuff
}


public class Unit : MonoBehaviour {
    private UnitProperty properties;
    private void Start() {
        foreach (var propertySource in GetComponents<UnitPropertySource>()) {
           properties |= propertySource.GetProperty();
        }
    }
    public bool HasProperty(UnitProperty p) {
        return properties & p == p;
    }
    public bool IsStealth {
        get {
            return HasProperty(UnitProperty.Stealth);
        }
    }
    public bool IsMadeOfJelly {
        get {
            return HasProperty(UnitProperty.MadeOfJelly);
        }
    }
}
\$\endgroup\$
-1
\$\begingroup\$

Your approach seems fine as long as a Stealth component cannot be added during runtime. Otherwise you should get rid of the bool field and just write your IsStealth method like so:

public bool IsStealth()
{
    return GetComponent<Stealth>();
}

Because a bool is returned, GetComponent<Stealth>() will be casted automatically.

Unity also provides a special method for validating values in MonoBehaviour called OnValidate. This is useful if you have public fields (or in Unity docs sometimes called properties) that require validation. But in your case it makes more sense to validate during runtime, because the isStealth field should not be public if its value depends on some other component.

\$\endgroup\$
3
  • \$\begingroup\$ Calling GetComponent more than once is unnecessarily expensive just to check existence if its existence will never change. \$\endgroup\$
    – Ed Marty
    Commented Jun 18, 2018 at 14:48
  • \$\begingroup\$ @EdMarty That's basically what I wrote in my very first sentence. \$\endgroup\$
    – narranoid
    Commented Jun 18, 2018 at 19:54
  • \$\begingroup\$ What I mean is in general using GetComponent frequently is expensive, so finding a way to avoid it is better than just ignoring the problem. \$\endgroup\$
    – Ed Marty
    Commented Jun 18, 2018 at 22:59

You must log in to answer this question.