Advice on separating Input from Entities

Started by
20 comments, last by Zipster 14 years, 1 month ago
So I have a 2D shooter and the idea is that planes/vehicles/whatever should be separated from the means used to control them, i.e. player or AI. This would easily allow things such as switching between different vehicles and whatnot since the player's input handling etc. isn't embedded in the same object as a type of plane used by the player. I have more or less the idea drawn up. Entities will be controlled by EntityControllers, either of the Player or AI type. These controllers should somehow be able to command the same Entity object to do the appropriate things, regardless of being an AI or a player. The controllers will have a pointer to their controlled entity, or rather a list just in case more than 1 is ever needed. Ok in theory so far, right? How would be a good way to do that? I've had a few ideas flit through my head but I'm not sure if some are more work than required and less flexible than they should be, and I've been away from programming for so long that it'll take a while to start thinking right again. --- 1. Should I give all controllable entities a "library" of functions used to represent all of the actions they can take and then just have the controllers differ in a way such as: Player
if( W key down )
{
Entity->moveForward();
}
AI
if( Player ahead )
{
Entity->moveForward();
}
? This way you could probably even switch from very different vehicles with very different characteristics without much trouble if it was implemented right. I'm just worrying it may be somehow unwieldy in a way I haven't anticipated. 2. Some sort of messaging system where the player doing the action (pressing a key most likely) that should result in the entity doing something, causes some sort of message to be passed as an argument to an input handling function of the entity where appropriate action can be taken. This seems... perhaps less organized than the previous way and also seems like possibly just as much work for less neat looking code. Also, having moveLeft() and the like in their own standardized functions might have advantages. --- So that's what I have so far. Any problems with the first? I'm gravitating towards that right now.
Advertisement
Hi,

Option number 1. will result in tons of functions. Every time you add a new type of button pressed you'll need to add a function too and that may result in lots of recompilations of code.


Option number 2. will result one function in the best case which will handle any type of input (keyboard, mouse, joystick ...).

I'd go for this way. Also, I'd implement sort of key binding system so that the entities don't handle the actual keys that were pressed but messages. So the entities would receive messages such as MOVE_FORWARD, STRAFE_LEFT, MOUSE_MOVEMENT, FIRE1, FIRE2 etc etc. With the binding system you can use any key for any action.

Cheers!
i created classes for this, called them player, or actor, or what ever..

derived from this are aiplayers, and usercontrolled players. the players job is to a) think (if it's ai) or b) handle inputs and convert them to actual vehicle controls (if it's a player).

so what your vehicles expose are typical vehicle-controls (accelerate, break, turn left, turn right, shoot). and those players interact only trough those methods.


and then, i create for each wehicle a "Player Driver", which can be null, or some instance. and i go trough all vehicles, and if they have a driver in, get the drivers input feed to this vehicle.


something like this.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

Quote:Original post by kauna
Also, I'd implement sort of key binding system so that the entities don't handle the actual keys that were pressed but messages. So the entities would receive messages such as MOVE_FORWARD, STRAFE_LEFT, MOUSE_MOVEMENT, FIRE1, FIRE2 etc etc. With the binding system you can use any key for any action.


Ya, I was thinking something using an enum. That would work fine, right?

Something like:
if( W key pressed ){ Entity->input( MOVE_FORWARD );}

for a player.

As for all the functions, I was thinking it would involve a lot of functions but then at the same time it would probably be less than 10 and most would apply to all vehicles. You'd mostly need to move in 4 directions and shoot. There probably wouldn't be even 10 so it might not be too unwieldy. Maybe though 1 input function would be more streamlined and just as good though.

Quote:Original post by davepermen
so what your vehicles expose are typical vehicle-controls (accelerate, break, turn left, turn right, shoot). and those players interact only trough those methods.


So, more or less the same idea as 1 above? Have each vehicle present a set of move, shoot etc. functions that the player can interact with?
I also vote for a mapping from "physical input" to "action input". The top solution would be that an InputControllable exposes what actions are provided in a common manner, so that an Input::Device (be it the keyboard, mouse, joystick, gamepad, wheel, ...) that is selected by the player is able to map its physical input possibilities to actions. The set-up can be changed by game state, so that also different vehicles may be controlled with different set-ups.

If interested in such a solution, you may have a look at e.g. unity's manual, Input section or Input Manager section, or even at USB HID specification if you're hard enough ;)
#2 might result in only one function, but it will be a really ugly one, which has to change every time you change the capabilities of the entity. That won't be fun. It might be that the best you could make of it is to move all the actual actions into other methods, which puts you mostly back to #1. The only difference is that they can now be private (probably a good thing), and the translation of events to function calls takes place in the entity rather than the controller (might be bad).

If that didn't make any sense, ignore it. Anyway, the problems of abstracting input and abstracting control of entities are separate ones. If there is any direct translation from input events to entity actions, only the player-input controller will know about it.
Quote:Original post by theOcelot
#2 might result in only one function, but it will be a really ugly one, which has to change every time you change the capabilities of the entity. That won't be fun.


