Holding Spacebar To Jump

Sage
Posts: 1,066
Joined: 2004.07
Post: #1
I'm thinking of entering a small skateboarding game in for uDevGames. I've been able to easily use what I have of my 2D sidescrolling engine and use it well with some tweaking. I need to find a way to have the spacebar be the jump button. But instead of pushing spacebar to jump, I want the player to hold the spacebar, have it increase a variable to represent the height of the jump, and when the player releases the spacebar the character jumps. I of course want a limit on this height. I've tried a few things and I can only get one jump out of the character before the code stops working. It probably has to do with some of my bool values. Below is the code I think you'll find necessary to help me (if you feel like doing so):

(Init.cpp)
Code:
bool upPressed = false , downPressed = false , leftPressed = false , rightPressed = false ;
bool spacePressed = false, iPressed = false;

Code:
/*
HandleKeyPressEvent
handles the key presses of the keyboard
*/
void HandleKeyPressEvent(SDL_keysym * keysym)
{
    switch(keysym -> sym) // which key have we got
    {
        case SDLK_ESCAPE:
            Quit(0);
            
        case SDLK_UP :
            upPressed = true;
            break;
            
        case SDLK_DOWN :
            downPressed = true;
            break;
            
        case SDLK_RIGHT :
            rightPressed = true;
            break;
            
        case SDLK_LEFT :
            leftPressed = true;
            break;
            
        case SDLK_SPACE :
            spacePressed = true;
            break;
            
        case SDLK_i :
            iPressed = !iPressed;
            break;
            
        default: // any other key
            break; // nothing to do
    }
}

/*
HandleKeyReleaseEvent
handles the key releases of the keyboard
*/
void HandleKeyReleaseEvent(SDL_keysym * keysym)
{
    switch(keysym -> sym) // which key have we got
    {
        case SDLK_UP :
            upPressed = false;  
            break;
            
        case SDLK_DOWN :
            downPressed = false;
            break;
            
        case SDLK_RIGHT :
            rightPressed = false;
            break;
            
        case SDLK_LEFT :
            leftPressed = false;
            break;
            
        case SDLK_SPACE :
            spacePressed = false;
            break;
            
        default: // any other key
            break; // nothing to do
    }
}


(Character.h)
Code:
#ifndef __CHARACTER__
#define __CHARACTER__

#include "ActiveObject.h"
#include "Obstacle.h"

/*
Sets out functions and variables responsible for maintaining a user controlled character
*/

enum { GOING_UP, COMING_DOWN, AT_REST }; //constants to set the jump direction

class CCharacter : public CActiveObject
{
public:
    //our constructor takes the coordinates, dimensions, mass, and speed along the x and y axis
    CCharacter(float x, float y, float z, float w, float h, float d, float m);
    
    void SetSpeedX(float m) { mSpeedX = m; } //sets the speed along the x axis
    void SetSpeedY(float m) { mSpeedY = m; } //sets the speed along the y axis
    void SetSpeedZ(float m) { mSpeedZ = m; } //sets the speed along the z axis
    
    float GetSpeedX() { return mSpeedX; } //returns the current speed of the object
    float GetSpeedY() { return mSpeedY; } //returns the current speed of the object
    float GetSpeedZ() { return mSpeedZ; } //returns the current speed of the object
    
    void AddSpeedX(float m) { mSpeedX += m; } //adds to the speed along the x axis
    void AddSpeedY(float m) { mSpeedY += m; } //adds to the speed along the y axis
    void AddSpeedZ(float m) { mSpeedZ += m; } //adds to the speed along the z axis
    
    void CheckCollision(CObstacle *obstacle); //checks collision with another active object
    
    void Jump(float s); //makes the character jump
    
    void Update(float s); //updates the character
    
    void CheckForMovement(float s); //checks for keyboard input
    void CheckGravity(float s); //uses gravity on the character
    void CheckWorld(); //checks the character to be in the world
    
    
private:
    float mSpeedX, mSpeedY, mSpeedZ; //values of the speed along each axis
    float mCameraX, mCameraY; //values of the x,y coordinate for the camera
    float mPeak; //jump peak
    float mJumpDirection; //going to, at, or coming down from the peak
    bool mJumping; //is the character jumping?
};

#endif


(Character.cpp)
Code:
extern bool leftPressed,rightPressed,upPressed,downPressed;
extern bool spacePressed,iPressed;
bool spaceReleased;
bool mPeakAddY;
float mPeakFigure;

