1
\$\begingroup\$

I was trying to come up with a structure for a simple TD game that has following elements

  1. Tower Each Tower has a set of properties like range, damage, health etc There could be different types of Towers with different attack types. For eg Tower A can perform attackType 1 and 2 and Tower B can perform attackType 3 and 4

  2. Creep Each Creep has a set of properties like damage, health, bountyPoints etc. There could be different types of Creeps with different abilities just like the Towers

For now I am trying to come with a good design that is scalable and well structured for the above two game elements

This is the skeleton of a Tower class that I have come up with so far. Please comment and suggest changes. Any design patterns that could make life easier

using System.Collections;
using System;

    public enum TowerType
    {
        tA,
        tB,
        tC
    };

    public class Tower {

        private TowerType type;
        private int damage;
        private int range;
        private int health;

        public Tower(TowerType type)
        {
            this.type = type;
            initializeVariables();
        }

        private void initializeVariables()
        {
            if (this.type != null)
            {
                if (this.type == TowerType.tA)
                {
                    this.damage = 20;
                    this.range = 40;
                    this.health = 50;
                }

                else if (this.type == TowerType.tB)
                {
                    this.damage = 30;
                    this.range = 50;
                    this.health = 60;
                }

                else if (this.type == TowerType.tC)
                {
                    this.damage = 60;
                    this.range = 60;
                    this.health = 80;
                }

            }
        }

        public int getDamage()
        {
            return this.damage;
        }

        public int getRange()
        {
            return this.range;
        }

        public int getHealth()
        {
            return this.health;
        }

        public TowerType getTowerType()
        {
            return this.type;
        }

        public string getType(int value)
        {
            return Enum.GetName(typeof(TowerType), value);
        }
    }

So using enums to define various types of towers. But is this a good design? Each Tower would have different damage, range and health.

What if there are 100 different towers? So in my InitializeVariables() would have a cluster of 100 if else statements. How can I improve on this or is there a better way to implement this?

\$\endgroup\$
  • \$\begingroup\$ You could also take the component oriented approach... I am creating a 2d tower defence game now and most scripts are loosely coupled components... When I want a new unique tower I can just drag different scripts onto it for different behaviors. Each script handles it's own Behaviour and doesn't care about other scripts attached. \$\endgroup\$ – Savlon Mar 4 '15 at 20:54
1
\$\begingroup\$

Here is how i think it could be done

class Class1 {
    public enum TowerType { A, B, C };
    static private Dictionary<TowerType, Tower> towerTypesInfo;

    static void init()
    {
        towerTypesInfo= new Dictionary<TowerType, Tower>(100);//100 tower types
        towerTypesInfo.Add(TowerType.A, new Tower(20, 40, 50));
        towerTypesInfo.Add(TowerType.B, new Tower(30, 50, 60));
        //... fill in the rest 98 tower types with their values ...

        //example of making a tower named tower1
        Tower tower1 = new Tower(TowerType.A);
    }

    public class Tower {
        public TowerType type { get; private set; }
        public int damage { get; private set; }
        public int range { get; private set; }
        public int health { get; private set; }

        public Tower(int d, int r, int h)
        {
            damage = d;
            range = r;
            health = h;
        }
        public Tower(TowerType type)
        {
            damage = towerTypesInfo[type].damage;
            range = towerTypesInfo[type].range;
            health = towerTypesInfo[type].health;
}   }   }

You don't need to make a function for every single variable you have, like in java. Just use public int damage { get; private set; }, C# has automated way of doing this with overwriting the default get; set; properties.

Also, You could fill this dictionary from a .txt if you wanted to. you could format the .txt to make it a bit easier to edit

TowerTypesInfo.txt:
A 20 40 50
B 30 50 60
C ...

