Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Character Movement & Animation approaches


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 sjaakiejj   Members   -  Reputation: 130

Like
0Likes
Like

Posted 16 March 2011 - 11:50 AM

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.

Sponsor:

#2 Buckeye   Crossbones+   -  Reputation: 6373

Like
0Likes
Like

Posted 16 March 2011 - 12:24 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

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


#3 sjaakiejj   Members   -  Reputation: 130

Like
0Likes
Like

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 haegarr   Crossbones+   -  Reputation: 4601

Like
1Likes
Like

Posted 16 March 2011 - 12:39 PM

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.

#5 Buckeye   Crossbones+   -  Reputation: 6373

Like
0Likes
Like

Posted 16 March 2011 - 12:48 PM

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...

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...?

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.

Edited by Buckeye, 16 March 2011 - 12:58 PM.

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


#6 Ruzhyo2000   Members   -  Reputation: 122

Like
0Likes
Like

Posted 16 March 2011 - 12:54 PM

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.

#7 sjaakiejj   Members   -  Reputation: 130

Like
0Likes
Like

Posted 16 March 2011 - 12:55 PM

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...

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...?

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.



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 Buckeye   Crossbones+   -  Reputation: 6373

Like
0Likes
Like

Posted 16 March 2011 - 01:06 PM

my general practise is to keep functions short and easy to read

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..

Sorry. That phrase should be taken out to the yard and shot.

Edited by Buckeye, 16 March 2011 - 01:07 PM.

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





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS