3
\$\begingroup\$

I'm trying to find a smart way to store and retrieve stats for a tower defence game, but am currently unsure as to which approach would be best.

Description:

The stats system should quite basic, there are 4 different towers, with up to 5 different levels each. One important requirement is that the stats should be stored in an XML file so that the game designer easily can access and balance the stats. (He knows nothing about programming)

I can see two ways of doing this:

  1. By creating a TowerStats class which hold values for one type of tower for one level. Something like:

    public class TowerStats2
    {
        public TowerType type;
        public int lvl;
        public int damageLow;
        public int damageHigh;
        public float range;
        public float attackFrequency;
    }
    

Then i would load the stats from the XMl file using Linq and XDocument and load it directly into a TowerStat List. I would do this for each tower so in the end there would be 4 different List's which would hold the different level stats for the specified tower.

  • gunTowerStats[0] would hold level 1 stats of the gun tower
  • rocketTowerStats[2] would be level 3 stats of the rocket tower

When a new tower is bought by the player or when a tower is upgraded, the stats would then be taken from the List so something like:

UpgradeTower()
{
    lvl++;
    towerStats = gunTowerStats[towerLevel - 1]
}
  1. Alternativly I could hardcode all the values, and have one big class which would go something like this:

    gunTowerDamageLvl1 = 4;
    gunTowerDamageLvl2 = 8;
    gunTowerDamageLvl3 = 15;
    rocketTowerDamageLvl1 = 10;
    

you get the point. I know that hardcoding is never never really the way to go. But does that also count for this kind of example where all possible tower attributes are known and will not change? the only thing that will change are the values of these attributes.

Question I'm personally in favour of the first way, but I must admit that I find both ways a bit clumsy, would it be alright to do it one of these ways or is there a much smarter and more obvious way to deal with this that I'm completely unable to see?

I hope my question is understandable.

\$\endgroup\$
  • 2
    \$\begingroup\$ Those statements seem to be contradictory: "are known and will not change and "the game designer easily can access and balance the stats". So, which one stands? ;) \$\endgroup\$ – Maik Semder Feb 12 '16 at 11:37
  • \$\begingroup\$ Sorry I can see how that is unclear. What I mean is that the different kinds of tower attributes such as damage and range will not change, but the values of these attributes will most likely change. I will change my question so it's more clear. \$\endgroup\$ – Ima Napple Feb 12 '16 at 11:46
  • \$\begingroup\$ No worries :) The point I was trying to get at, is to differentiate the type of data you are dealing with. It seems there are 2 types of data: [1.] persistent and constant data that does not change during runtime from the Xml [2.] data like current damage, or tower level and stuff that will change during runtime. Make sense? \$\endgroup\$ – Maik Semder Feb 12 '16 at 11:59
  • \$\begingroup\$ Yes that's true. The damage and range would change when towers are upgraded. In my first example though, the data in the different List's of TowerStats for each tower would not change. They would be loaded in the beginning and the overall (with a lack of a better word) Tower object would have a TowerStats stats variable which would get the stats from the appropriate List depending on the type of tower and the level. \$\endgroup\$ – Ima Napple Feb 12 '16 at 12:11
  • \$\begingroup\$ So, thats the design. 1 class TowerDefinition (or something) for the persistent and never changing data from the Xml with only 1 Instance .. and the other class Tower with many instances, one for each tower, having a reference to the TowerDefinition. \$\endgroup\$ – Maik Semder Feb 12 '16 at 12:33
2
\$\begingroup\$

Firstly, I see no issue (in principle) with the first approach, the XML file. Easily editable, easily extendable.

Secondly, I would still recommend not using XML, and using JSON instead, since it's going to make the saving/loading of the stats significantly easier:

[System.Serializable] 
public class TowerStats2 
{
    public TowerType type;
    public int lvl;
    public int damageLow;
    public int damageHigh;
    public float range;
    public float attackFrequency; 
}

And then instead of having to write annoying boilerplate to convert to/from XML, you can just do

var stats = JsonUtility.FromJSON<TowerStats2>(jsonString);
string jsonStats = JsonUtility.ToJson(stats);

And if you ever add new attributes, it'll still work.

Thirdly, if the XML files are inside the unity Assets folder, meaning to modify them, you need to actually open the project in unity, meaning your designer needs to have unity editor and work within it anyway... ...you might want to look into ScriptableObject, which is basically... A C# class that the unity uses as a prescription for a data storage file, which you can then create in your project as an asset.

How that works in principle is that you can create assets (data files) equivalent to the XML/JSON ones you'd use, except all of the deserialization is automatically handled by unity, you can edit the data in them via inspector, and you can also readily plug them into C# code, assign them into fields in Inspector, all the good standard Unity Editor stuff, so now the workflow for your designer is literally the same as doing anything else within unity editor. So if there's no need for the files to be external to the project (meaning they would be besides the compiled data, still accessible and editable even within the built game), this would be probably the easiest and "most native to Unity" way to do it.

\$\endgroup\$
1
\$\begingroup\$

Although I think @sh code 's answer is the correct way to go, I wanted to add that Unity's new prefab variant workflow is really useful for making related objects have slightly different properties. It also works great when the visuals need to match the variations in internal state, since each variant can have a different meshes or effects.

You could also take a hybrid approach. Use prefab variants that access different scriptable-object settings for internal state, while still being able to vary the visuals.

\$\endgroup\$

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.