# SDL player.update doesnt update?

This topic is 2316 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey guys im have a little bit of trouble with checking keys for input, im pretty sure they are being checked correctly but it doesnt seem to change the location of my player image.

Here is my main code
#include "SDL.h" #include <string> #include "player.h" SDL_Surface *screen = NULL; SDL_Event event; player gamePlayer; bool init(){ if (SDL_Init (SDL_INIT_EVERYTHING) == -1) { return false; } screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE); if (screen == NULL) { return false; } SDL_WM_SetCaption("Event Handling", NULL); return true; } int main(int argc, char* args[] ){ bool quit = false; gamePlayer.loadImage("hello2.png"); //initialize SDL if (init() == false) { return 1; } while (quit == false) { while (SDL_PollEvent( &event)) { if (event.type == SDL_QUIT) { quit = true; } gamePlayer.update(); } SDL_BlitSurface(gamePlayer.draw(),NULL,screen,&gamePlayer.rtnPos()); if (SDL_Flip(screen) == -1) { return 1; } } return 0; }

Here is my player.h and player.cpp
//Player header #ifndef PLAYER_H #define PLAYER_H //includes #include <string> #include "SDL.h" #include "SDL_image.h" //Using namespace //body class player{ private: SDL_Surface* image; SDL_Event iEvent; SDL_Rect pos; public: player(); void update(); void loadImage(std::string filename); SDL_Rect rtnPos(){return pos;} SDL_Surface* draw(); }; //end body #endif ////player.cpp #include "player.h" player::player() { image = IMG_Load("dot.bmp"); pos.x = 100; pos.y = 100; pos.h = 320; pos.w = 240; } void player::loadImage(std::string fileName) { image = IMG_Load(fileName.c_str()); } SDL_Surface* player::draw() { return image; } void player::update() { if(SDL_PollEvent(&iEvent)) { if (iEvent.type == SDL_KEYDOWN) { switch(iEvent.key.keysym.sym) { case SDLK_UP: pos.y -= 10; break; case SDLK_RIGHT: pos.x += 10; break; case SDLK_LEFT: pos.x -= 10; break; case SDLK_DOWN: pos.y += 10; break; } } } }

Can anyone see why it isnt moving?

Cheers Canvas

##### Share on other sites
You have two poll event loops, but SDL only has a single event queue. The event loop in main will pick up the first even that occurs in a given frame, and the player::update() will pick up the second. They will then alternate while events are still in the queue (for non-mouse games, there are generally few events in the queue).

I recommend having a single even loop, and passing interesting events to the player object:
 // In player.h class player { public: // ... void update(SDL_Event event); // ... }; // Inside main() while (SDL_PollEvent( &event)) { if (event.type == SDL_QUIT) { quit = true; } else { gamePlayer.update(event); } } 
Now, in this case your player object will correctly receive the events of interest.

There may remain another issue however, depending on the style of your game. If your game expects the player to continue moving while the key is held down, then you need a way to "remember" the direction of movement and a way to update the position even when events do occur.

