Best practice for selecting between multiple playable characters?

I want to create a mechanic which allows the player to switch between multiple on screen characters in real time, using something like a mouse click, hotkeys, or if on mobile, a finger tap.

Before I hop in and start writing scripts, I want to make sure I have the most efficient arrangment of scripts.

I suppose what I’m asking is, how would you organize this? A movement script on each character object and then a seperate “selection” script that enables/disables scripts on each object as you click from one to another?

I’m just spitballing, but would love some feedback from people who have used similar systems as to what unexpected barriers you ran into and what seemed to work best before I start writing the actual code.

Thanks in advance!

using the new ui, scroll rect and buttons?

An example of this kind of system implement; in the game “This War of Mine”, you click on each character to gain control of the character.

If you’re interested in feedback on how the player switches characters – hotkeys, mouse clicks, menu, etc. – the Game Design forum might be a good place for that discussion.

If you’re talking scripting, a common approach is to use a virtual controller. Brett Laming at Rockstar wrote a good article for AIGPW4 about their MARPO architecture, which uses a virtual controller.

A virtual controller sits in the middle of your stack of scripts. Below it, lower-level scripts handle things like character stats, inventory, physics, animation, etc. They read control input from the virtual controller. Above it, the virtual controller receives control input from a player input controller when the character is player-controlled, and from an AI input controller when the player is AI-controlled.

To switch from AI control to player control, you simply disable the AI input control script and enable the player input control script. The virtual controller isolates the lower-level scripts from this, so they continue to function without any need for modification.

So a player-controlled character might have these scripts:

[PlayerControl:enabled] [AIControl:disabled]
v
[VirtualController]
v
[CharacterStats] [Inventory]
[Physics components] [AnimationManager]
[Animator]

And when the player relinquishes control, it would look like this:

[PlayerControl:disabled] [AIControl:enabled]
v
[VirtualController]
v
[CharacterStats] [Inventory]
[Physics components] [AnimationManager]
[Animator]

When the player clicks on a character B (relinquishing control of character A), set:

B.PlayerControl.enabled=true
B.AIControl.enabled=false

and set:

A.PlayerControl.enabled=false
A.AIControl.enabled=true

To “click on character B”, maybe add a script with OnMouseEnter, OnMouseUp, and OnMouseExit.

OnMouseEnter: Show some prompt text, maybe by enabling a world space UI canvas.
OnMouseExit: Hide the prompt text.
OnMouseUp: Enable player control of the character.

You’ll probably also want some kind of manager that keeps track of the currently-controlled character so you can return that one to AI control before taking control of the new character.

@TonyLi apologies to necro this old thread, but in your architecture, how could you use a completely separate AIControl to control this specific entity? Do you just need to swap the local AIControl with an external one?

I’m not sure what you mean. The AIControl script could feed input into your virtual controller. If you want to play with an example, here’s an old project that was part of a presentation for a local game dev group: Github repo. In the virtual controller example scene, the agents are AI controlled by default. Each agent’s AI control component feeds input into the agent’s virtual controller. If you click on an agent, it disables the AI control component and enables a component that feeds input to the virtual controller from the player’s keyboard.

Thanks for the response, I’ll take a poke at the example you posted. Yeah so I have what you described above working, each agent has an “AI brain” and a PlayerInput script and I can easily switch between them and that’s working, but what I was thinking is it would be cool to have brains from other agent feed into the current agent’s virtual controller. For example, as a game mechanic, a boss possessing a trash mob temporarily.

Sure. That would work much the same way. Just get the boss to feed inputs into the trash mob’s virtual controller.

1 Like

Perfect, that’s what I thought thank you! One follow up question for you @TonyLi - say I have an AI that has an FSM for two states: wander and chase. The AI wanders about until it spots an enemy, then it chases and attacks until it either dies or the player dies.

Now that’s great and all, but don’t we need another FSM to control more granular states like idle, move, attack, recharge etc. In this case, I’d like the player to reuse the same lower level FSM, instead of having to write a player-only FSM when the player is controlling the AI. Is that possible with this setup? Thanks in advance.

The FSMs shouldn’t care about who is controlling the AI. It just reads signals from the virtual controller or from higher-level FSMs if you’re using layered FSMs, hierarchical FSMs, BTs, or whatever else at that level. So on one side of the virtual controller is either player-supplied input or an AI decision maker that decides what inputs to set. On the other side are the FSMs (or whatever) that act on the virtual controller inputs. The virtual controller serves as a hard separator between the two sides. (The AI decision maker that sets virtual controller inputs may read from the FSMs – or, better yet, a blackboard – but it will never directly set anything on the FSMs.)

Oh I see, you’re suggesting the FSMs sit under the virtual controller and just read from the virtual controller, instead of above. That’s where my confusion was, ty! This means the FSM can remain exactly the same regardless of who is controlling it.

1 Like