2
\$\begingroup\$

User A can have many entities

A Entity is a object that has properties such as health, attack, defence, agility, stamina, etcetera.

When User A want to attack User B with x entities I am looking for the algorithm/equation to calculate the fight. I have brought some couple of ideas but they all have some pros and cons and I am not sure which one I would use or If I should use one of them at all?

Model A - The while loop Basically I would get all the entities that is suppose to fight in this battle, I would assign each of them (objects) in to an array (the User A array and the User B array). Now I would simply loop through until one of the array is empty. Inside the loop I would let one of the User attack first, calculate the result (If the Entity has 0 health, remove it) and then let the next User attack back, calculate the result (If the Entity has 0 health, remove it) And then continue.

The Pros with Model A would be that every entity would be battling and instead of just do a calculation on all around there would be a justice fight.

The Cons To loop through like 10 entities would be fine but what about 1000-2000 entities? And how about the different strength of each entity I mean how could I decide which entity should battle against what entity? This could be just an sorted array (weakest > to strongest) But then I couldn't have like different types of entities is better against a different type of entity, meaning like a Gunner wouldn't mean anything If it met a Swordsman even though a Gunner would most likely win such in a real fight.

Model B The idea of Model B is quite simple basically calculate all the attributes (properties) together and then If User A army has greater stats than User B army, User A army would win the fight. The Pros with this is it easy on the performance. The Cons are "Which entities would survive?" And it would basically be, the one with greatest army would win. You wouldn't even have a "chance" to win.

Model B B Then I started to think what If I take the concept of Model B calculate the stat and then I have a battle between just those two single entities. This way User B actually would have a chance ( a small one but the possibility to win) even though the User A has greater army (better stats). The Cons are yet again, How would I know which entities that would survive on the winning team?

The answer I am looking for to this question is what Model should I use? And how would I solve the cons in that particular Model. Or should I use some completely different model (idea) ? (If possible please provide some php pseudo code)

\$\endgroup\$
2
  • \$\begingroup\$ Usually an army is divided in smaller groups, so you could use a Model B applied to them, instead of the whole army. It would be different from Model A (less comparisons) and smoother than model B: the greater Army1 could still lose some groups from the smaller Army2 if Army2 has better units. Also, you could add a random factor for each group (terrain advantage, timing, etc). Defining wich units would surivive could be based on 'how much they won' over the enemy's result. PS: why the PHP tag for a game design question? \$\endgroup\$
    – Darkwings
    May 13, 2012 at 12:49
  • \$\begingroup\$ Well how would I base it anyway? What If the User sent 5 soldiers, there are no point to divide in to smaller groups. I use the tag php because it would simply be written in php later, and if people would like to give some pseudo code they know its in php! thanks for your reply. \$\endgroup\$
    – josmith
    May 13, 2012 at 13:03

3 Answers 3

5
\$\begingroup\$

I've recently used both models A and B in two different games. Neptune's Pride and Jupiter Folly.

In both games, when two armies meet, they fight until one army remains.

In Neptune's Pride, players take turns inflicting damage on one another until one of the armies is dead. In Jupiter's Folly, the strength of the armies is simply compared and some die rolls are added to the result, the stronger army wins. The winner suffers damage equal to the loser strength.

For your games you must ask yourself, how well the player will be able to guess the outcome of the battle. Will they be able to calculate their odds in their head before the battle? Will they be able to understand the math that is going on under the hood.

Instead of thinking about the problem in terms of how you code it, you should think about what the player will see and think.

Model B will be much easier for the player to understand.