\$\endgroup\$
  • \$\begingroup\$ This sounds like a good scalable solution. I had a question though if you had a solution for it. Would it be possible to control almost all the parameters like damage, range, health or even add new ones dynamically controlled from a file as you said a text file. For eg: Say if the designers wanted to add a new type of variable to the Tower say wealth or a completely new type of Tower say Tower D. Instead of coming back and hard coding the new changes, would there be a better way to do this? \$\endgroup\$ – ckzilla Mar 4 '15 at 21:37
  • \$\begingroup\$ @ckzilla I misunderstood your comment, if you wanted to add another variable to the tower, that would be pretty tricky to do. i guess you would have to keep a list of objects instead of variables and then cast the variables you have on your text into string/int/float, etc so you would have to specify the variable type and value as well in the .txt. and then you would reference those variables like variablesList(0) would be the damage, etc, but that seems like a strange thing to want to do. \$\endgroup\$ – dimitris93 Mar 4 '15 at 21:57
  • \$\begingroup\$ @ckzilla or you would have an additional dictionary<string, object> where the key to the dictionary would be the variable name and the result dictionary[key] would give you the variables type, so that you can know each variable's type. so you would store that there to know each variables type \$\endgroup\$ – dimitris93 Mar 4 '15 at 22:07
3
\$\begingroup\$

Instead of having a TowerType enum and a lot of if/else/case constructs in your code which handle differences between types, you could make your types of towers separate classes which inherit from an abstract Tower base class.

These classes would set their properties in their constructors. Using sub-classes would also allow you to have a different implementation for the attack-method in each class thus allowing you to implement the different ways of attacking in an elegant way. The same pattern applies to any other situation where you want to run different code depending on the tower type. Like, for example, drawing the tower to the screen.

\$\endgroup\$
  • \$\begingroup\$ That makes sense. But in case where say I wanted to scale my game in future and have more than 50-100 towers then would I need to create 50 different sub-classes for each tower type? \$\endgroup\$ – ckzilla Mar 4 '15 at 21:30
  • 1
    \$\begingroup\$ @ckzilla if you are thinking "in the future" you need to also consider that you might will want to add extra functionalities to the towers and this is where this answer is more flexible than mine i guess. also with this answer you can have different attack methods as phillipp said. I like this approach as well. I guess it depends on what exactly you are planning on doing with your Towers \$\endgroup\$ – dimitris93 Mar 4 '15 at 21:38
2
\$\begingroup\$

I would avoid the general idea of a tower type.

Let tower contain a set of properties that matter. An Attack object (that has its own range, RoF, damage, sound effects, onHit() effect for DoTs, etc.), a model, health, location...

Then build factory classes that are asked to build a "type" of tower by figuring out how to initialize a tower to be a "cannon" or a "mortar". This way your systems never need to look at a tower type. Graphics for instance just draws the model specified at the location specified. It doesn't have to lookup the appropriate model for towertype X each frame for each tower.

What makes this great is that if you want a new tower type, you just make a new initializer that builds those towers with different defaults. Your systems won't need to be "upgraded" to support it.

\$\endgroup\$
  • \$\begingroup\$ This makes sense too. So many good suggestions so far. This one definitely sounds scalable and getting rid of the concept of "tower type" is a good way to do it. I am not experienced with factory patterns. Could you please explain how it would work in this case? From what I understand, all my object creation would be handled by a factory class which would create specific objects for me when I need them. So would there be one factory class handling creation of all my gameobjects like towers, waves of enemies and so on? \$\endgroup\$ – ckzilla Mar 4 '15 at 21:54
0
\$\begingroup\$

You might have misunderstood me a little bit. Not all objects HAVE to use factories. Perhaps only your tower and enemy objects. Maybe your Attack object as well as a Projectile. You'll need to tinker to see what fits the pattern.

Some people would create a generic Entity/GameObject class though. You could do some research on Entity Component Systems to see how that works.

Ultimately though, if a "cannon" is built, you could call public static ITowerFactory.GetFactoryByType(TowerType type); to get a CannonTowerFactory. Just pass it TowerType.Cannon

Then use that to call public Tower ITowerFactory.BuildTower(Vector position);

This method (implemented in CannonTowerFactory) will make a new Tower() and set all its properties accordingly for a cannon tower.

You could do something similar for stamping out enemies of various "types" as well.

\$\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.