[SDL] Jumping input

Started by
12 comments, last by _paf 11 years, 2 months ago

hello i am creating a platformer in C++/SDL and for some reason i cant work out the input for the jumping when i press the "UP" key like so


case SDLK_UP: jumping = true; break;
 

which sets jumping to true

inside the main game loop i have this


if (jumping == true)
{
myDot.yVel = 0;
myDot.yVel -= 30;
if (myDot.yVel == -100)
{
myDot.yVel = 0;
myDot.yVel += 60;
jumping = false;
}
}
 

what this is little snippet is supposed to repersent is when you press the "UP" button jumping is set to true which them runs this which sets yVel to = and then decreases it by 30 (which allows the player to move in the upwards direction for by 30. However when it hits -100 it knows you have jumped high and starts decreasing your yVel to fall back to the ground. But what is actully happening is the Player(myDot) is just forever going in the upwards position even though i have set it to stop at -100.

i realize i have completely over complicated that but you get the picture

Advertisement
EDIT: Actually your first problem is that by setting yVel to 0 first, and then doing yVel -= 30, you will always be setting it to -30, and never to anything below that. You should set your yVel to 0 when the key up event is received, instead of in your main loop.
Note that if you hold down a key, you may constantly receive events for that key. So your keyhandling should be:
case SDLK_UP: 
if (!jumping)
{
  jumping = true;
  myDot.yVel = 0;
}
break;
However, even if you remove setting it to 0 first you'll have another problem:

Your yVel will never be exactly -100. It will go -30, -60, -90, -120...etc.
Your check needs to be
if (myDot.yVel <= -100)
On a different note, is yVel supposed to be velocity or position? Because it kind of seems like you're treating it like position, and not velocity, which is fine, but the naming seems off.

its velocity but it just holds the value of the player speed it dosent increase also i just followed your guide lines and it made no diffrence the Player still moves to the screen

Player still goes to top of the screen?

Can you post your code now?

Also, what do you mean by "it just holds the value of the player speed it doesn't increase" - I don't understand?

Are you sure that those values you've set (the -100 limit) won't cause the player to move off the top of the screen anyway? Why not put some std::cout statements and check how your yVel is changing in the main loop?

Try having these variables:

vSpeed, vSpeedMax, gravity, jHeight;

if there is no collision below the object, add gravity ( should be positive ) to vSpeed.

if vSpeed > vSpeedMax set vSpeed to vSpeedMax

if you press the jump key set vSpeed = to jHeight ( you want jHeight to be negative )

if you are in the air and there is a collision below the object at the vSpeed distance, set vSpeed to 0 and resolve collision.

Finally, add the vSpeed variable to the objects y coordinate.

combatcactus could you possibly put that in code format

Edit: i have kinda fixed it when i press space and enter the jumping statement my yVel goes from 0 to -120 and moves -120 y's but then it changes back to 0 so he dosent come down. Here is my updated code


if (jumping == true)
{
myDot.yVel -= 120;
if (myDot.yVel <= -240)
{

myDot.yVel += 240;
jumping = false;
}
}

wow that printing the yVel to the console has really helped me understand it its not fixed but i have a better understanding.

Post more code, better yet, post the full code if you can.

It is hard to see what's wrong if we can't see some more code.

combatcactus could you possibly put that in code format

Edit: i have kinda fixed it when i press space and enter the jumping statement my yVel goes from 0 to -120 and moves -120 y's but then it changes back to 0 so he dosent come down. Here is my updated code

if (jumping == true){myDot.yVel -= 120;if (myDot.yVel <= -240){myDot.yVel += 240;jumping = false;}}
Following each iteration through there, it looks to me like this:
1. yVel gets -= 120, and should now be -120 (assuming you set it to 0 when jumping)
2. yVel <= -240 evalutes to false, code moves to next loop
3. yVel gets -= 120, and should now be -240
4. yVel <= -240 evaluates to True - you enter the if statement
5. yVel gets += 240 - and now becomes 0
6. jumping is set to false, nothing more is executed in that part

If you want to set your velocity to some downward velocity (like positive 240) once it reaches a maximum, you should do two things:
a) make the statement yVel += 240 be just yVel = 240;
b) make the check yVel <= 240 be yVel < 240
- doing these will results in your yVel being -120, -240, 0 (after each execution of your loop).
Hope that helps, because I'm still not 100% clear on how you're using your yVel.

