Character Movement & Animation approaches

Started by
6 comments, last by Buckeye 13 years, 1 month ago
Hi,

I wasn't quite sure which section to put this in, so I decided that this was the most appropriate place for it. Having taken a step back from coding for a moment, I looked at my code and found the EventReceiver code completely cluttered with information such as:

if ( key_pressed == 'W' )
then move_forward


An alternative approach would've been a switch statement, which honestly doesn't make much of a difference. Either of these two approaches leaves the code cluttered, and they are not very flexible (though the 'if' way a bit more than a switch) when it comes to custom controls. In addition to that, having this code in the EventReceiver class is, from my understanding, not a good idea to begin with. That made me wonder, and this is something I've had in the back of my mind for quite a while now - How is it usually done?

Say we've got an Event Receiver class, a Player Class, and a Game Manager class. The player class has functions for Animations, can alter the characters position, rotation and scale, and do all sorts of entity transformations. The Event Receiver class has a callback function which is invoked when a key (or mouse button) is pressed, and can then handle the key. The Game Manager class manages the Camera and the Game State.

I'd imagine movement and animation calls go in the same place, though I'm not quite sure what the better approach is. Thanks in advance.

As a side note, I don't know if it makes much of a difference for this general problem, but I'm talking about a 3D game.
Advertisement
Not sure how it fits in with your program architecture, but a common approach is to simply record keypresses and mouse messages, perhaps in an array of bool's, without taking immediate action.

In your run/update loop, check the array for key/mouse activity as appropriate and take action at that time. That approach separates the user interface from the update and rendering and allows for coincident key+mouseclick combinations.

E.g.,

bool keyDown[256];

// ... when keypress/keyup detected
keyDown[ key-code ] = true; // for key-down
OR
keyDown[ key-code ] = false; // for key-up

// elsewhere, e.g., during player->Update
if( keyDown[ W-code ] )
{
add-forward-motion;
// if you want a single movement per key-press then
keyDown[ W-code ] = false;
}
if( keyDown[ A-code ] ) add-side-motion; // or similar to above

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


Not sure how it fits in with your program architecture, but a common approach is to simply record keypresses and mouse messages, perhaps in an array of bool's, without taking immediate action.

In your run/update loop, check the array for key/mouse activity as appropriate and take action at that time. That approach separates the user interface from the update and rendering and allows for coincident key+mouseclick combinations.

E.g.,

bool keyDown[256];

// ... when keypress/keyup detected
keyDown[ key-code ] = true; // for key-down
OR
keyDown[ key-code ] = false; // for key-up

// elsewhere, e.g., during player->Update
if( keyDown[ W-code ] )
{
add-forward-motion;
// if you want a single movement per key-press then
keyDown[ W-code ] = false;
}
if( keyDown[ A-code ] ) add-side-motion; // or similar to above



Hi Buckeye,

Thanks for your reply. it's an interesting approach, and one that I'm not completely unfamiliar with. Am I right in saying that, if a player has a lot of different movement types (e.g. jump, attack, walk forward, backward etc etc), the player update function will become rather large?

Also, I'm not quite as confident with Animations yet. This is my first time of really trying to use them, and I know that for instance "Walk forward" would use a looped animation "Walk", though would you start that looped animation the moment you press a key and keep track of which key it was you last pressed, as well as keeping track of whether you've released the key? Or is there an easier, cleaner way of doing this?
It is further meaningful to decouple physical input (e.g. "key w pressed") from logical input (e.g. "forward motion"). It separates input controller (keyboard, joystick, mouse, whatever) from gameplay abilities. So it allows for binding input elements of controllers (that match the respective input mechanics) to the gameplay.
Am I right in saying that, if a player has a lot of different movement types (e.g. jump, attack, walk forward, backward etc etc), the player update function will become rather large?[/quote]
It could, but probably no more convoluted or time-consuming than having a separate function called for each keypress. "Large" is, of course, a relative term, and depends on how much you want to do in the update function. Is that a concern?

would you start that looped animation the moment you press a key...[/quote]
There might be other things to consider such as transitioning from the current animation to the new one, but, yes, I'd start it at that point.

and keep track of which key it was you last pressed...?[/quote]
No.. not sure what you have in mind. If you check the "forward" key each update, continue the animation until the forward key is no longer pressed. At that point, transition to/begin an "idle" animation. In general, you don't want to consider the "history" of the character, only the current and future state.

EDIT: Just to clarify a bit, rather than "a key has been pressed," I would use "a key is down" or "a key is up" to determine which action ("move forward", "idle") should be considered. E.g., in Windows, I would use the WM_KEYDOWN/WM_KEYUP messages rather than WM_CHAR messages.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I am by no means an expert but I have found that it is useful to simply keep track of what keys are being held down at what time, and make the event handling portion of my code do nothing but signify that these key states have changed. For example, something like this works for me (pseudocode, of course):

if ( /*a key has been pressed*/ )
{
switch ( /*the type of key*/ )
{
case UPKEY:
upkeyDown = true;
break;
case DOWNKEY:
downkeyDown = true;
break;
//etc.
}
}


And then, how I handle the fact that these keys are down depends entirely on what is happening within the game at the time. For example: if the player is currently jumping, holding the space key down isn't going to do much, so that spacekeyDown bool won't be dealt with at all. I found that breaking away the actual processing of the event itself from what to do with that processed information helps keep my code less cluttered (even if I do have what some might call a large series of unnecessary boolean variables). I guess, alternatively, you could have case SPACEKEY: call a function like player.jump() which simply does nothing if the player is already jumping, but just looking at your code and reading it logically might have it making less sense.

Am I right in saying that, if a player has a lot of different movement types (e.g. jump, attack, walk forward, backward etc etc), the player update function will become rather large?

It could, but probably no more convoluted or time-consuming than having a separate function called for each keypress. "Large" is, of course, a relative term, and depends on how much you want to do in the update function. Is that a concern?

would you start that looped animation the moment you press a key...[/quote]
There might be other things to consider such as transitioning from the current animation to the new one, but, yes, I'd start it at that point.

and keep track of which key it was you last pressed...?[/quote]
No.. not sure what you have in mind. If you check the "forward" key each update, continue the animation until the forward key is no longer pressed.
[/quote]


It's not much of a concern, though my general practise is to keep functions short and easy to read. But I'm also aware that larger functions would probably be more appropriate here. I'm also just trying to get a firm starting point, and further complexity is something I'll consider once I've got the basics working correctly.
And you're right on the last one, that was simply my thinking pattern taking a wrong turn. Thanks a lot for your help, it's always nice to get some clarification on how things are done in general.



Also heagarr:
Thanks for your input, it makes sense that decoupling is a good thing, and I hadn't thought of it in that way before.
my general practise is to keep functions short and easy to read[/quote]
That's certainly worthwhile. To keep things cleaner, you can incorporate into your update function calls to "PickDirection()" or "ChooseWeapon()," etc., each of which can check appropriate conditions. That further separates non-interacting actions from one another.

.. non-interacting actions..[/quote]
Sorry. That phrase should be taken out to the yard and shot.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement