Character Movement & Animation approaches
#1 Members - Reputation: 130
Posted 16 March 2011 - 11:50 AM
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.
#2 Members - Reputation: 1189
Posted 16 March 2011 - 12:24 PM
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
#3 Members - Reputation: 130
Posted 16 March 2011 - 12:30 PM
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?
#4 Members - Reputation: 1773
Posted 16 March 2011 - 12:39 PM
#5 Members - Reputation: 1189
Posted 16 March 2011 - 12:48 PM
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?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?
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.would you start that looped animation the moment you press a key...
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.and keep track of which key it was you last pressed...?
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.
Edited by Buckeye, 16 March 2011 - 12:58 PM.
#6 Members - Reputation: 122
Posted 16 March 2011 - 12:54 PM
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.
#7 Members - Reputation: 130
Posted 16 March 2011 - 12:55 PM
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?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?
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.would you start that looped animation the moment you press a key...
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.and keep track of which key it was you last pressed...?
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.
#8 Members - Reputation: 1189
Posted 16 March 2011 - 01:06 PM
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.my general practise is to keep functions short and easy to read
Sorry. That phrase should be taken out to the yard and shot... non-interacting actions..
Edited by Buckeye, 16 March 2011 - 01:07 PM.