\$\endgroup\$
3
  • \$\begingroup\$ Assuming that no player at all will be smart enough or willing to spend some time improving a strategy is just as bad as flawed game mechanics. Even more if the game involves RTS elements, and this seems the case. If the math is 'hard' (and this isn't even an objective statement) simply give some directions on the odds of winning, comparison between units etc. Almost every decent game does that. \$\endgroup\$
    – Darkwings
    May 18, 2012 at 14:06
  • \$\begingroup\$ Yeah but Darkwings, if you are going to help the player out by giving them the odds, why not just use those odds to calculate the outcome. Why do the work of having a complex simulation of the battle, then the work of calculating what the outcome might be to tell the player. If you want to be able to show the players a blow by blow battle, then that's a different story. You need to have those events. \$\endgroup\$
    – Jay Kyburz
    May 18, 2012 at 22:21
  • \$\begingroup\$ I was just saying that the most simple and easy to understand method is not always the best one to achieve something that is fun/good/realistic. Assuming that no one will look under the hood to see the hard rules is like assuming no one will be that interested in your game. Else you could argue that 'who presses X faster wins' would be the best policy. No math involved. Since it's a strategy game, the assumption should be the opposite: a dedicated player will want to elaborate as much as possible to win. \$\endgroup\$
    – Darkwings
    May 19, 2012 at 20:21
2
\$\begingroup\$

Here is a basic version of a battle model that combines some features of A and B with WWII troop organization, while at the same time avoiding a problem you mentioned, namely that "a Gunner wouldn't mean anything if it met a Swordsman even though a Gunner would most likely win in a real fight."

Define the interface of battle entities in ITroop. Implement ITroop with GunnerTroop, SwordmenTroop, etc., with different behaviors for finding targets, applying damage, reacting to battle events, etc.

Now implement the Composite design pattern in order to branch together several leaf like entities to form Troops of different sizes. Define Group (up to 10 single entities), Platoon (up to 4 Groups), Company (up to four Platoons), Battalion (up to 5 Companies), and Regiment (up to 8 Battalions). In each of these classes, define a couple of additional constants and methods:

const damageMultiplier
const damageFullRanks
isFull()

as well as any new behavior that troops of that type and troop size have:

reactToOnBeingTargeted()
reactToBeginSecondBattleRound()

The battle then follows these steps:

  • Before the fight starts, the entities of both armies are grouped by entity types. 10 entities of the same type and army are put into Groups (of the given entity type), until no more Groups can be filled that way. Groups of the same type are grouped together to form Companies, Companies of the same type to form Battalions, etc. For example, if you have 180 gunners, this process would result in one Company with 1 full Platoon and another half-full Platoon. Register the Company in the player's Army data structure as the biggest Troop of gunners available to that player. Also register any event handlers that Groups, Platoons, and Companies of gunners might have.
  • Cycle through the combat rounds and tell different entity types to act.
  • When it's player A's gunner's turn to shoot, look for the biggest Troop of gunners available to player A. Let's say that it is the Company described above. The Company now looks for a target in the other player's army; let's say that it looks for cavalry troops. Again, the biggest troop of that type is returned as the target.
  • Having found a suitable target, the Company determines how much damage it does. This is a two-step process:
    • Company calls its own isFull() method to see if the ranks of the Company are fully filled. If this is the case, return the constant damageFullRanks. This is a precalculated number that prevents large troops from causing a myriad of requests down the composite tree.
    • If Company is not fully filled, cycle through its members and ask for their damage. In this case, the first request goes to the full Platoon of gunners, which returns its damageFullRanks constant. The second request goes to the half-full Platoon, which in turns asks its members for their damage values. When all damage values are collected, Company applies the constant damageMultiplier to the sum of the damage of all its members.
  • Apply the damage at the target. If the troop size of the target drops because of the attack, register the new and smaller sized Troop object as the new biggest troop of that kind for that player.

This model has a couple of advantages:

  • Each unit fights. If there are other units of this type, it types within a Troop, but if not, it fights alone.
  • You don't need to handle the battle behavior of 2,000 individual objects. You might HAVE that many objects, but the number of attacks to be calculated is much lower, because the composite pattern groups many entities into bigger units.
  • damageMultipliers should be > 1, thus providing an incentive to build bigger armies. This represents the advantage that bigger armies have over smaller ones without aggregating all the units into a single number which is then compared to a single number of the opponent. The damageMultipliers > 1 should, of course, be thematically motivated somehow, for example by saying that a Company of Swordmen carries a banner that boosts morale, and that a Battalion has a commander who makes them more efficient.
  • Having different ITroop implementations for different unit types allows for game mechanics that require careful army composition (instead of just adding more junk to the pile in order to make the numbers bigger). For example, information about an enemy's army composition could be exploited by 'countering' his composition.
  • Another way to add a size bonus AND strategic depth to army composition is to define custom event listeners for different troop types and sizes. For example, each Company of gunners might have a canon that can do something fancy against another entity type once per battle to counter that entity type, or Groups of fairies might fight alongside Groups of Paladines, proving some kind of protection in case of certain onBeingAttacked events.
  • Having an OO design approach generally adds flexibility for whatever you might want to add to your game later on.
\$\endgroup\$
1
\$\begingroup\$

If a user is sending just 5 soldiers than of course there's no point in dividing in even smaller groups, let alone using different simulation models. But you also considered a case where there are 2000 entities in play.

If you want something even barely realistic, 2000 soldiers won't be attacking as a single mass of people (or stats). They would be divided in groups, possibly with different game stats.

Instead of just doing 500 VS 200 (where the 500 would win) or 500+rnd VS 200+rnd (where the 200 could have a slight probability of winning, depending on the rnd factor) you could define groups of (pick a number) 25 units and compare groupA1 VS groupB1 etc. And, to improve the randomness, making it groupA1+rnd VS groupB1+rnd.

Defining a formula to find out if a soldier is taken out of combat shouldn't be that hard at that point.

I.E: Let's say there's a 25 vs 20 situation. The 25 should have better probability of winning (and surviving). Random1 = random[0,5] and Random2 = [0,5]

So if it's Value1+Random1 VS Value2+Random2, the result could be 25 VS 25. Then you could say that taken_out1 = (group2/group1)+X taken_out2 = (group1/group2)+X

Where X is another random value (probably related to the other variables)

Of course all the numbers are just made up in a couple of minutes, but they should provide a decent enough example.

That way each group has a probability of winning, and a 2000 soldiers army would have 80 groups (that is, a maximum of 80 check to do).

That would make the battle both less predictable and less heavy to simulate, and also give you a way to modify your simulation later (adding specific unit types, or terrain variables, etc).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .