3
\$\begingroup\$

In a lot of games the player can choose whether an entity will be controlled by the AI or by the player. For example in the game Little Fighter 2, the player can choose how many of a maximum of 8 characters would be AI-controlled and how many of them would be human-controlled.

I was thinking how I can achieve this in my game. Currently in my game whatever controls the characters is hardcoded into them. I even have an AIAgent abstract superclass that all AI characters derive from, and a Player class that represents the player-controlled entity.

I realized that in order to be able to choose dynamically if an entity will be controlled by the player or by the AI, I need to decouple the entity itself from "it's brain", i.e. whatever controls it.

By "the entity itself" I mean the attributes and actions of the entity: it's mass, it's image, the way it implements shooting a missile, etc. By "the brain" I mean the system that decides when, and possibly how, to act.

As I said, currently "the brain" of my entities is hardcoded in their update() function. My Player class responds to player input in it's update() method, and my AIAgent subclasses usually delegate to a StateMachine of some sort in this method.

So I was thinking: how can I decouple the entities from their "brains", in order to be able to choose dynamically whether a Monster is player or AI controlled - and without a lot of ugly code duplication.

The solution that comes to mind is creating an abstract Controller class, with subclasses that can be plugged into the entities. Then the entities simply delegate to their controllers in the 'update()` function, and the controller controls the entity through it's interface.

To demonstrate:

abstract class Entity{
    // .. stuff omitted
    Controller brains;

    public void update(){
         brains.update(this);
         // .. non-behavioral physics stuff omitted
    }

    public void setController(Controller brains){
        this.brains = brains;
    }

    // methods that will be called by the controller in order to control the entity:
    public void attack(){
        ....
    }
    public void moveLeft(){
        ....
    }
    // ....
}

A PlayerController can read user input and control the entity accordingly, while an AIController would implement a state machine to control the entity. The controllers would use the entity's public interface to control it.

The only doubt I have about this approach is that it forces the entities to offer a lot of public methods to control them, such as moveLeft() and shootMissile().

Conceptually, it doesn't "feel right" that the entity would expose methods like these to the outside world, when 'conceptually' it should be it's own job to control itself. Just like it isn't possible to control a human's legs or heart from the outside. Feels like it breaks encapsulation.

So my question is: what do you think of this approach? Can you recommend a better one? How is this often done in games?

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

I tend to subscribe to the theory that an entity is somewhat abstract and in the general sense doesn't really have much of any logic. If anything, an entity often exists as a wrapper around a complex set of systems that deliver specialized behavior based on outside factors.

For example, two entities are constructed in the same way but one perhaps has an AIController where-as the other has a PlayerController. The two different controller components dictate which systems the entity is controlled by.

In the case of the player, input from the keyboard/mouse get translated into actions and the player system reacts by setting appropriate MovementComponent attributes on the entity that has a PlayerController.

In the case of the AI, the various AI systems dispatch actions and the AI system reacts by setting appropriate MovementComponent attributes on the entity in which the AI logic is running for.

At this point, a seperate system is responsible for interpretating the information on the MovementComponent and causing the entity to actually move in the world simulation.

This very easily lends itself to situations where a player controlled entity may loose control of their entity due to some fear or mind control affect and now be controlled by some AI temporarily or allows a player to temporarily mind control an AI based entity for their own bidding all by simply swapping the controller being used on a given entity.

Want to add networking? Now you might introduce a NetworkController which takes input from network packets from the game server, sets appropriate entity state, and the movement system begins to navigate those entities in the world simulation.

Sometimes adding a single layer of indirection (such as the movement system above) can easily help decouple code and all the while provide a very flexible way to introduce additional behaviors or alter behaviors in the future without severe system impact.

\$\endgroup\$
3
  • \$\begingroup\$ Since my game is simple and I'm a beginner, I'm not going to implement the MovementComponent part in this game (not really sure what it does). But generally, do you agree with my solution? I.e. have the entity delegate to the Controller, and the Controller control the entity through they entity's interface? \$\endgroup\$
    – Aviv Cohn
    Commented Jul 16, 2014 at 12:19
  • \$\begingroup\$ I would recommend using 2 constructors. So at selection time for number of players, you choose 2 humans and 6 ai's. You'd see something in a loop like: New Player(player[i], human); New Player(player[i], human); New Player(player[i], robot); etc.... \$\endgroup\$ Commented Jul 16, 2014 at 12:38
  • \$\begingroup\$ @Prog Creating a controller who is responsible for some movement interaction is fine, but I would not have any movement API on the entity class itself. Remember, you will likely have some entities that are stationary but can be used such as doors, chests, perhaps some form of mine/herb nodes, etc. The benefit of a component entity system is that specialized functionality is abstracted out to either a component or a system that operates on components and facilitates that functionality. The idea behind a movement component was to give you an abstracted movement API w/varying controller types. \$\endgroup\$
    – Naros
    Commented Jul 20, 2014 at 7:46
1
\$\begingroup\$

The way I like to think about this problem is as abstracting the input. In order words, have the AI "press buttons" (not literally). It's pretty much the same as what you're suggesting, with the Entity being a fully functional puppet that can either be controlled by the player (using normal input) or by the AI (using your state machine).

Modern game engines use what's called a Component or Entity architecture where the entities are built out of smaller pieces (components), instead of reusing through inheritance. In this case, the controller would be one of the components, and you'd have components to render the visuals, update the physics, etc. The components communicate directly, and the entity becomes not more than a container.

This might alleviate your concerns about exposing a public interface, but if you don't want to re-architect your game you don't have to. Think about it in terms of code systems, not "real" objects. Your entity is an encapsulated object that implements functionality to draw itself and internal logic to update its position and such. And it offers an interface for other systems to interact with it, effectively to control it. I see no real problem with this.

\$\endgroup\$

You must log in to answer this question.

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