i will post the full code


/*This source code copyrighted by Lazy Foo' Productions (2004-2013)
and may not be redistributed without written permission.*/

//The headers
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <string>
#include <fstream>
#include <SFML/Audio.hpp>
#include <iostream>
//Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
bool quit = false;
bool jumping = false;
//The frame rate
const int FRAMES_PER_SECOND = 20;

//The dot dimensions
const int DOT_WIDTH = 80;
const int DOT_HEIGHT = 80;

//The dimensions of the level
const int LEVEL_WIDTH = 2280;
const int LEVEL_HEIGHT = 480;

//Tile constants
const int TILE_WIDTH = 80;
const int TILE_HEIGHT = 80;
const int TOTAL_TILES = 192;
const int TILE_SPRITES = 12;

//The different tile sprites
const int TILE_RED = 0;
const int TILE_GREEN = 1;
const int TILE_BLUE = 2;
const int TILE_CENTER = 3;
const int TILE_TOP = 4;
const int TILE_TOPRIGHT = 5;
const int TILE_RIGHT = 6;
const int TILE_BOTTOMRIGHT = 7;
const int TILE_BOTTOM = 8;
const int TILE_BOTTOMLEFT = 9;
const int TILE_LEFT = 10;
const int TILE_TOPLEFT = 11;
 Uint8 *keystates = SDL_GetKeyState( NULL ); 
//The surfaces
SDL_Surface *dot = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *tileSheet = NULL;
SDL_Surface *background = NULL;
//Sprite from the tile sheet
SDL_Rect clips[ TILE_SPRITES ];

//The event structure
SDL_Event event;

//The camera
SDL_Rect camera = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };

//The tile
class Tile
{
    private:
    //The attributes of the tile
    SDL_Rect box;

    //The tile type
    int type;

    public:
    //Initializes the variables
    Tile( int x, int y, int tileType );

    //Shows the tile
    void show();

    //Get the tile type
    int get_type();

    //Get the collision box
    SDL_Rect get_box();
};

//The dot
class Dot
{
    private:
    //The dot's collision box
    

    //The velocity of the dot
    

    public:
    //Initializes the variables
    Dot();
SDL_Rect box;
   int xVel, yVel;
    //Takes key presses and adjusts the dot's velocity
    void handle_input();

    //Moves the dot
    void move( Tile *tiles[] );

    //Shows the dot on the screen
    void show();

    //Sets the camera over the dot
    void set_camera();
};

//The timer
class Timer
{
    private:
    //The clock time when the timer started
    int startTicks;

    //The ticks stored when the timer was paused
    int pausedTicks;

    //The timer status
    bool paused;
    bool started;

    public:
    //Initializes variables
    Timer();

    //The various clock actions
    void start();
    void stop();
    void pause();
    void unpause();

    //Gets the timer's time
    int get_ticks();

    //Checks the status of the timer
    bool is_started();
    bool is_paused();
};

SDL_Surface *load_image( std::string filename )
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;

    //The optimized surface that will be used
    SDL_Surface* optimizedImage = NULL;

    //Load the image
    loadedImage = IMG_Load( filename.c_str() );

    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );

        //Free the old surface
        SDL_FreeSurface( loadedImage );

        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF ) );
        }
    }

    //Return the optimized surface
    return optimizedImage;
}

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
    //Holds offsets
    SDL_Rect offset;

    //Get offsets
    offset.x = x;
    offset.y = y;

    //Blit
    SDL_BlitSurface( source, clip, destination, &offset );
}

bool check_collision( SDL_Rect A, SDL_Rect B )
{
    //The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;

    //Calculate the sides of rect A
    leftA = A.x;
    rightA = A.x + A.w;
    topA = A.y;
    bottomA = A.y + A.h;

    //Calculate the sides of rect B
    leftB = B.x;
    rightB = B.x + B.w;
    topB = B.y;
    bottomB = B.y + B.h;

    //If any of the sides from A are outside of B
    if( bottomA <= topB )
    {
        return false;
    }

    if( topA >= bottomB )
    {
        return false;
    }

    if( rightA <= leftB )
    {
        return false;
    }

    if( leftA >= rightB )
    {
        return false;
    }

    //If none of the sides from A are outside B
    return true;
}

