Tower Defense: Damage Types vs Enemy Armor Types

Currently I am working on a group project to make a tower defense game. I want to add the following damage and armor types to make the game more dynamic (quite similar to Kingdom Rush):

Damages:
Physical (arrow towers, cannon towers)
Magical (mage towers, timeweaver towers (they slow enemies))

Armors:
Light, Medium, Heavy, Mega Armor (15%,30%,45%,80% physical damage reduction respectively)
Light, Medium, Heavy, Super Resistance(15%,30%,45%,80% magical damage reduction respectively)

I am a newcomer to unity, and I am unsure of how to implement the scriping of of assigning these types to the projectile and enemy prefabs, and interaction between them.

you can make enum for each type of armor and damage (and let it just in the assets folder).
Not sure if this should be class (if so, then just make it as class and use as example: NameOfClass.PhysicArmorType.light).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum PhysicArmorType
{
    none, light, middle, heavy
}

public enum MagicArmorType
{
    none, light, middle, heavy
}

public enum DamageType
{
    physical, magical
}

then make prefab for arrow, fireball or what ever

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Arrow : MonoBehaviour
{
    public float damage;
    public DamageType damageType;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag ("Enemy"))
        {
            collision.GetComponent<HpController>().DoDamage(damage, damageType);
        }
    }
}

and on the enemy hp

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HpController : MonoBehaviour
{
    public float hp;
    public MagicArmorType magicArmorType;
    public PhysicArmorType physicArmorType;

    public void DoDamage (float damage, DamageType damageType)
    {
        switch (damageType)
        {
            case DamageType.magical:

                switch (magicArmorType)
                {
                    case MagicArmorType.light:
                        hp -= damage * 0.75f;
                        break;
                    case MagicArmorType.middle:
                        hp -= damage * 0.50f;
                        break;
                    case MagicArmorType.heavy:
                        hp -= damage * 0.25f;
                        break;
                    default:
                        hp -= damage;
                        break;
                }

                break;

            case DamageType.physical:

                switch (physicArmorType)
                {
                    case PhysicArmorType.light:
                        hp -= damage * 0.75f;
                        break;
                    case PhysicArmorType.middle:
                        hp -= damage * 0.50f;
                        break;
                    case PhysicArmorType.heavy:
                        hp -= damage * 0.25f;
                        break;
                    default:
                        hp -= damage;
                        break;
                }

                break;
        }
    }
}
2 Likes

The above example is 100% viable, but since I already wrote this up I’ll leave it here as well. There’s a thousand ways to program a system like this. Just go with whatever makes the most sense to you.

My first instinct would be to use scriptable objects to store armor data. A scriptable object is a class that can hold data and run functions, but is not a monobehavior and does not get attached to a gameobject as a component. You make a definition file for it, then make instances of it and customize the data.

For instance:

using UnityEngine;

// define types of damage, could be in its own DamageType.cs file
public enum DamageType
{
    Physical,
    Magical
}

[CreateAssetMenu(fileName ="New Armor Type")]
public class Armor : ScriptableObject
{
    public DamageType damageType;
    public float damageReduction;
}

After defining this, if you right click in your project files and look under the Create menu, there will be a new entry at the top that says “Armor”. If you click it, it creates a new armor asset. You then name it, and configure the damage and reduction for that armor in the inspector.

Then your units or towers could have a field of type “Armor”, and you can drag one of those assets into the field to define their armor.

Here’s an example usage:

using UnityEngine;

public class GameUnit : MonoBehaviour
{
    public float health;
    public Armor armor;

    public void TakeDamage(DamageType damageType, float damageAmount)
    {
        // if you assigned an armor asset of the damaging type
        if (armor != null && armor.damageType == damageType)
        {
            // reduce the damageAmount by a percentage
            damageAmount -= damageAmount * armor.damageReduction;
        }

        health -= damageAmount;
    }
}

Hope that gives you some stuff to try.

2 Likes

exactly :roll_eyes: And I think scriptable objects will be better for this task (they are not so heavy for pc) , still I didn’t used them much. I should look at them too :smile:

If you’re planning on expending the system later on, enum are probably not the best implementation and you might wanna take a look at interfaces :slight_smile:

1 Like

all right! thanks for the help guys!

@jefferyschoch

So far so good, I created the armors assets, but how do I go about applying the damage types to each kind of tower projectile? How do I add the armor fields to my goblin and orc prefabs? Should I place the armor assets in the scripts folder or the prefab folder?

The easiest way would be to give your projectiles a float field for damage, and a DamageType field, configure those on the prefab. When your projectile hits an enemy, call the enemy’s TakeDamage function and pass the damage and type to it.

I like to use an interface for things that take damage, so that the projectile doesn’t have to look for specific class types, but if you’re not familiar with interfaces then don’t worry about it. If you’re interested I can explain that approach though.

Look at my GameUnit example above for how to add the armor field. You can add a new public variable of type Armor, and assign one of your armor assets to the prefab.

Those armor assets are technically speaking “scriptable object instances”, so I would put them in a Configs folder, and maybe in a subfolder “Armor”. But they can live anywhere, so just organize as you please.

Excellent advice! Thanks for the help! It all works perfectly now

1 Like