3
\$\begingroup\$

I have a simple game where you try to go as high up with rockets as possible. I currently store 2 statistics about your playthrough:

  • Current altitude
  • Highest altitude

These statistics are stored in a Dictionary<string,float> where the string key is the name of the statistic. I have two tasks related to stats, setting the statistic, which I do as follows:

public class UpdateAltitude : View
{
    public float AltitudeFactor
    {
        get
        {
            return altitudeFactor;
        }
        set
        {
            altitudeFactor = value;
        }
    }

    [Inject]
    public IDictionary<string, float> Stats
    {
        get;
        set;
    }

    [SerializeField]
    private float altitudeFactor;

    // Update is called once per frame
    private void Update()
    {
        var altitude = AltitudeFactor * transform.position.y;
        Stats["altitude"] = altitude;
        Stats["maxaltitude"] = Mathf.Max(Stats["maxaltitude"], altitude);
    }
}

View here is a baseclass from the StrangeIOC framework that allows me to inject into Unity behaviours. The SerializeField attribute allows me to display the private field in the editor for an artist to use (Unity cannot display properties, so this is a common workaround).

The Stats dictionary is created and injected into my View instances from a StrangeIOC context like so:

var stats = new Dictionary<string, float>()
    {
        {"altitude", 0f},
        {"maxaltitude", 0f}
    };

injectionBinder.Bind<IDictionary<string, float>>().ToValue(stats).ToSingleton();

The other task, displaying the statistic, is done thusly:

public class StatLabel : View
{

    public string FormatString
    {
        get
        {
            return formatString;
        }
        set
        {
            formatString = value;
        }
    }

    [Inject]
    public IDictionary<string, float> Stats
    {
        get;
        set;
    }

    [SerializeField]
    private string statName;

    public string StatName
    {
        get
        {
            return statName;
        }
        set
        {
            statName = value;
        }
    }


    [SerializeField]
    private string formatString;

    private UILabel label;

    protected override void Start()
    {
        base.Start();
        label = GetComponent<UILabel>();
    }

    private void Update()
    {
        label.text = string.Format(FormatString, Stats[StatName]);
    }
}

Here a UILabel is essentially a TextBlock control from the NGUI framework.

My issue is that in order for an artist to work with this within the Unity Framework, they need knowledge of the exact string keys in this dictionary, an enum would be a preferable solution, because they appear in the Unity editor as a combo box of possible options, however this would couple my StatLabel class to this game's enum, and each new game would require a custom version.

I intend soon to add additional statistics, such as speed, max speed, coins, etc, so would like to know if I can improve the existing code to make it more artist-friendly, and reusable, while keeping it extensible.

\$\endgroup\$
  • \$\begingroup\$ Your statistics Dictionary in my mind should be <Enum, float> That way you don't have to type it out correctly each time you can just refer to your StatsEnum. \$\endgroup\$ – d347hm4n Nov 25 '14 at 9:35
1
\$\begingroup\$

I assume by artist you mean graphic or sound effect designers. The logic should independent from its visualisation. How data like altitude is stored or processed is no concern for the artist. To stay in Unity3D, you should create components (or complete prefabs) that render graphics or play sound effects. Having a enum for the dropdown is the preferred way as you mentioned. You map it to the corresponding names in the component for the artits. The component is easy to reuse. In your case extracting UILabel and 'TextBlock' is key. Consider those to styled by artists. You then create copies of the component for speed and coins or make it more generic for those cases.

tl;dr Create components in Unity to separate logic and represantation (think or MVC controller and view) in components. Design view components artist friendly and controller components coder friendly.

\$\endgroup\$
  • \$\begingroup\$ In this case artist can also mean gameplay artists. In my team the artists take on the dual roles of creating art as well as setting the objects up in Unity's inspector (i.e. they create the rocket picture, then create the rocket object with engines, etc, wire up the scripts and set parameters there). My problem with enums and reusability is if I were to take this component to a different project (and I have a few in mind), I would need to change the code for every project in order to swap out the enum. \$\endgroup\$ – Nick Udell Nov 27 '14 at 17:01
  • \$\begingroup\$ If your enum is game specific then it is. I recommend on focusing on the current game at hand and then refactor with the next game. You could also go a more data driven way. Then your artist is going to tweak spreadsheets or XML files or has an additional tool/editor extension for data input/tweaking. \$\endgroup\$ – aggsol Nov 28 '14 at 8:17
  • \$\begingroup\$ I'm actually currently contracted on multiple games, I could see a use case for this class on all of them (and have permission to reuse code in my contracts), but if it's going to be a nightmare to abstract this out a little, it's probably simpler to just rewrite when I need to. \$\endgroup\$ – Nick Udell Nov 28 '14 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.