bool init()
{
    //Initialize all SDL subsystems
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;
    }
    //Set up the screen
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

    //If there was an error in setting up the screen
    if( screen == NULL )
    {
        return false;
    }

    //Set the window caption
    SDL_WM_SetCaption( "Mario", NULL );

    //If everything initialized fine
    return true;
}

bool load_files()
{
// Load the music from an OggVorbis file
    
    // Display music informations
   
    //Load the dot image
    dot = load_image( "dot.png" );
  
    //If there was a problem in loading the dot
    if( dot == NULL )
    {
        return false;
    }

    //Load the tile sheet
    tileSheet = load_image( "tiles.png" );

    //If there was a problem in loading the tiles
    if( tileSheet == NULL )
    {
        return false;
    }

    //If everything loaded fine
    return true;
}

void clean_up( Tile *tiles[] )
{
    //Free the surfaces
    SDL_FreeSurface( dot );
    SDL_FreeSurface( tileSheet );
    SDL_FreeSurface( background );
    //Free the tiles
    for( int t = 0; t < TOTAL_TILES; t++ )
    {
        delete tiles[ t ];
    }

    //Quit SDL
    SDL_Quit();
}

void clip_tiles()
{
    //Clip the sprite sheet
    clips[ TILE_RED ].x = 0;
    clips[ TILE_RED ].y = 0;
    clips[ TILE_RED ].w = TILE_WIDTH;
    clips[ TILE_RED ].h = TILE_HEIGHT;

    clips[ TILE_GREEN ].x = 0;
    clips[ TILE_GREEN ].y = 80;
    clips[ TILE_GREEN ].w = TILE_WIDTH;
    clips[ TILE_GREEN ].h = TILE_HEIGHT;

    clips[ TILE_BLUE ].x = 0;
    clips[ TILE_BLUE ].y = 160;
    clips[ TILE_BLUE ].w = TILE_WIDTH;
    clips[ TILE_BLUE ].h = TILE_HEIGHT;

    clips[ TILE_TOPLEFT ].x = 80;
    clips[ TILE_TOPLEFT ].y = 0;
    clips[ TILE_TOPLEFT ].w = TILE_WIDTH;
    clips[ TILE_TOPLEFT ].h = TILE_HEIGHT;

    clips[ TILE_LEFT ].x = 80;
    clips[ TILE_LEFT ].y = 80;
    clips[ TILE_LEFT ].w = TILE_WIDTH;
    clips[ TILE_LEFT ].h = TILE_HEIGHT;

    clips[ TILE_BOTTOMLEFT ].x = 80;
    clips[ TILE_BOTTOMLEFT ].y = 160;
    clips[ TILE_BOTTOMLEFT ].w = TILE_WIDTH;
    clips[ TILE_BOTTOMLEFT ].h = TILE_HEIGHT;

    clips[ TILE_TOP ].x = 160;
    clips[ TILE_TOP ].y = 0;
    clips[ TILE_TOP ].w = TILE_WIDTH;
    clips[ TILE_TOP ].h = TILE_HEIGHT;

    clips[ TILE_CENTER ].x = 160;
    clips[ TILE_CENTER ].y = 80;
    clips[ TILE_CENTER ].w = TILE_WIDTH;
    clips[ TILE_CENTER ].h = TILE_HEIGHT;

    clips[ TILE_BOTTOM ].x = 160;
    clips[ TILE_BOTTOM ].y = 160;
    clips[ TILE_BOTTOM ].w = TILE_WIDTH;
    clips[ TILE_BOTTOM ].h = TILE_HEIGHT;

    clips[ TILE_TOPRIGHT ].x = 240;
    clips[ TILE_TOPRIGHT ].y = 0;
    clips[ TILE_TOPRIGHT ].w = TILE_WIDTH;
    clips[ TILE_TOPRIGHT ].h = TILE_HEIGHT;

    clips[ TILE_RIGHT ].x = 240;
    clips[ TILE_RIGHT ].y = 80;
    clips[ TILE_RIGHT ].w = TILE_WIDTH;
    clips[ TILE_RIGHT ].h = TILE_HEIGHT;

    clips[ TILE_BOTTOMRIGHT ].x = 240;
    clips[ TILE_BOTTOMRIGHT ].y = 160;
    clips[ TILE_BOTTOMRIGHT ].w = TILE_WIDTH;
    clips[ TILE_BOTTOMRIGHT ].h = TILE_HEIGHT;
}

