Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

RPG Damage Type vs Armor Type and/or Resistance

Discussion in 'Scripting' started by diagadumah, Dec 11, 2018.

  1. diagadumah

    diagadumah

    Joined:
    Feb 1, 2018
    Posts:
    3
    Greetings!
    This is my first post here, so quick introduction... I have been learning C# and Unity for the past little while, and I think I've got at least a decent grasp on things. That said, I am also not a programmer, in my day to day game dev I am an artist, so, please be gentle :D

    On to my question.. So, I was wondering if anyone could help me figure out a clean way to "bind" for lack of better term, a damage type to a resistance or armor type without having to do 100 different If() checks or switch statements with passed through arguments. With the amount of knowledge I have, I feel like there has to be a better way to do what I want, but I still lack enough knowledge to actually know what that would be, or of course I could just be entirely wrong lol.

    The scenario: you attack an enemy (or an enemy attacks you), based on the damage type of the attack, I want to put that attack against a matching armor or resistance type and have the damage resolve. Currently I have two enums, one for DamageType, the other for ResistanceType, and I am just passing the damage type through as an argument for the Attack(). Which means I basically have to do a switch or if() check on the DamageType to put that against the ResistanceType, to reduce the damage done by the ResistanceType Value (which I already have as a variable), and as I said, doing it that way doesn't feel like the "right" way to me.

    Apologies for the long post, and thanks in advance for the help, I could really use some :)
     
  2. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    How many different damage/resitance types do you have? 5? 12? If its a small amount I would just give any weapon/spell each of those for example in a struct. So a sword would fe do 10 melee damage, 0 ranged, 0 ice, 0 fire, 0 lightning, 0 poison etc. A sword of ice would do 15 melee and additionally 5 ice damage. So every thing that can do damage (weapon, spell, trap) has one of these structs with the appropriate damages set.
    And everything that can take damage (player, npc, barrel) has the same set of corresponding resistances. A helmet blocks fe 5 melee and 3 ranged and 0 of the others. This way you just need one local method which takes a damage doer and a damage reciver and calculates the effect at one central place. This can also handle when armor itself is damaged for example. Does that sound like what you are looking for? Or did I understood your question wrong?
     
  3. Reeii

    Reeii

    Joined:
    Feb 5, 2016
    Posts:
    91
    If your system should work like the types in Pokémon, where some types are effective against others and some are not, you could create a struct for each DamageType that contains two arrays, one for the ResistanceTypes it is effective against and one for the others.

    Then, in your attack method, you can check which of these arrays contains the ResistanceType.

    Or, if it's more complex, let's say AttackType X does 2x more damage against ResistanceType Y, but only 1,736x more damage against ResistanceTypeZ, you could create a dictionary with the ResistanceTypes as keys and the damage multipliers as values. Or, instead of the damage multiplier as the value, you could pass a delegate method which applies some complex math on the damage. Or, or, or...
     
  4. diagadumah

    diagadumah

    Joined:
    Feb 1, 2018
    Posts:
    3
    Thanks to both of you. You've given me a few ideas to work with. I will start playing around with structs and some interactions between them as you have suggested. :) Although I have never heard of passing a delegate method through a dictionary before... Would you be able to explain that Reeii?
     
  5. Reeii

    Reeii

    Joined:
    Feb 5, 2016
    Posts:
    91
    I thought it would be simpler than it's looking like right, there will surely be an easier way, but that's my idea anyway. :)
    You have your two enums
    Code (CSharp):
    1.         public enum DamageType {
    2.             attackType1,
    3.             attackType2
    4.             // etc.
    5.         }
    6.  
    7.         public enum ResistanceType {
    8.             resistanceType1,
    9.             resistanceType2
    10.             // etc.
    11.         }
    Then, you have a static Dictionary of DamageTypes which again has a Dictionary of ResistanceTypes and their function to change the damage(confusing, ik).
    Code (CSharp):
    1.  public static Dictionary<DamageType, Dictionary<ResistanceType, Func<float, float>>> damageTypes = new Dictionary<DamageType, Dictionary<ResistanceType, Func<float, float>>>() {
    2.             {DamageType.attackType1, new Dictionary<ResistanceType, Func<float, float>> {
    3.                 { ResistanceType.resistanceType1, baseDamage => { return baseDamage * 2f; }},
    4.                 { ResistanceType.resistanceType2, baseDamage => { return baseDamage * 500f; }}
    5.             }},
    6.             {
    7.                 DamageType.attackType2, new Dictionary<ResistanceType, Func<float, float>> {
    8.                     { ResistanceType.resistanceType1, baseDamage => { return baseDamage + 10; }},
    9.                     { ResistanceType.resistanceType2, baseDamage => { return baseDamage + 500; }}
    10.             }}
    11.         };
    You add an entry for each DamageType that has the DamageType as the key and as the value a new Dictionary. This Dictionary contains each ResistanceType as a key that should affect the damage, the ResistanceType which shouldn't change the damage are left out. The value of the inner Dictionary is the function that returns the changed base damage. Here, you can use lambda expressions to simplify the code (but pay attention to the sheer huge of braces :confused: ).

    Then, you can have such a function to apply the calculate the damage:
    Code (CSharp):
    1.         private static float CalcDamage(float baseDamage, DamageType damageType, ResistanceType resistanceType) {
    2.             Dictionary<ResistanceType, Func<float, float>> damageTypeDictionary = damageTypes[damageType];
    3.             if (damageTypeDictionary.ContainsKey(resistanceType)) { // only apply the delegate function if it exists, if none exists there should be no change to the damage for this resistance type
    4.                 return damageTypeDictionary[resistanceType](baseDamage); // applies the delegate function which modifies the base damage and returns its result
    5.             } else {
    6.                 return baseDamage;
    7.             }
    8.         }
     
  6. diagadumah

    diagadumah

    Joined:
    Feb 1, 2018
    Posts:
    3
    Fantastic thank you very much for explaining that. I've definitely got a lot to think about and some great new information to play around with. Thanks for all of your help. :)