21
\$\begingroup\$

I am starting to implement player and enemy AI in a game, but I am confused about how to best implement this in a component-based game architecture.

Say I have a following player character that can be stationary, running and swinging a sword. A player can transit to the swing sword state from both the stationary and running state, but then the swing must be completed before the player can resume standing or running around. During the swing, the player cannot walk around.

As I see it, I have two implementation approaches:

  • Create a single AI-component containing all player logic (either decoupled from the actual component or embedded as a PlayerAIComponent). I can easily how to enforce the state restrictions without creating coupling between individual components making up the player entity. However, the AI-component cannot be broken up. If I have, for example, an enemy that can only stand and walk around or only walks around and occasionally swing a sword, I have to create new AI-components.
  • Break the behavior up in components, each identifying a specific state. I then get a StandComponent, WalkComponent and SwingComponent. To enforce the transition rules, I have to couple each component. SwingComponent must disable StandComponent and WalkComponent for the duration of the swing. When I have an enemy that only stands around, swinging a sword occasionally, I have to make sure SwingComponent only disables WalkComponent if it is present. Although this allows for better mix-and-matching components, it can lead to a maintainability nightmare as each time a dependency is added, the existing components must be updated to play nicely with the new requirements the dependency places on the character.

The ideal situation would be that a designer can build new enemies/players by dragging components into a container, without having to touch a single line of engine or script code. Although I am not sure script coding can be avoided, I want to keep it as simple as possible.

Summing it all up: Should I lob all AI logic into one component or break up each logic state into separate components to create entity variants more easily?

edit: I suspect there is some confusion about what I meant with the first and second situation. I have tried to explain it in the diagram below.

Component diagram

Note the relationship between the individual states and the entity. In the first situation, an AI component is pre-built before being put in the entity. A designer can only select from a distinct set of AIComponents made available by the programmer. The second situation has the different states on the same level as other components. A designer can now create an entity with unique AI without interference of a programmer.

The question is, are these the only two options for structuring AI in an component-based entity and, if so, what would give the maximum flexibility?

\$\endgroup\$
2
  • \$\begingroup\$ I think a good answer will depend on where you want to enforce the exclusivity of actions. If you want it to be in the objects themselves the design would be much different as compared to say, enforcing it through the drag and drop interface (This state already has a movement action so it can not have another, this state transition container already contains a time based end state, etc or whatever). \$\endgroup\$
    – James
    Feb 23, 2011 at 17:23
  • \$\begingroup\$ 2 is not a viable option. \$\endgroup\$
    – Coyote
    Apr 10, 2013 at 19:41

4 Answers 4

6
\$\begingroup\$

If you do intend to have more possible enemies or players that you can't imagine right now, then you should definitely break it up. What you're describing in your second point is basically the state pattern.

I think I agree with Gregory that you shouldn't have separate stand and walk state components. It's just a movement component with speed 0. On the other hand, if you have objects that can't move, you either have to split it up, or just put some kind of boolean restriction in the movement state that prevents having non zero velocity.

For the player I don't think it needs to be completely separate. It can still use all the other components, with the addition of an input component. This component drives the transitions between states, whereas in the enemy it's controlled by a default AI, or if you want, different AI subclasses that your enemy designers can choose from.

edit: actually, for your stationary enemies, rather than restricting the movement component, just give them a stationary AI component that never chooses to move them.

\$\endgroup\$
4
  • \$\begingroup\$ Doesn't a state pattern imply the first situation? This results in a single AIComponent implementing a state machine containing different state objects. What I meant with the second option was that WalkComponent and SwingComponent are of the same type as, say, RenderComponent and PhysicsComponent. \$\endgroup\$
    – ghost
    Feb 25, 2011 at 12:11
  • \$\begingroup\$ @ghostonline As far as the idea goes, sort of. In implementation, not really. AIComponent would be separate, as in the second diagram. It wouldn't contain the other components. The more important question for your second situation is, if the designer just chooses components without a programmer, how does the Entity know when to change state? Different states imply different state transitions - someone still needs to specify those. \$\endgroup\$
    – Tesserex
    Feb 25, 2011 at 13:56
  • \$\begingroup\$ Do you mean adding an AIComponent to the entity in diagram 2, which will control the Stand/Walk/Swing-Component? My idea was that the components send block or activation signals upon certain conditions. For example, SwingComponent would emit generic signals, for example "bound_feet" signal on starting and "release_feet" on finishing the swing. WalkComponent would disable and enable itself based on these signals. Because the 'state transitions' are encapsulated in the components themselves, the designer will not need a programmer wiring the components together. \$\endgroup\$
    – ghost
    Feb 25, 2011 at 15:09
  • \$\begingroup\$ @ghostonline That works fine for the things that have fixed rules like "can't walk while swinging" but what about transitions between stand and walk? If standing is in control, how will it know to try walking? The standing logic may want to choose either walk or swing, which is affected by the total absence of a walking ability - it should always choose to swing in that case. But I do think you're on the right track. \$\endgroup\$
    – Tesserex
    Feb 25, 2011 at 15:20
2
\$\begingroup\$

I'd at least keep Player AI (or what I'd call Player Controller) as its own component. With most games, the player is fundamentally different enough from the NPCs that you can't generalize from one to another except in basics like hit points.

For NPCs, I see StandComponent and WalkComponent as aspects of the same thing. Are you ever going to have a WalkComponent without a StandComponent? I doubt it. Likewise, a RunComponent would just be a WalkComponent with a higher speed and different animations. I can see the value in having an NPCMovementComponent and a separate NPCSwordFighterComponent, but even that feels like overengineering to me.

\$\endgroup\$
2
  • \$\begingroup\$ I wouldn't separate the NPC movement and player movement that much. The movement actions which drive the animations and physics could definitely be shared; it's what selects the actions or transitions that is different (player takes input while AI is...AI). I agree you'd have a PlayerController, but you'd also have an AIController, both of which could use Movement Components / Swing Components to get the actual animation/physics work done. \$\endgroup\$
    – homebrew
    Feb 23, 2011 at 16:09
  • \$\begingroup\$ True. I'm assuming that all moving objects have a PhysicsComponent or MovementComponent that handles their motion, and that the PlayerController and AIController would use that to handle the movement. Movement should definitely be a separate component, as there may be things that need to move that don't have AI or have the simplest possible AI (dumb physics objects like crates or junk). \$\endgroup\$ Feb 24, 2011 at 22:11
2
\$\begingroup\$

First I would make a State component and then I would create a state machine to handle the transitions. Make it generic enough that you can use this for your players and your AI. This will make sure the AI plays by the same rules and that you don't have to change your logic when you change how the player states work compared to the AI states.

Finite State Machine C++

The above has a concrete example of a state machine in c++ that can be used by players and AI alike.

\$\endgroup\$
1
\$\begingroup\$

What you want is a component handling the movement of characters (player and NPCs). The AI component or a player component will send commands to this movement component and it will check if the action can be initiated. This will encapsulate your movement constraints into one single component. Your AI code and player code do not have to know how swing sword is executed. The AI would have internal states e.g. Idle, Attacking, Fleeing.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ TYPO: "It will receive..." what from the AI component? \$\endgroup\$
    – Pup
    Feb 24, 2012 at 23:32

You must log in to answer this question.

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