Code:
void CCharacter::Jump(float s)
{
    if (mJumpDirection == GOING_UP) //if still going up
    {
        SetDescent(0); //remove the descent
        AddY(mSpeedY * s); //add to the Y coordinate
        if (GetY() >= mPeak) //if above or at peak
        {
            mJumpDirection = COMING_DOWN; //set direction to coming down
        }
    }
}

void CCharacter::CheckForMovement(float s)
{
    if ((GetDescent() == 0) && ((mJumpDirection != GOING_UP))) //if not going up and not descending
    {
        mJumpDirection = AT_REST; //must be at rest
    }
    if (spacePressed && mJumpDirection==AT_REST)
    {
        if (mPeakAddY)
        {
            mPeakFigure += GetY();
            mPeakAddY = false;
        }
        mPeakFigure += ( .4 * s * GetH() );
    }
    if (!spacePressed && mPeakFigure!=0)
    {
        mPeakAddY = true;
        spaceReleased = true;
    }
    if (spaceReleased && !mJumping && (mJumpDirection == AT_REST)) //if 'space' is pressed and at rest
    {
        mPeak = mPeakFigure;
        mPeakFigure = 0;
        mJumpDirection = GOING_UP; //set direction to going up
        mJumping=true; //yes we are jumping
        spaceReleased = false;
    }

       [more key checking and close of the function]

Code:
void CCharacter::Update(float s)
{
    CheckForMovement(s); //first check for any keypresses by the player
    if (mJumping){Jump(s);} //if jumping run through the jump function
    AddX(mSpeedX * s);
    AddSpeedX( -s * .9 );
    if (mSpeedX < 0) { SetSpeedX(0); }
    CheckGravity(s);
    CheckWorld();
}


(main.cpp)
Code:
        Player.Update(g_FrameInterval); //frame independent movement

I understand that this may not be the clearest of help asking posts (it is 3:20 am here) but I hope that if you want to help me, you have the ability with the given information to do so. If you feel that I should figure it out on my own, please keep your opinion to yourself and do not reply. I, as always, will continue to try things out and if I figure it out I apologize for any inconvenience I will have caused you for answering this post. Thanks in advance.
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #2
I've just given your code a cursory look over for now (I'm typing this on my lunch break!), but one thing strikes me as odd.... You don't seem to be handling SDL_KEYDOWN and SDL_KEYUP events separately. If you're only getting keydowns, you'll find that spacePressed gets set to true the first time it's pressed, and then it'll stay like that. You need to detect the key release (keyup) as well, and set spacePressed to false again when it occurs.

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #3
In the second block of code there are two separate functions. Both are called separately. One handles the key presses and one handles key releases. I forgot this piece of code that calls those two functions:

(main.cpp)
Code:
while(! done) // as long as our job's not done
    {
        while( SDL_PollEvent(& event) ) // look for events (like keystrokes, resizing etc.)
        {
            switch ( event.type ) // what kind of event have we got ?
            {
                case SDL_QUIT : // if user wishes to quit
                    done = true; // this implies our job is done
                    break;
                    
                case SDL_KEYDOWN : // if the user has pressed a key
                    HandleKeyPressEvent( & event. key.keysym ); // callback for handling keystrokes, arg is key pressed
                    break;
                    
                case SDL_KEYUP :
                    HandleKeyReleaseEvent(& event.key.keysym) ; // callback for handling keystrokes, arg is key released
                    break;
Quote this message in a reply
Moderator
Posts: 771
Joined: 2003.04
Post: #4
NCarter Wrote:I've just given your code a cursory look over for now (I'm typing this on my lunch break!), but one thing strikes me as odd.... You don't seem to be handling SDL_KEYDOWN and SDL_KEYUP events separately. If you're only getting keydowns, you'll find that spacePressed gets set to true the first time it's pressed, and then it'll stay like that. You need to detect the key release (keyup) as well, and set spacePressed to false again when it occurs.

You may want to use SDL_GetKeyState:

Do this (only once)
Code:
keystate = SDL_GetKeyState(NULL);

and whenever you want to know if some key is down, check using:
Code:
if(keystate[SDLK_LEFT]))
    doSomething();
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #5
Why would this code be better than simply checking for keypresses and keyreleases?
Quote this message in a reply
Member
Posts: 469
Joined: 2002.10
Post: #6
shouldn't key state checking be sloooooooow? catching events will surely be faster, and you'll get multiple key taps when the state changes and sends the events. The only reason I'd see to use state checking would be for something that required realtime key feedback like a beat game, and even then...

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Member
Posts: 304
Joined: 2002.04
Post: #7
It would be so much easier if you posted a link to code so I could play with it and test things out. I am (almost) always able to fix posters problems when they provide a download. However, I notice that when you start a jump you set mJumping to true, but when you finish you never set it back to false. You also never formally initialize mJumping either which would be cleaner to do. Speaking of clean - merge HandleKeyPressEvent and HandleKeyReleaseEvent - make it:
Code:
void HandleKeyEvent(SDL_keysym * keysym, bool isKeyDownEvent)
{
    switch(keysym -> sym) // which key have we got
    {
        case SDLK_ESCAPE:
            Quit(0);
                        
        case SDLK_UP :
            upPressed = isKeyDownEvent;
            break;
...
That way you dont have duplicate code - and if you want to add/change a key you can do it in one spot instead of two. Call the function by:
Code:
while(! done) // as long as our job's not done
    {
        while( SDL_PollEvent(& event) ) // look for events (like keystrokes, resizing etc.)
        {
            switch ( event.type ) // what kind of event have we got ?
            {
                case SDL_QUIT : // if user wishes to quit
                    done = true; // this implies our job is done
                    break;
                                        
                case SDL_KEYDOWN : // if the user has pressed a key
                    HandleKeyEvent(& event.key.keysym, true); // callback for handling keystrokes, arg is key pressed
                    break;
                    
                case SDL_KEYUP :
                    HandleKeyEvent(& event.key.keysym, false); // callback for handling keystrokes, arg is key released
                    break;

or if you want to be slick:
Code:
while(! done) // as long as our job's not done
    {
        while( SDL_PollEvent(& event) ) // look for events (like keystrokes, resizing etc.)
        {
            switch ( event.type ) // what kind of event have we got ?
            {
                case SDL_QUIT : // if user wishes to quit
                    done = true; // this implies our job is done
                    break;
                                        
                case SDL_KEYDOWN : // if the user has pressed a key
                case SDL_KEYUP :
                    HandleKeyEvent(& event.key.keysym, (SDL_KEYDOWN == event.type)); // callback for handling keystrokes, arg is key released
                    break;

hth,
Codemattic
Quote this message in a reply
DM6
Unregistered
 
Post: #8
Instead of "building up energy" and then releasing the spacebar to jump you may want to consider the mario technique of accelerating upward as long as you hold the jump button. It's a control technique more players are comfortable with.

-Duncan
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #9
The Mario type jump is the one that I have working right now (well I did until I tried this method). I could probably get it to work again. Maybe I should for the sake of ease and to allow me some time to figure out some more things I need to get done if I want to enter uDevGames (which I do). If you'd like to get the project you can download it here. Just make sure to right click and download/save rather than clicking.
Quote this message in a reply
Moderator
Posts: 771
Joined: 2003.04
Post: #10
SimReality/Nick Wrote:Why would this code be better than simply checking for keypresses and keyreleases?

Because your code is doing this:

Code:
...
case SDLK_UP :
            upPressed = true;
            break;

case SDLK_DOWN :
            downPressed = true;
            break;

on its keydown handling function

and from your second post I guess you are doing this for your keyup handling function

Code:
...
case SDLK_UP :
            upPressed = false;
            break;

case SDLK_DOWN :
            downPressed = false;
            break;

The code I gave you eliminates the need to have one bool variable for each key state you want to track and the need to manually set such state. Personally I use both the keypress/release events and the keystate array. For instance, I check for the keypress event SDLK_p to pause/unpause the game, and the state array for SDLK_UP/DOWN/LEFT/RIGHT.

kelvin Wrote:shouldn't key state checking be sloooooooow? catching events will surely be faster, and you'll get multiple key taps when the state changes and sends the events. The only reason I'd see to use state checking would be for something that required realtime key feedback like a beat game, and even then...

No, the array of keystates is maintained automatically by SDL. SDL updates it even if you don't use it. "SDL_GetKeyState(NULL);" just returns you a pointer to such array, but you don't need to keep calling it after you get that pointer.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  unexpexced jump of graphics and delay displaying sefiroths 4 5,250 Sep 19, 2011 12:27 AM
Last Post: sefiroths
  jump preview StealthyCoin 1 2,700 Mar 7, 2008 10:25 AM
Last Post: StealthyCoin