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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

How to organize Towers in a Tower Defense game-like?

Discussion in 'Scripting' started by Padrox_, Mar 25, 2022.

  1. Padrox_

    Padrox_

    Joined:
    Jun 12, 2021
    Posts:
    15
    Hello developers!

    I'm currently working on a Tower Defense game, and I'm having trouble on how to organize my Towers.

    These are my required criteria for my Tower System:
    - Each tower have a cost
    - Can be upgraded multiple times
    - Different models (prefabs) depending on the current upgrade
    - Different attack paterns and animations depending on the current upgrade
    - Can apply status effect
    - Can have multiple activable abilities (e.g. Slows by 50% all nearby enemies)
    - There are different types of towers, some may deal damage, some may give bonus income every ways, some may enhance the statistics such as the damage or the range of the other towers. The towers shoudn't stick to one unique type, for example, we could have one tower who deals damage, but also give 300$ bonus income every round.

    If possible, I'd like to use ScriptableObjects to store my Tower statistics in the living Assets folder of the project (to be able to modify value while Playtesting)

    I need to precise that I already have a good working CharacterStat class on which I can apply bonus like +50% of the base stat.

    When thinking of every criteria I need to implement, I don't know how to organize my systems.
    I first thought about ScriptableObject or to have different MonoBehaviour for every upgrade of each towers or maybe have one single big MonoBehaviour for every towers. I just think those ways aren't the good one, because I would need to copy some attributes to every new MonoBehaviours.

    So I'm looking for a good pratical way to store my Tower Statistics in the Assets folder, and a way to be able to add different upgrades, with different attack paterns, to be able to apply Status Effect such as Burning, Slow...

    I hope you will be able to help me!
    I stay tuned if you have any questions,
    Thank you in advance,
    Padrox.
     
  2. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    671
    Taken from here.

    Have some kind of base Tower class that includes everything that each tower will share, I imagine that each tower will share a damage variable, range variable, attack rate variable etc...
    Then have child classes that inherit from Tower, e.g. FireTower, which inherits from Tower, so it'll have the same shared variables but you can include new values here too, like fire tick rate or whatever.

    To include your upgrades, it's up to you how you do this. You could have FireTowerTierI, FireTowerTierII, III, IV...
    Or you can include a new variable to your tower base class that dictates upgrade level and set the model accordingly.

    The link I posted above suggests that you make factories for each Tower Type, though it's really up to you how you manage this.

    As for abilities, have interfaces for each ability and implement their methods accordingly.
     
  3. Padrox_

    Padrox_

    Joined:
    Jun 12, 2021
    Posts:
    15
    Hello,

    Firstly, thank you for your quick and precise answer.

    On the first hand, for the ability system, I don't worry that much because I can already figure out how to make it working.
    And on the other, I don't think a TowerType system would properly work with what I have in mind.
    For the Tower class, I don't want all my towers to have Dmg, Range... because an income generator won't use these stats. So I thought about making a Tower class with Cost, Upgrades List (idk how it would be managed but ^^), and so on... And make default classes for the basic classes, like, a class DamageDealer which include Dmg, Range, Rate...,
    an IncomeGenerator class who has a default connection bind to an event such as "WaveEnded", another Enhancer class that would include enhancement properties. And then I could make a class, deriving from the Base Tower class and the other classes I'm interested by...

    For example: FireDancer : BaseTower, DamageDealer, Enhancer

    But I don't really know how could I use ScriptableObject to store the Data of the different Tower's upgrades. It would be useful to be able to change Data in the Assets folder.
    What do you think about the idea?
     
  4. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    671
    C# doesn't support multiple inheritance so two of the three inherited values need to be interfaces. It makes sense for BaseTower to be a class and the other two to be interfaces.
     
  5. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    It sounds like you want to use composition, not inheritance. I mean all the scriptable objects will likely inherit from the same abstract scriptableobject class, but you want to composite multiple types of tower abilities as individual components for your in-scene towers.

    You could treat your scriptableobjects as "TowerComponents" that get added to a Tower monobehaviour. The monobehaviour just holds a list of which scriptableObjects it runs and you can add/remove these objects on the fly in game via the inspector. You can add in a basic api that all the scriptable objects will implement and the tower will just iterate the list of assets attached to it and call the methods on each as needed.
     
  6. Padrox_

    Padrox_

    Joined:
    Jun 12, 2021
    Posts:
    15
    Hey hey,

    First thing first, I want to thank you for your replies.
    I had no idea about Composition before, and it seems to be the perfect solution for my case.
    I red a bit of the concept of composition and I understood the concept of having one Tower monobehaviour, with "Tower Components " attached to it.

    But, I'm not sure to understand the part about the ScriptableObjects as "TowerComponents" and the part of API.
    If could try to provide a simple composition codebase example, it could help me a lot.

    Thank you so much for your help so far,
    Padrox.
     
  7. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    for example
    Code (CSharp):
    1.  
    2. public abstract class TowerComponent: ScriptableObject
    3. {
    4.  public abstract void Enabled(Tower tower);
    5.  public abstract void Update(Tower tower);
    6. }
    a generic scriptableobject asset

    then the monobehaviour would have something like
    Code (CSharp):
    1.  
    2. public class Tower: Monobehaviour
    3. {
    4.    public List<TowerComponent> towerComponents;
    5.    public TowerState towerData;
    6.  
    7.    public void EnableComponents()
    8.    {
    9.        foreach(var component in towerComponents)
    10.        {
    11.             if(component) component.Enabled(this);
    12.        }
    13.    }
    14.  
    15.     private void OnEnable()
    16.     {
    17.         EnableComponents();
    18.     }
    19.  
    20.     private void Update()
    21.     {
    22.        foreach(var component in towerComponents)
    23.        {
    24.             if(component) component.Update();
    25.        }
    26.     }
    27. }
    28.  
    All the behaviours for each individual tower ability get implemented in the scriptable object that you'll derive from the TowerComponent class. The state for the TowerComponents would be stored on the Tower script (in the towerData object) and accessed and updated via the reference thats passed in.

    (Rather... to be clear... instanced data is highly recommended that its not stored on scriptableobjects since it can quickly get confusing and cause issues)

    This way you can have two towers using the same ability but all the instanced state is stored on each individual tower and shared with the other abilities (but only if they need it)on those towers. towerData would store stuff like the towers current range, current damage, attack cooldown timer, etc, details you'll need to define. the benefit of this is that you can put the same ability twice on a tower, effectively enchancing its effectiveness (cause it'll either apply bonus stats twice during Enabled, or calculate damage twice in Update, etc.).

    further more you can sort the list components however you want and see how changes the order of operations the components will do on the fly