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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Maths problem! [Solved]

Discussion in 'Scripting' started by HAlbera, Feb 4, 2016.

  1. HAlbera

    HAlbera

    Joined:
    Jun 7, 2013
    Posts:
    63
    Hello all!

    I'm having a hard time getting my head around a (probably) very simple math problem.

    I have game that has 3 types of health. If you've played Eve Online you'll know exactly what I'm trying to recreate.

    I have a shield health amount, then an armor health amount and finally a structure health amount.

    Damage will be applied in that order ie. If a shot is fired that has 100 damage at the ship then it will hit first the shield, if there is no shield left then it will hit armor, then structure likewise.

    That's the simple bit and easy to do, what I am struggling with is each 'level' of health has a resistance profile.

    For example the ship has:
    200 shield hit points.
    200 armor hit points.
    and 200 structure hit points.

    The shield can resist:
    40% kinetic damage
    20% thermal
    0% em

    The armor for example:
    20%
    30%
    100%

    Now what I'm interested in is if the shield has only 20 hit points left, and a hit is taken that does 100 kinetic damage, how would I calculate how much of that shot is consumed reducing the shield to 0, factoring in the resistance, so that the remaining amount hits the armor?

    eg. 100 damage - 40% resist = 60 damage (to the shields)
    60 - the remaining 20 hit points = 40 damage, which is totally useless as the resists are different on armor.

    So I need to find how much pre-resistance damage is deducted from the raw damage amount and subtract that from the number, set the shield to 0, and recalculate it again.

    If it helps I am storing the damage in a class with 3 properties called DamagePacket. Here is what I have but I feel like its wrong somehow?
    Code (CSharp):
    1. int DamageAfterResist(int damage, int resist)
    2.     {
    3.         int output = Mathf.RoundToInt(damage - (resist / damage * 100));
    4.         return output;
    5.     }
    6.     int InverseDamageAfterResist(int damage, int resist)
    7.     {
    8.         int output = Mathf.RoundToInt(damage * 1 + (resist / 100));
    9.         return output;
    10.     }
    11.     void TakeDamage(DamagePacket damage)
    12.     {
    13.         if (DamageAfterResist(damage.Kinetic,shieldKineticResistance) >= shieldAmount)
    14.         {        
    15.             damage.Kinetic = damage.Kinetic - InverseDamageAfterResist(shieldAmount, shieldKineticResistance);
    16.             shieldAmount = 0;
    17.         }
    18.  
    19.         //calc armor
    20.  
    21.         //calc structure
    22.  
    23.     }
    With this code a shot that does 100 damage at 40% resistance would deduct 28 from the shots 'power' which is wrong.

    I'm so lost in the sauce.

    Thanks in advance!
     
  2. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    I have not read all your text (apologies) but I can see straight off that you're doing a heap of integer division.

    eg resist/damage will yield an integer result (not float) because both operands are int.

    Simplest way to fix this is to change the types from into to float or just cast the values.

    Code (CSharp):
    1. int DamageAfterResist(float damage, float resist)
    2.     {
    3.         int output = Mathf.RoundToInt(damage - (resist / damage * 100));
    4.         return output;
    5.     }
    6.     int InverseDamageAfterResist(float damage, float resist)
    7.     {
    8.         int output = Mathf.RoundToInt(damage * 1 + (resist / 100));
    9.         return output;
    10.     }
    11.     void TakeDamage(DamagePacket damage)
    12.     {
    13.         if (DamageAfterResist(damage.Kinetic,shieldKineticResistance) >= shieldAmount)
    14.         {        
    15.             damage.Kinetic = damage.Kinetic - InverseDamageAfterResist(shieldAmount, shieldKineticResistance);
    16.             shieldAmount = 0;
    17.         }
    18.  
    19.         //calc armor
    20.  
    21.         //calc structure
    22.  
    23.     }
    or

    Code (CSharp):
    1. int DamageAfterResist(int damage, int resist)
    2.     {
    3.         int output = Mathf.RoundToInt(damage - (resist / (float)damage * 100));
    4.         return output;
    5.     }
    6.     int InverseDamageAfterResist(int damage, int resist)
    7.     {
    8.         int output = Mathf.RoundToInt(damage * 1 + ((float)resist / 100));
    9.         return output;
    10.     }
    11.     void TakeDamage(DamagePacket damage)
    12.     {
    13.         if (DamageAfterResist(damage.Kinetic,shieldKineticResistance) >= shieldAmount)
    14.         {        
    15.             damage.Kinetic = damage.Kinetic - InverseDamageAfterResist(shieldAmount, shieldKineticResistance);
    16.             shieldAmount = 0;
    17.         }
    18.  
    19.         //calc armor
    20.  
    21.         //calc structure
    22.  
    23.     }
     
    HAlbera likes this.
  3. HAlbera

    HAlbera

    Joined:
    Jun 7, 2013
    Posts:
    63
    Okay thanks, I wondered if using ints would have an effect on the code come run time. I'm using a RoundToInt anyway so I assumed it would be okay. I can fix stuff like that not a problem, it's actually the maths im struggling with.

    Can anyone see a potential issue with this instead?

    Code (CSharp):
    1. int DamageAfterResist(int damage, int resist)
    2.     {
    3.         int output = Mathf.RoundToInt(damage - (resist / damage * 100));
    4.         return output;
    5.     }
    6.  
    7.     void TakeDamage(DamagePacket damage)
    8.     {
    9.         if (DamageAfterResist(damage.Kinetic,shieldKineticResistance) >= shieldAmount)
    10.         {          
    11.             damage.Kinetic = damage.Kinetic - shieldAmount + (shieldAmount * (shieldKineticResistance / 100));
    12.             shieldAmount = 0;
    13.         }
    14.  
    15.         //calc armor
    16.  
    17.         //calc structure
    18.  
    19.     }
    Here I'm working out what the remaining shields health is if I add the percentage of resistance onto it, then subtracting that from the total damage left. I think it works?
     
  4. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    I think you may have missed my point (or maybe not :) )

    Your maths is likely to not work because of the float issue (even if there are other issues)

    eg: take your:

    int output =Mathf.RoundToInt(damage -(resist / damage *100));

    And then note:

    Debug.Log("result: " + (5 / 3 * 100));
    Debug.Log("result: " + (5 / 4 * 100));


    Both will print 100

    Debug.Log("result: " + (1/2 * 100));
    Debug.Log("result: " + (1/3 * 100));


    Both will print 0


    I don't think this is what you want.
     
    HAlbera likes this.
  5. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    The resist formula is wrong:

    if resist = 40
    and damage is 10
    output should be 6

    Your formula:
    damage - (resist / damage * 100)
    10 - (40 / 10 * 100) = -390

    Now try this, (read 40% as 40 / 100)
    damage - (damage * resist / 100)
    10 - (10 * 40 / 100) = 6


    ps: inverse damage is also wrong, operators have a priority so the * 1 + breaks the math, try dropping the "1 +" part to have a proper result
     
    Last edited: Feb 4, 2016
    HAlbera likes this.
  6. HAlbera

    HAlbera

    Joined:
    Jun 7, 2013
    Posts:
    63
    OKAY! All sorted, thank-you guys so much!

    I used your formula in the resist cals _met44 and larku you fixed a problem before it arose.

    Thanks a lot guys! Here's a fully functioning example using just one damage type, I will simply copy paste for the other 2.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SHIP_Tank : MonoBehaviour {
    5.  
    6.     //Armor variables.
    7.     public int maximumShield;
    8.     public int shieldAmount;
    9.     public int shieldRegenRate;
    10.     public int shieldRegenAmount;
    11.  
    12.     //Shield Resistances.
    13.     public int shieldEMResistance;
    14.     public int shieldKineticResistance;
    15.     public int shieldThermalResistance;
    16.  
    17.     //Armor variables.
    18.     public int maximumArmor;
    19.     public int armorAmount;
    20.     public int armorRegenRate;
    21.     public int armorRegenAmount;
    22.  
    23.     //TODO: armor resists
    24.     public int armorEMResistance;
    25.     public int armorKineticResistance;
    26.     public int armorThermalResistance;
    27.  
    28.     //Structure variables
    29.     public int maximumStructure;
    30.     public int structureAmount;
    31.  
    32.     public int structureKineticResistance;
    33.     public int structureThermalResistance;
    34.     public int structureEMResistance;
    35.     //TODO: engineer skills
    36.  
    37.     int DamageAfterResist(int damage, int resist)
    38.     {
    39.         int output = Mathf.RoundToInt(damage - (damage * (float)resist / 100));
    40.         return output;
    41.     }
    42.  
    43.     void TakeDamage(DamagePacket damage)
    44.     {
    45.  
    46.         //KINETIC DAMAGE CALCULATIONS!
    47.         //If the (Kinetic) damage is more than the remaining shields.
    48.         if (DamageAfterResist(damage.Kinetic,shieldKineticResistance) >= shieldAmount)
    49.         {  
    50.             Debug.Log("Calculating S");
    51.             //deduct the amount from the damagepacket
    52.             damage.Kinetic = damage.Kinetic - shieldAmount + (shieldAmount * (shieldKineticResistance / 100));
    53.             //set shields to 0.
    54.             shieldAmount = 0;
    55.             //Armor Calcs
    56.             if (DamageAfterResist(damage.Kinetic,armorKineticResistance) >= armorAmount)
    57.             {  
    58.                 Debug.Log("Calculating A");
    59.                 //deduct the amount from the damagepacket
    60.                 damage.Kinetic = damage.Kinetic - armorAmount + (armorAmount * (armorKineticResistance / 100));
    61.                 //set armor to 0.
    62.                 armorAmount = 0;
    63.                 //Structure Calcs
    64.                 if (DamageAfterResist(damage.Kinetic,structureKineticResistance) >= structureAmount)
    65.                 {  
    66.                     Debug.Log("Calculating Str");
    67.                     //deduct the amount from the damagepacket
    68.                     damage.Kinetic = damage.Kinetic - structureAmount + (structureAmount * (structureKineticResistance / 100));
    69.                     //set structure to 0.
    70.                     structureAmount = 0;
    71.                     return;
    72.                 }
    73.                 else
    74.                 {
    75.                     Debug.Log("ELSE Structure");
    76.                     structureAmount -= DamageAfterResist(damage.Kinetic, structureKineticResistance);
    77.                     return;
    78.                 }
    79.             }
    80.             else
    81.             {
    82.                 Debug.Log("ELSE Armor");
    83.                 armorAmount -= DamageAfterResist(damage.Kinetic, armorKineticResistance);
    84.                 return;
    85.             }
    86.         }
    87.         else
    88.         {
    89.             Debug.Log("ELSE Shield");
    90.             shieldAmount -= DamageAfterResist(damage.Kinetic, shieldKineticResistance);
    91.             return;
    92.         }
    93.  
    94.     }
    95.  
    96.     void BeforeTick()
    97.     {
    98.  
    99.     }
    100.  
    101.     void DoTick()
    102.     {
    103.  
    104.     }
    105.  
    106.     // Use this for initialization
    107.     void Start ()
    108.     {
    109.         shieldAmount = 110;
    110.         armorAmount = 199;
    111.         structureAmount = 45;
    112.  
    113.         shieldKineticResistance = 40;
    114.         armorKineticResistance = 50;
    115.         structureKineticResistance = 0;
    116.     }
    117.  
    118.     // Update is called once per frame
    119.     void Update ()
    120.     {
    121.  
    122.     }
    123.  
    124.     void OnGUI(){
    125.         if (GUI.Button(new Rect(0,0,50,50),"Eat a dick")){
    126.             DamagePacket dp = new DamagePacket();
    127.             dp.Kinetic = 22;
    128.             TakeDamage(dp);
    129.         }
    130.         GUI.Label(new Rect(0,50,200,50),shieldAmount.ToString());
    131.         GUI.Label(new Rect(0,100,200,50),armorAmount.ToString());
    132.         GUI.Label(new Rect(0,150,200,50),structureAmount.ToString());
    133.     }
    134. }
    135.  
    Oh and you'll want DamagePacket.cs too ;P

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class DamagePacket {
    5.  
    6.     private int _Thermal;
    7.     public int Thermal
    8.     {
    9.         get
    10.         {
    11.             return _Thermal;
    12.         }
    13.         set
    14.         {
    15.             _Thermal = value;
    16.         }
    17.     }
    18.     private int _Kinetic;
    19.     public int Kinetic
    20.     {
    21.         get
    22.         {
    23.             return _Kinetic;
    24.         }
    25.         set
    26.         {
    27.             _Kinetic = value;
    28.         }
    29.     }
    30.     private int _EM;
    31.     public int EM
    32.     {
    33.         get
    34.         {
    35.             return _Kinetic;
    36.         }
    37.         set
    38.         {
    39.             _Kinetic = value;
    40.         }
    41.     }
    42.  
    43.     public void SetDamage(int thermal, int kinetic, int em){
    44.         _Thermal = thermal;
    45.         _Kinetic = kinetic;
    46.         _EM = em;
    47.     }
    48.  
    49. }
    50.  
     
    larku likes this.