I'm sure there's a simple algorithm for this, but it's eluding me.
In a pure stat-based attack algorithm, how do you account for varying ATK/DEF values for units based on the units they are fighting against.
In other words, if I have the following:
Swordsmen: ATK=10, DEF=10, HP=80
Pikemen: ATK=5, DEF=10, HP=50
Cavalry: ATK=20, DEF=10, HP=150
There are a couple of different ways to run the attack logic but they're all basically just sum(ATK), sum(HP) for attackers and sum(DEF), sum(HP) for defenders.
But, if you want to create the rock-paper-scissors with
Swordsmen attacking Pikemen: ATK=20
Pikemen defending against Calary: DEF=40
Cavalry attacking Pikemen: ATK=5
Then, what does the attack algorithm look like? If 50 Swordsmen, 10 Pikemen, 100 Cavalry attack 20 Swordsmen, 20 Pikemen, 20 Cavalry, for example ... then what's the algorithm to compute the deaths? If anyone has a link to an articles discussing this I would be grateful. And is there a term for this? I'm not finding anything in searches but I maybe I'm not conversant in terms for these types of stat-based attack systems.
Stat-based attack system - should be simple, but need help
I would suggest to calculate the outcome of a combat only for two opponents at a time. One simple way to handle ATK/DEF is to work with the difference of this values. Either derive a probability from it or a direct damage.
I would prefer the probabilty version. You can look up the probabilty in a table and then determine the if the unit hit the opponent. If hit has been hit, reduce the hp.
Taking whole units into account, you need to determine which single unit is able to hit which opponent. If you have an abstract battlefield (ala might and magic) you can do something like this:
I would prefer the probabilty version. You can look up the probabilty in a table and then determine the if the unit hit the opponent. If hit has been hit, reduce the hp.
Taking whole units into account, you need to determine which single unit is able to hit which opponent. If you have an abstract battlefield (ala might and magic) you can do something like this:
executeAttack(attacker,defender){ // add offset to keep index positive, OFFSET should be MAX_DEF int look_up_index = attacker.ATK - defender.DEF + OFFSET; // look up table contains probabilty [0..1] float probability = look_up_table[look_up_index]; if(random()<probability ) { // hit defender.hp = defender.hp - attacker.dmg; }}executeBattle( unitA, unitB){ // execute attack unitA -> unitB for each attacker in unitA do { opponent = choooseRandomSingleUnit( unitB) executeAttack( attacker, opponent) } // execute attack unitB -> unitA for each attacker in unitB do { opponent = choooseRandomSingleUnit( unitA) executeAttack( attacker, opponent) } // check for dead units for each singleUnit in unitA do { if singleUnit.hp<=0 then { // singleUnit has been killed, remove from unit, play death aniamation .. } } // do the same check for unitB for each singleUnit in unitB do { if singleUnit.hp<=0 then { // singleUnit has been killed, remove from unit, play death aniamation .. } }}
Thanks. It's pretty clean and I like it.
I'm not used to randomness in stat-based browser game attack logic. I think it could be quite fun (although players will complain when it goes against them, I do think it will be "fun" overall).
Removing the probability randomness is easy in your code, but I'm still wondering how games handle this without randomness of chooseRandomSingleOpponent() . What's a logical/fair way to line up the units?
I'm not used to randomness in stat-based browser game attack logic. I think it could be quite fun (although players will complain when it goes against them, I do think it will be "fun" overall).
Removing the probability randomness is easy in your code, but I'm still wondering how games handle this without randomness of chooseRandomSingleOpponent() . What's a logical/fair way to line up the units?
You could a priority system, coupled with a proportional distribution of the rest of the damage.
So you have pikemen and cavalry get matched up first deal their damage, casualties are removed, and any remaining damage gets added to the damage pool, then on to the next priority. Once all priority damage has been done the rest gets add to the damage pool and the damage pool gets divided among the surviving troops based the proportion of the army they make up.
So you have pikemen and cavalry get matched up first deal their damage, casualties are removed, and any remaining damage gets added to the damage pool, then on to the next priority. Once all priority damage has been done the rest gets add to the damage pool and the damage pool gets divided among the surviving troops based the proportion of the army they make up.
Writing Blog: The Aspiring Writer
Novels:
Legacy - Black Prince Saga Book One - By Alexander Ballard (Free this week)
Quote:
Original post by NateDog
I'm sure there's a simple algorithm for this, but it's eluding me.
In a pure stat-based attack algorithm, how do you account for varying ATK/DEF values for units based on the units they are fighting against.
You can't.
The stats in question are linear values, ranging from low to high. You can compare them arithmetically.
The rock/paper/scissors system you want is a circular value, where Rock is 'higher' than Scissors, which is 'higher' than Paper, but then Paper is also 'higher' than Rock. You can assign numerical values to these three but not in a way that preserves the circularity you want.
So you need an additional function that takes the type of the attacker and defender and returns some relevant modifiers to ATK/DEF based on these types.
My personal favorite system works like this....
3 + 3 = 6;
4 + 2 = 6;
3 * 3 = 9;
4 * 2 = 8;
In the example above, you can have a situation where each player has the same number of attributes (in this case, 6. but their product returns different values. This can equate to:
Atk 3 * Spd 3 = 9 vs. Atk 4 * Spd 2 = 8;
In the above, the first player wins.
You can also add HP into this equation:
Atk 3 * Spd 3 * HP 3 > Atk 4 * Spd 2 * HP 3;
You can then add armor:
Atk 3 * Spd 3 * HP 3 * Armor 3 > Atk 4 * Spd 2 * HP 4 * Armor 2
So, visually speaking, the winner of the battle is the person who, with equal stats, has an equal value in each stat.
Where this gets tricky is, you can give weapons to an attacker that change the defenders stats. Such as Weapon1 - Reduces armor by 50%. Weapon2 - Reduces Spd by 50%. Weapon 3 - Reduces the defenders armor by a flat about of 2.
However you want to mix up the variables at this point is fair game. You could add more stats. Have armor that limits how high their Atk can be vs. your HP. All sorts of fun stuff.
3 + 3 = 6;
4 + 2 = 6;
3 * 3 = 9;
4 * 2 = 8;
In the example above, you can have a situation where each player has the same number of attributes (in this case, 6. but their product returns different values. This can equate to:
Atk 3 * Spd 3 = 9 vs. Atk 4 * Spd 2 = 8;
In the above, the first player wins.
You can also add HP into this equation:
Atk 3 * Spd 3 * HP 3 > Atk 4 * Spd 2 * HP 3;
You can then add armor:
Atk 3 * Spd 3 * HP 3 * Armor 3 > Atk 4 * Spd 2 * HP 4 * Armor 2
So, visually speaking, the winner of the battle is the person who, with equal stats, has an equal value in each stat.
Where this gets tricky is, you can give weapons to an attacker that change the defenders stats. Such as Weapon1 - Reduces armor by 50%. Weapon2 - Reduces Spd by 50%. Weapon 3 - Reduces the defenders armor by a flat about of 2.
However you want to mix up the variables at this point is fair game. You could add more stats. Have armor that limits how high their Atk can be vs. your HP. All sorts of fun stuff.
I came up with an equation for rock-paper-scissors:
sqrt(3.0)*sin(theta)/(2+cos(theta))
Make rock = 0, paper = 120 degrees (but in radians), scissors = 240 degrees (in radians). Then to determine the damage that a unit deals find the difference in the angle and plug it into the equation. You will get a 1 for maximum damage (rock trying to smash scissors) and a -1 for minimum (rock trying to smash paper, and a 0 for a fair fight (rock trying to smash rock) The beauty of this equation is that it works with any angle. So a fight between 10 degrees and 40 degrees will be identical to a fight between 170 degrees and 200 degrees.
Then take that raw number between 1 and -1 and scale it to work with your game. For example I multiplied it by 20 and then added it to some other numbers to come up with a percentage chance of hitting. For example rock vs paper gives you 1, multiply by 20, add to say 50%, and you have a 70% chance of hitting. Each hit dealt 1 damage.
sqrt(3.0)*sin(theta)/(2+cos(theta))
Make rock = 0, paper = 120 degrees (but in radians), scissors = 240 degrees (in radians). Then to determine the damage that a unit deals find the difference in the angle and plug it into the equation. You will get a 1 for maximum damage (rock trying to smash scissors) and a -1 for minimum (rock trying to smash paper, and a 0 for a fair fight (rock trying to smash rock) The beauty of this equation is that it works with any angle. So a fight between 10 degrees and 40 degrees will be identical to a fight between 170 degrees and 200 degrees.
Then take that raw number between 1 and -1 and scale it to work with your game. For example I multiplied it by 20 and then added it to some other numbers to come up with a percentage chance of hitting. For example rock vs paper gives you 1, multiply by 20, add to say 50%, and you have a 70% chance of hitting. Each hit dealt 1 damage.
Glak, I don't think you need to do that.
Just add simple if else statements to make your code clear for yourself and other designers.
if (offender == rock && defender == scissor)
bonusDamage = 50;
else if (offender == scissor && defender == paper)
bonusDamage = 50;
else if (offender == paper && defender == rock)
bonusDamage = 50;
else
bonusDamage = -50;
Just add simple if else statements to make your code clear for yourself and other designers.
if (offender == rock && defender == scissor)
bonusDamage = 50;
else if (offender == scissor && defender == paper)
bonusDamage = 50;
else if (offender == paper && defender == rock)
bonusDamage = 50;
else
bonusDamage = -50;
Quote:
Original post by tommy408
Glak, I don't think you need to do that.
Just add simple if else statements to make your code clear for yourself and other designers.
Glak's Equation is far more elegant than your example, and far more flexible. For instance with Glak's Equation I can define 4, 5, 100, or any number of positions on the circle and the the equation gives me results based on their relative position. I can change their position so that one is closer to another and further from the third so that the bonuses change magnitude. It is an incredibly flexible solution requiring no changes for even some crazy modifications.
Your example takes care of three equidistant positions on the circle and only that. It needs a near total rewrite to do what I just said and needs modifications and an addition just to make it 4 equidistant positions.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement