3
\$\begingroup\$

I am currently trying to make an AI for my 2D Fighting Game like Brawlhalla or Super Smash Bros. The problem is that I don't know how to go around doing it, like what algorithm should I use. The methods I have found like mini-max would take to long to make decisions and finite state machine seems a bit to simple to make it even slightly difficult. I do have time on my side if that helps.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ We already have How to implement AI for fighting game? The language is different, but the answer is general enough that it could be used in Unity. If that doesn't fit your situation, please edit to help us better understand your problem. \$\endgroup\$
    – Pikalek
    Nov 9, 2022 at 21:53
  • 2
    \$\begingroup\$ @Pikalek I think the AI for a Smash Bros style fighter where victory is obtained by knocking your opponent off the stage might have important differences from AI used in fighting games where you win by emptying your opponent's health bar. The stages are often larger and more complicated, include items or hazards, and the positioning relative to platform bounds has to be factored into the strategy. I think it would be worth editing the question to focus on this aspect of the problem. \$\endgroup\$
    – DMGregory
    Nov 9, 2022 at 22:03

2 Answers 2

4
+100
\$\begingroup\$

The specifics.

On top of the typical fighting-brawling AI (as given in other answers and comments), your AI needs to predict and achieve such a world state, in which the opponent crosses a border of a no-return zone (or other kind of environment hazard).

enter image description here

This task may be subdivided into the following components:

  • Predicting the long-term consequences of a "punch". After all, sending an enemy flying to death involves some flying, which is not instant (unlike the punch itself).
  • Finding a position for a good punch, while avoiding being punched on the way. This is rather simple, once you can predict when someone can knock a character out from given position.

Predicting future is really hard, and I see this to be the main challenge here — and thus the focus of my answer. In fact, you may consider constraining the game mechanics to make it more predictable.

Heuristics.

If the game employs somewhat simple mechanics, then a manually coded approximation will do. Sprinkle with some extra rules regarding the character's state and abilities and then tweak the numbers until your play-testers report satisfaction.

For example, choose few random positions around the enemy, and see if tracing a line in opposite direction would cross a hazard or will end up above a chasm. If answer is positive, then see if you could navigate there. Because the enemy also moves, you'll need to update the goal regularly.

As for defense, check if the enemy can knock the character out the same way. If so, try to get into safety, either by retreating to the previously known safe place, or by locating a new one with a series of "punch-probes" (pick few random points nearby and see if they are safe). Alternatively, you could also try blocking, dodging, and employing whatever else the game offers.

(By the way, the method of probing a set of (predefined or random) points is a rather popular approach in designing game AI for complex environmental interactions. In Unreal Engine terms (which has one of the bestest Behavior Tree editors around), this is called Environmental Query, you may want to look further into it.)

Simulation.