bool set_tiles( Tile *tiles[] )
{
    //The tile offsets
    int x = 0, y = 0;

    //Open the map
    std::ifstream map( "lazy.map" );

    //If the map couldn't be loaded
    if( map == NULL )
    {
        return false;
    }

    //Initialize the tiles
    for( int t = 0; t < TOTAL_TILES; t++ )
    {
        //Determines what kind of tile will be made
        int tileType = -1;

        //Read tile from map file
        map >> tileType;

        //If the was a problem in reading the map
        if( map.fail() == true )
        {
            //Stop loading map
            map.close();
            return false;
        }

        //If the number is a valid tile number
        if( ( tileType >= 0 ) && ( tileType < TILE_SPRITES ) )
        {
            tiles[ t ] = new Tile( x, y, tileType );
        }
        //If we don't recognize the tile type
        else
        {
            //Stop loading map
            map.close();
            return false;
        }

        //Move to next tile spot
        x += TILE_WIDTH;

        //If we've gone too far
        if( x >= LEVEL_WIDTH )
        {
            //Move back
            x = 0;

            //Move to the next row
            y += TILE_HEIGHT;
        }
    }

    //Close the file
    map.close();

    //If the map was loaded fine
    return true;
}

bool touches_wall( SDL_Rect box, Tile *tiles[] )
{
    //Go through the tiles
    for( int t = 0; t < TOTAL_TILES; t++ )
    {
        //If the tile is a wall type tile
        if( ( tiles[ t ]->get_type() >= TILE_CENTER ) && ( tiles[ t ]->get_type() <= TILE_TOPLEFT ) )
        {
            //If the collision box touches the wall tile
            if( check_collision( box, tiles[ t ]->get_box() ) == true )
            {
                return true;
            }
        }
    }

    //If no wall tiles were touched
    return false;
}

Tile::Tile( int x, int y, int tileType )
{
    //Get the offsets
    box.x = x;
    box.y = y;

    //Set the collision box
    box.w = TILE_WIDTH;
    box.h = TILE_HEIGHT;

    //Get the tile type
    type = tileType;
}

void Tile::show()
{
    //If the tile is on screen
    if( check_collision( camera, box ) == true )
    {
        //Show the tile
        apply_surface( box.x - camera.x, box.y - camera.y, tileSheet, screen, &clips[ type ] );
    }
}

int Tile::get_type()
{
    return type;
}

SDL_Rect Tile::get_box()
{
    return box;
}

Dot::Dot()
{
    //Initialize the offsets
    box.x = 0;
    box.y = 200;
    box.w = DOT_WIDTH;
    box.h = DOT_HEIGHT;

    //Initialize the velocity
    xVel = 0;
    yVel = 0;
}

void Dot::handle_input()
{

    //If a key was pressed
    if( event.type == SDL_KEYDOWN )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
            case SDLK_UP: 
if (!jumping)
{
  jumping = true;
    yVel = 0;
} break;
            case SDLK_DOWN: yVel += 20 / 2; break;
            case SDLK_LEFT: xVel -= 20 / 2; break;
            case SDLK_RIGHT: xVel += 20 / 2; break;
        }
    }
    //If a key was released



    else if( event.type == SDL_KEYUP )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
        
            case SDLK_DOWN: yVel -= 20 / 2; break;
            case SDLK_LEFT: xVel += 20 / 2; break;
            case SDLK_RIGHT: xVel -= 20 / 2; break;
        }
    }
}

void Dot::move( Tile *tiles[] )
{
    //Move the dot left or right
    box.x += xVel;

    //If the dot went too far to the left or right or touched a wall
    if( ( box.x < 0 ) || ( box.x + DOT_WIDTH > LEVEL_WIDTH ) || touches_wall( box, tiles ) )
    {
        //move back
        box.x -= xVel;
    }

    //Move the dot up or down
    box.y += yVel;

    //If the dot went too far up or down or touched a wall
    if( ( box.y < 0 ) || ( box.y + DOT_HEIGHT > LEVEL_HEIGHT ) || touches_wall( box, tiles ) )
    {
        //move back
        box.y -= yVel;
    }
  if (( box.y < 0 ) || ( box.y + DOT_HEIGHT > LEVEL_HEIGHT ) )
{
quit = true;
}
}