Yeah, that's what I was thinking. It's all mish-mashed together and nothing is in its own compartment like with #1 and both probably involve comparable amounts of work to implement.

Quote:Original post by theOcelotThe only difference is that they can now be private (probably a good thing), and the translation of events to function calls takes place in the entity rather than the controller (might be bad).


Hmmm... yeah, probably makes more sense. Keep 1 big input function but have it manage the other ones that actually implement the behaviour. That probably is a good idea.

There aren't any glaring problems with my concept in general though? I think I'll go with #1 but with the single function controlling the private functions. Should be alright for my current purposes at least.
Quote:Original post by Sean_Seanston
Hmmm... yeah, probably makes more sense. Keep 1 big input function but have it manage the other ones that actually implement the behaviour. That probably is a good idea.

That way, you can use a full-on object to pass commands, allowing you to pass an arbitrary amount of information to the entity. You might be able to inject a little extra flexibility by encoding part of the instructions in a string. Of course, if you find the strings getting too complicated, you probably want a scripting system.

This might not be as good as it sounds, though.
Quote:There aren't any glaring problems with my concept in general though? I think I'll go with #1 but with the single function controlling the private functions. Should be alright for my current purposes at least.

Just that you may be making things far more complicated and messy than they need to be. Bear in mind the Single Responsibility Principle. Unless you can put almost all the command parsing in an Entity base class, which is unlikely, you are likely to wind up with a major violation of this principle, with event parsing code spread out between entity classes and scattered inside them, mixing with the actual game logic that's supposed to be in there.

You may be able to make it work, but you'll actually have to plan more carefully what kind of information passes through that one function to prevent it from turning into a hideous tangled mess. And you'll almost certainly need more than an enum if you want the system to scale farther than a very few kinds of entities.

You can make #1 work without constantly adding member functions to the entity interface. It may feel crazy at first, but if you put a little thought into the functions and make full use of their parameters, things will eventually settle down. I speak from experience with this approach.

You'll have to experiment with it. Perhaps you'll wind up with a hybrid approach, but whatever you do, don't let command interpretation get tangled with actual execution of the commands (game logic).

And again, don't forget that input handling is a different problem.

Edit: fixed link.

[Edited by - theOcelot on February 18, 2010 2:31:14 PM]
I've always been partial to a setup like this:

1) Translation layer which converts raw/virtual codes (VK_H, VK_LBUTTON, VK_MOUSE_MOVE, etc.) combined with modifiers (up/down, ctrl/alt/shift) from the system into "game" codes. Some mappings are available to the user to be modified via configuration screens.

2) Handling layer which handles game commands on behalf of different systems or objects. Multiple handlers can be present (usually one for each system), in which case there's a simple process to determine who gets input, whether or not it's consumed, what order it gets processed in, etc. For some systems, like GUI, there's yet another translation/handling layer pair afterward that takes care of the GUI's specific needs. But for the most part, the handlers are the interface between game commands and whatever objects underneath that need input.
Ok, I just discovered the huge problem with the way I decided to try to do this.

Basically, I sent enums like MOVE_UP, MOVE_LEFT, MOVE_RIGHT, MOVE_DOWN to the entity's input function depending on what key was pressed. Obviously, (though not to me when I was thinking of it) the entity needs to know whether or not it's moving in each direction and not just if it happens to now be moving in a new direction. Otherwise you end up going left then pressing up and releasing left but you're now going up and still left.

This naive implementation (no doubt partly due to being away so long) at least made me think about the matter more clearly. Somehow I'm going to need the Controller to send the complete state (as it relates to controls at least) the Entity should have to the Entity's input function. So whether or not it's moving left, whether or not it's moving up etc.

Obviously an enum system is no good whatsoever for this. However, some form of bitmask involving enums might be workable but definitely seems limited and more than a little clumsy to me.

So one way or another I'm going to have to have the Controller tell the Entity what overall state it should have. I can imagine some sort of EntityStatus class that's filled with all the info and sent off to the Entity but is that really a good idea? Also, if I wanted one variable of the Entity to change based on another variable I would then need to access those variables if I was merely filling an object with the new values the Entity should have and that seems to involve the Controller object in things it really shouldn't be doing.

Is there really any practical, beneficial way of doing this without a relatively complex messaging system of some kind? Maybe I should avoid it altogther.

In fact, here's my situation: I'm making a 2D scrolling shooter much like SWIV or Xevious as a college project and obviously that means limited time and no real necessity to do things in an ideal way. I'm intending to make a similar but expanded game after finishing this one, hopefully having learned some things.
Given the situation, do you think I should just hardcode the player as controlling 1 specific vehicle and have enemy AI hardcoded into theirs?
I'd like to do things as elegantly as possible but maybe it's just not worth it in this case and there probably wouldn't be any real benefit to this particular project if I got this Controller system working perfectly, it would be more of a good thing to know in the future.

This topic is closed to new replies.

Advertisement