A simple solution is to add some variables to the player to indicate the current direction and speed of movement, and to separate the event code from the update code, like so:
 class Player { public: Player(); void update(); void onEvent(const SDL_Event &event); // ... private: int x; int y; int vx; int vy; }; // Player.cpp Player::Player() { x = 100; y = 100; vx = 0; vy = 0; } void Player::onEvent(const SDL_Event &event) { const int SPEED = 10; if (event.type == SDL_KEYDOWN) { switch(event.key.keysym.sym) { case SDLK_UP: vy -= SPEED; break; case SDLK_DOWN: vy += SPEED; break; case SDLK_LEFT: vx -= SPEED; break; case SDLK_RIGHT: vx += SPEED; break; } } else if(event.type == SDL_KEYUP) { switch(event.key.keysym.sym) { case SDLK_UP: vy += SPEED; break; case SDLK_DOWN: vy -= SPEED; break; case SDLK_LEFT: vx += SPEED; break; case SDLK_RIGHT: vx -= SPEED; break; } } } void Player::update() { x += vx; y += vy; // Maybe some code to keep the player inside the screen/world/map bounds? SDL_Surface *screen = SDL_GetVideoSurface(); if(x < 0) { x = 0; } else if(x > screen->w) { x = screen->w; } if(y < 0) { y = 0; } else if(x > screen->h) { y = screen->h; } } 
An interesting "trick" here is starting the velocity at 0, and adding or subtracting the speed to it, rather than simply setting the speed. You may wonder at this idea - surely any key can only be pressed down once, and thus the difference would appear irrelevant.

For reference, here is the type of implementation I'll be discussing:
 void Player::onEvent(const SDL_Event &event) { const int SPEED = 10; if (event.type == SDL_KEYDOWN) { switch(event.key.keysym.sym) { case SDLK_UP: vy = -SPEED; break; case SDLK_DOWN: vy = SPEED; break; case SDLK_LEFT: vx = -SPEED; break; case SDLK_RIGHT: vx = SPEED; break; } } else if(event.type == SDL_KEYUP) { switch(event.key.keysym.sym) { case SDLK_UP: vy = 0; break; case SDLK_DOWN: vy = 0; break; case SDLK_LEFT: vx = 0; break; case SDLK_RIGHT: vx = 0; break; } } } 
Imagine that the player starts by holding down the UP key. So their y velocity is incremented to -10. Now, imagine that without releasing the UP key they press the down key. If you set the velocities, rather than added to them, then their velocity would become +10. With the addition method, it becomes 0 - which I think is reasonable if the user holds the up and down keys at the same time.

However, even that, while nice, is not the real "win". Think what happens now if the user releases the either key under the "set" implementation - the velocity becomes zero. But the player is still holding down a key!

This isn't perfect. If you are running the game in a window, and the game loses focus, the state of the player can get out of sync with the keys. Another option is simply to ask for the current key "state":
 class Player { public: Player(); void update(); // ... private: int x; int y; // ... }; Player::Player() { x = 100; y = 100; } void Player::update() { const int SPEED = 10; Uint8 *keys = SDL_GetKeyState(NULL); if(keys[SDLK_UP]) { y -= SPEED; } if(keys[SDLK_DOWN]) { y += SPEED; } if(keys[SDLK_LEFT]) { x -= SPEED; } if(keys[SDLK_RIGHT]) { x += SPEED; } // Bounds code is similar } 
In this case, you would have no player related code in your event loop, instead you must call Player::update() every frame.

Finally, note that I'm using regular integers to hold the player's position, rather than a SDL_Rect. SDL_BlitSurface() modifies the "destination" rectangle passed to it to contain the "clipped" co-ordinates. You are passing a copy, so this doesn't affect you... yet.

##### Share on other sites
Awesome, im going to try the code soon, just abit busy at the moment, Also i know about the focus stuff and velocity im going to try and code it later and i will let you know if i need help with them also but cheers for the reminder , I will reply if i found some errors , also when it draws the rectangle it seems to draw it in all of its previous positions? can you see why in my code?

##### Share on other sites
Well you don't clear the screen, so anything you have previously drawn will still be underneath your new stuff. A simple way to clear the screen is use the SDL_FillRect() function, and pass a NULL SDL_Rect pointer:
 SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); 

##### Share on other sites
K i have just moved my player.update and other stuff and works correctly, but sometimes when i release a button the player sprite keeps moving, like its stuck on speed 10, why so?

player handleInput code here
void player::handleInput(SDL_Event iEvent) { const int SPEED = 10; if (iEvent.type == SDL_KEYDOWN) { switch(iEvent.key.keysym.sym) { case SDLK_UP: yVel = -SPEED; break; case SDLK_DOWN: yVel = SPEED; break; case SDLK_LEFT: xVel = -SPEED; break; case SDLK_RIGHT: xVel = SPEED; break; } } else if(iEvent.type == SDL_KEYUP) { switch(iEvent.key.keysym.sym) { case SDLK_UP: yVel = 0; break; case SDLK_DOWN: yVel = 0; break; case SDLK_LEFT: xVel = 0; break; case SDLK_RIGHT: xVel = 0; break; } } }

if i press right arrow and up arrow at the same time and then let go at the same time, the player sprite just goes "wwweeeeeeeee" upwards

i feel like its because the players.udpate is the only one that can change the xVel and yVel, now if i was to let go of a key and the pollEvent missed it, it wont stop moving until i press the key again, but why is this so? is my code wrong?

##### Share on other sites
gamePlayer.update() needs to be called even when there are no events (That's what's causing your jerky movement).
gamePlayer.handleInput() needs to be called only when there are events.

So it should look like this:
 while(quit == false) { //Handle events first. SDL_Event event; while(SDL_PollEvent(&event)) { //Handle events like quiting. gamePlayer.handleInput(event); otherStuff.handleInput(event); moreThings.handleInput(event); } //Handle updating next. gamePlayer.update(); otherStuff.update(); moreThings.update(); //Handle drawing after that. SDL_FillRect(...); //Whatever you draw last is above whatever you drew before it. gameWorld.draw(screen); gamePlayer.draw(screen); otherStuff.draw(screen); moreThings.draw(screen); SDL_Flip(screen); }

##### Share on other sites
Awesome my code for my main loop is now
while (quit == false) { fps.start(); while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { quit = true; } //Handle Inputs gamePlayer.handleInput(event); } //Update gamePlayer.update(); //Clear screen SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); //Draw SDL_BlitSurface(gamePlayer.draw(),NULL,screen,&gamePlayer.rtnPos()); if (SDL_Flip(screen) == -1) { return 1; } if( fps.rtnTicks() < 1000 / 30 ) { SDL_Delay( ( 1000 / 30 ) - fps.rtnTicks() ); } }

Cheers for the help, i should i seen this myself

1. 1
Rutin
23
2. 2
3. 3
JoeJ
20
4. 4
5. 5

• 9
• 33
• 41
• 23
• 13
• ### Forum Statistics

• Total Topics
631745
• Total Posts
3002006
×