void Dot::show()
{
    //Show the dot
    apply_surface( box.x - camera.x, box.y - camera.y, dot, screen );
}

void Dot::set_camera()
{
    //Center the camera over the dot
    camera.x = ( box.x + DOT_WIDTH / 2 ) - SCREEN_WIDTH / 2;
    camera.y = ( box.y + DOT_HEIGHT / 2 ) - SCREEN_HEIGHT / 2;

    //Keep the camera in bounds.
    if( camera.x < 0 )
    {
        camera.x = 0;
    }
    if( camera.y < 0 )
    {
        camera.y = 0;
    }
    if( camera.x > LEVEL_WIDTH - camera.w )
    {
        camera.x = LEVEL_WIDTH - camera.w;
    }
    if( camera.y > LEVEL_HEIGHT - camera.h )
    {
        camera.y = LEVEL_HEIGHT - camera.h;
    }
}

Timer::Timer()
{
    //Initialize the variables
    startTicks = 0;
    pausedTicks = 0;
    paused = false;
    started = false;
}

void Timer::start()
{
    //Start the timer
    started = true;

    //Unpause the timer
    paused = false;

    //Get the current clock time
    startTicks = SDL_GetTicks();
}

void Timer::stop()
{
    //Stop the timer
    started = false;

    //Unpause the timer
    paused = false;
}

void Timer::pause()
{
    //If the timer is running and isn't already paused
    if( ( started == true ) && ( paused == false ) )
    {
        //Pause the timer
        paused = true;

        //Calculate the paused ticks
        pausedTicks = SDL_GetTicks() - startTicks;
    }
}

void Timer::unpause()
{
    //If the timer is paused
    if( paused == true )
    {
        //Unpause the timer
        paused = false;

        //Reset the starting ticks
        startTicks = SDL_GetTicks() - pausedTicks;

        //Reset the paused ticks
        pausedTicks = 0;
    }
}

int Timer::get_ticks()
{
    //If the timer is running
    if( started == true )
    {
        //If the timer is paused
        if( paused == true )
        {
            //Return the number of ticks when the timer was paused
            return pausedTicks;
        }
        else
        {
            //Return the current time minus the start time
            return SDL_GetTicks() - startTicks;
        }
    }

    //If the timer isn't running
    return 0;
}

bool Timer::is_started()
{
    return started;
}

bool Timer::is_paused()
{
    return paused;
}

int main( int argc, char* args[] )
{

 sf::Music Music;
    if (!Music.OpenFromFile("awake.ogg"))
        return EXIT_FAILURE;

    //Quit flag
    
    
    //The dot
    Dot myDot;

    //The tiles that will be used
    Tile *tiles[ TOTAL_TILES ];

    //The frame rate regulator
    Timer fps;

    //Initialize
    if( init() == false )
    {
        return 1;
    }
    //Load the files
    if( load_files() == false )
    {
        return 1;
    }
    Music.Play();
    //Clip the tile sheet
    clip_tiles();

    //Set the tiles
    if( set_tiles( tiles ) == false )
    {
        return 1;
    }

    //While the user hasn't quit
    while( quit == false )
    {
        //Start the frame timer
        fps.start();

if (jumping == true)
{
myDot.yVel -= 120;
if (myDot.yVel < -240)
{

myDot.yVel = 240;
myDot.yVel = 0;
jumping = false;
}
}

        //While there's events to handle
        while( SDL_PollEvent( &event ) )
        {
            //Handle events for the dot
            myDot.handle_input();

            //If the user has Xed out the window
            if( event.type == SDL_QUIT )
            {
                //Quit the program
                quit = true;
            }
        }

        //Move the dot
        myDot.move( tiles );
        std::cout<<myDot.yVel<<std::endl;
        //Set the camera
        myDot.set_camera();

        //Show the tiles
        for( int t = 0; t < TOTAL_TILES; t++ )
        {
            tiles[ t ]->show();
        }

        //Show the dot on the screen
        myDot.show();

        //Update the screen
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;
        }

        //Cap the frame rate
        if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
        {
            SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
        }
    }

    //Clean up
    clean_up( tiles );

    return 0;
}

This topic is closed to new replies.

Advertisement