For more complex games (especially when talking about environment and complex characters' abilities), a proper simulation would be required. Helpfully enough, fighter-type games usually are pretty lightweight in terms of game state, which makes probing multiple simulations rather affordable.

You'll need at least two instances of your world: the "real" one, and the simulated. Every so often, the "real" world will be cloned into the simulated one to run the simulation (usually few times in a row) and see how it goes.

But this raises a question: how will the actors in the simulation predict the future of the simulation? To break the infinite recursion, the characters should not to try predicting the future, but instead try a random sequence of actions, and choose the best one. (If you are looking to learn more, the method described is known as Evolutionary Algorithm, and Genetic Algorithm is its popular variant.)

  • The simulation runs few times (each time initializing from the current "real" world's state).
  • Before the runs, each actor chooses a new plan: a random sequence of actions. (E.g. pressing left, then waiting half a second, then pressing jump. This can be further improved with heuristics.)
  • During each run, each actor follows their plan unconditionally. Each plan is scored based on the outcome of run (e.g. ending up near a chasm will result in a penalty, while punching an enemy would result in a reward).
  • In the beginning of the every next run, actors with a high(er) score will keep their plan intact, while the actors with low(er)score will re-roll a new plan.

Running this for few cycles should result in a somewhat optimal plan for each character. All what remains for each actor is to stick to the chosen plan in the "real" world.

(Also, you probably want to simulate the players' characters too, because them standing still could make the AI extremely aggressive — because the AI will incorrectly predict that the player is completely inert and defenseless.)

The simulation approach can be really good, because it requires virtually no tweaking and re-testing every time you update the game.

Reinforced learning.

This is rather academic topic, thus I am not going into too much details, but the basic idea is equipping your AI with bunch of sensors (e.g. measuring distance under the feet, distance to the enemy, reading health, stun status, etc) and a miniature "brain" (in a form of a matrix multiplication pipeline) that will get inputs from the sensors and transform them into action preference (e.g. pressing left or right). The brain itself is produced in a "learning" process, where the AI is allowed to run free, interact with the world semi-randomly, and be judged, which will modify the brain to improve the performance.

\$\endgroup\$
0
\$\begingroup\$

I don't like 2d fighting games. I didn't play one in ages and I never made one. So I am probably not the most qualified person to answer. But if someone would put a gun to my head and tell me to, then I would probably start the AI based on a behavior tree.

Behavior trees are a common and well-documented pattern in game AI programming. Others have explained it much better than I could. So the rest of this answer will assume that the reader is familiar with the principles and the terminology of behavior trees.


Have you read up on behavior trees and are familiar with the theory? Did pick one of the many Unity addons for behavior trees or implement a basic code-only BT framework yourself (been there, done that, took about 2 hours)? Good, then let's see how we can apply the theory to a fighting game.


As a first "Hello World" of fighting game AI, I would start with a simple repeating sequence, like two steps forward, two steps back, jump up, punch. Now this is of course not really a challenge, but it at least gets us somewhere and proves that the system works.

The next step would be to build a behavior tree which represents the regular logic of a player in a fighting game. What is that logic?

  1. Is the opponent performing an attack? Then I should probably do something so I don't get hit.
  2. If not, is the opponent in a position where I can hit them with an attack? Then I should probably perform that attack.
  3. If not, then I should probably get closer to the enemy so I can hit them.

In behavior tree terms, this sounds like a selector:

               ┌────────────┐
               │  Repeater  │
               └──────┬─────┘
                      │
 ┌────────────────────▼─────────────────────┐
 │  Selector                                │
 │  "Main"                                  │
 └────┬───────────────┬──────────────┬──────┘
      │               │              │
 ┌────▼────┐    ┌─────▼────┐   ┌─────▼──────┐
 │"Defend" │    │ "Attack" │   │ "Approach" │
 └─────────┘    └──────────┘   └────────────┘

The "Defend" branch would first check if the opponent is actually performing an attack right now. If it doesn't, the branch fails so we can proceed with the attack branch. If not, we would go through all the defensive options the character has available (ducking, jumping, blocking), check if they are currently possible to perform, check if they would even help in this situation, and then succeed by performing that defensive maneuver:

┌───────────────────────────────────────────────────────────────────────────────────────┐
│Sequence                                                                               │
│"Defend"                                                                               │
└─────┬────────────────────────────────────────────────────┬────────────────────────────┘
      │                                                    │
┌─────▼─────────────┐ ┌────────────────────────────────────▼────────────────────────────┐
│Enemy is attacking?│ │ Selector                                                        │
│                   │ │"Pick maneuver"                                                  │
└───────────────────┘ └───────────────┬──────────────────────────────────┬─────────┬────┘
                                      │                                  │         │
                      ┌───────────────▼───────────────────────────┐ ┌────▼───┐ ┌───▼────┐
                      │Sequence                                   │ │Sequence│ │Sequence│
                      │"Duck"                                     │ │"Jump"  │ │"Block" │
                      └────┬───────────────────┬───────────────┬──┘ └───┬────┘ └───┬────┘
                           │                   │               │        │          │
                      ┌────▼──────┐  ┌─────────▼─────────┐ ┌───▼──┐     ▼          ▼
                      │Can I duck?│  │Would ducking help?│ │Duck! │    ...        ...
                      └───────────┘  └───────────────────┘ └──────┘  

The "Attack" branch would look basically the same. A selector going through all the attacks the AI has available, each one represented by a sequence "Am I able to use this attack?" -> "Is the opponent in range for this attack?" -> "Use this attack".

When no attack is performable right now, then we still have the "Approach" node. For starters, we could just walk forward. But this node could later be expanded by a more varied palette of movements, like jumping towards the enemy, or occasionally moving backwards just to throw the enemy off.

There might be one problem, though: Even though the AI will probably not yet be very strong in the strategy department, it is still blessed with superhuman reflexes. It will block everything when it has the choice and spam any attack that has a chance to connect. That might not be too fun to play against. To make the AI a bit easier to play against and also make it a bit less predictable, you could add a random chance for each "Am I able to do this?" leaf to just fail for no reason. So sometimes the AI won't block or attack even though it theoretically could. Just like a human player who doesn't always have perfect reaction either. Adjusting that random fail chance up and down would then also be a great way to adjust the difficulty.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I think this is solid guidance for a traditional fighting game where the goal is just to land hits on the opponent to reduce their health bar to zero. In the context of a Brawlhalla/Smash Bros style fighter where victory requires knocking your opponent off the stage, I wonder if some more complicated spatial planning would also be needed. Any thoughts on how one would incorporate those considerations into this AI model? \$\endgroup\$
    – DMGregory
    Nov 15, 2022 at 18:23

You must log in to answer this question.

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