Trouble moving sprites

Started by
21 comments, last by CraazyDave 12 years, 8 months ago
I am trying to make a game in SDL but I am avoiding at all costs to have any part of SDL in the main. Instead I have a class GameEngine with all the SDL functionality.

My problem is that I need to tie together the keyinputs that I check in GameEngine and call in the main method to the blitting of the Sprite.
It all should be straightforward but for some reason it does not work for me.

Now the problem I am having is that the x and y values that I use to change the position of the Sprite does not update with my keypresses.

The Method that checks the events:


bool GameEngine::events()
{
std::cout << spriteField.size() << std::endl;

int xVel = 0;
int yVel = 0;

while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
exit();
return true;
}
if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_UP:
yVel -= 5;
break;
case SDLK_DOWN:
yVel += 5;
break;
case SDLK_RIGHT:
xVel -= 5;
break;
case SDLK_LEFT:
xVel += 5;
break;
}
}
if(event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP:
yVel += 5;
break;
case SDLK_DOWN:
yVel -= 5;
break;
case SDLK_RIGHT:
xVel += 5;
break;
case SDLK_LEFT:
xVel -= 5;
break;
}
}

for(int i = 0; i < spriteField.size(); i++)
{
spriteField.setVel(xVel, yVel);
spriteField.move();
}
}

return false;
}


Any help with figuring out why it does not work would be very helpfull.
Advertisement
Try changing your second if to an else if. I have never used SDL but from what I can see if you have a key down and than release it the events will cancel as it is an if statement and not an else if.

Remember to mark someones post as helpful if you found it so.

Journal:

http://www.gamedev.net/blog/908-xxchesters-blog/

Portfolio:

http://www.BrandonMcCulligh.ca

Company:

www.gwnp.ca


Try changing your second if to an else if. I have never used SDL but from what I can see if you have a key down and than release it the events will cancel as it is an if statement and not an else if.



That wont have an effect, as the event will only return a result once per call, AKA, it's not going to change during the processing of that code.
However, you are onto what I think the problem is. In the event loop you are increasing the velocity on key down, but then decrementing velocity on key up. That means on a key press ( an down and up event ) you are immediately increasing the velocity, then in the very next event literally milliseconds away, you are descreasing velocity.


So, in the event of a keypress, the following is happening.

velocity set to 0

key down, velocity increased by 5

milliseconds later, next event in loop is keyup event, velocity reduced back to 0.


This is most likely not the logic you actually want. That said, in the event of a key held down, your sprite should move. In this case, without seeing more code ( specifically setVel() and move() ) there is no way to know eactly where the problem is.

[quote name='XXChester' timestamp='1311619888' post='4840121']
Try changing your second if to an else if. I have never used SDL but from what I can see if you have a key down and than release it the events will cancel as it is an if statement and not an else if.



That wont have an effect, as the event will only return a result once per call, AKA, it's not going to change during the processing of that code.
However, you are onto what I think the problem is. In the event loop you are increasing the velocity on key down, but then decrementing velocity on key up. That means on a key press ( an down and up event ) you are immediately increasing the velocity, then in the very next event literally milliseconds away, you are descreasing velocity.


So, in the event of a keypress, the following is happening.

velocity set to 0

key down, velocity increased by 5

milliseconds later, next event in loop is keyup event, velocity reduced back to 0.


This is most likely not the logic you actually want. That said, in the event of a key held down, your sprite should move. In this case, without seeing more code ( specifically setVel() and move() ) there is no way to know eactly where the problem is.
[/quote]


I changed it to else if, and I can agree why that would be preferable but it made no difference. So here is the setVel() and Move()

void Sprite::setVel(int xv, int yv)
{
xVel += xv;
yVel += yv;

std::cout << "setVel" << x << " " << y << std::endl;
}


And:


void Sprite::move()
{
x += xVel;
y += yVel;

std::cout << "move is" << x << " " << y << std::endl;
}


And nothing special happens in them. I could poste the entire main, GameEngine and Sprite class if needed

[quote name='XXChester' timestamp='1311619888' post='4840121']
Try changing your second if to an else if. I have never used SDL but from what I can see if you have a key down and than release it the events will cancel as it is an if statement and not an else if.



That wont have an effect, as the event will only return a result once per call, AKA, it's not going to change during the processing of that code.
However, you are onto what I think the problem is. In the event loop you are increasing the velocity on key down, but then decrementing velocity on key up. That means on a key press ( an down and up event ) you are immediately increasing the velocity, then in the very next event literally milliseconds away, you are descreasing velocity.


So, in the event of a keypress, the following is happening.

velocity set to 0

key down, velocity increased by 5

milliseconds later, next event in loop is keyup event, velocity reduced back to 0.


This is most likely not the logic you actually want. That said, in the event of a key held down, your sprite should move. In this case, without seeing more code ( specifically setVel() and move() ) there is no way to know eactly where the problem is.
[/quote]

Basically what you stated is exactly what I was thinking about the events canceling each other but I am not sure why I thought the else if would fix that.

As for the problem Crazy, you are probably still having the same problem even though they are split into separate functions because the way you are handling the events is probably the same...on key down; do this, on key up; do this. You may want to post how you are calling these functions. Also a little background on the type of game might help, reading the code I am assuming it is a sort of racing game or space game and that is why you have -velocity calculations on key up opposed to just stopping the sprite all together, correct?

Remember to mark someones post as helpful if you found it so.

Journal:

http://www.gamedev.net/blog/908-xxchesters-blog/

Portfolio:

http://www.BrandonMcCulligh.ca

Company:

www.gwnp.ca


[quote name='Serapth' timestamp='1311620372' post='4840127']
[quote name='XXChester' timestamp='1311619888' post='4840121']
Try changing your second if to an else if. I have never used SDL but from what I can see if you have a key down and than release it the events will cancel as it is an if statement and not an else if.



That wont have an effect, as the event will only return a result once per call, AKA, it's not going to change during the processing of that code.
However, you are onto what I think the problem is. In the event loop you are increasing the velocity on key down, but then decrementing velocity on key up. That means on a key press ( an down and up event ) you are immediately increasing the velocity, then in the very next event literally milliseconds away, you are descreasing velocity.


So, in the event of a keypress, the following is happening.

velocity set to 0

key down, velocity increased by 5

milliseconds later, next event in loop is keyup event, velocity reduced back to 0.


This is most likely not the logic you actually want. That said, in the event of a key held down, your sprite should move. In this case, without seeing more code ( specifically setVel() and move() ) there is no way to know eactly where the problem is.
[/quote]

Basically what you stated is exactly what I was thinking about the events canceling each other but I am not sure why I thought the else if would fix that.

As for the problem Crazy, you are probably still having the same problem even though they are split into separate functions because the way you are handling the events is probably the same...on key down; do this, on key up; do this. You may want to post how you are calling these functions. Also a little background on the type of game might help, reading the code I am assuming it is a sort of racing game or space game and that is why you have -velocity calculations on key up opposed to just stopping the sprite all together, correct?
[/quote]

Allright. I did some thinking and I figure that the else if is unnecessary so I commented it away to try and see what happened.

RIght now what happens everytime I press a key I see that it changes the xVel and yVel in setVel() and changes are made to the values affected in move() but when the values are taken to the bliting method they are the
of the dafault value.
If that makes any sense.

I'll just post the classes that is involved in the movement:

GameEngine.cpp:

#include "SDL.h"
#include "GameEngine.h"
#include "Image.h"
#include "Sprite.h"
#include <vector>
#include <string>
#include <iostream>

GameEngine::GameEngine(int h, int w)
{
SCREEN_HEIGHT = h;
SCREEN_WIDTH = w;

SDL_Init(SDL_INIT_EVERYTHING);

screen = SDL_SetVideoMode(SCREEN_HEIGHT, SCREEN_WIDTH, 32, SDL_SWSURFACE | SDL_DOUBLEBUF);

SDL_ShowCursor(SDL_DISABLE);
}

void GameEngine::log(std:: string log)
{
std::cout << log.c_str() << std::endl;
}

void GameEngine::update()
{
//Update screen and rect
SDL_Flip(screen);
SDL_UpdateRect(screen, 0, 0, 0, 0);
}

void GameEngine::fill()
{
SDL_FillRect(getScreen(), NULL, 0x000000);
}

void GameEngine::blit(SDL_Surface * i, SDL_Rect rect)
{
SDL_BlitSurface(i, NULL, screen, &rect);
}

void GameEngine::exit()
{
SDL_Quit();
}

bool GameEngine::events()
{
std::cout << spriteField.size() << std::endl;

int xVel = 0;
int yVel = 0;

while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
exit();
return true;
}
if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_UP:
yVel -= 5;
break;
case SDLK_DOWN:
yVel += 5;
break;
case SDLK_RIGHT:
xVel -= 5;
break;
case SDLK_LEFT:
xVel += 5;
break;
}
}
/*else if(event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP:
yVel += 5;
break;
case SDLK_DOWN:
yVel -= 5;
break;
case SDLK_RIGHT:
xVel += 5;
break;
case SDLK_LEFT:
xVel -= 5;
break;
}
}*/

for(int i = 0; i < spriteField.size(); i++)
{
spriteField.setVel(xVel, yVel);
spriteField.move();
}
}

return false;
}

int GameEngine::checkFPS()
{
const int tickInterval = 1000/30;
nextTick = SDL_GetTicks() + tickInterval;

delay = nextTick - SDL_GetTicks();

return delay;
}

void GameEngine::delayProgram(int delay)
{
if(delay > 0)
SDL_Delay(delay);
}

SDL_Surface * GameEngine::getScreen()
{
return screen;
}

void GameEngine::addSprite(Sprite s)
{
spriteField.push_back(s);
}

SDL_Rect GameEngine::createTempRect(int x, int y)
{
SDL_Rect rectTemp;
rectTemp.x = x;
rectTemp.y = y;

return rectTemp;
}



Sprite.cpp:

Sprite::Sprite(int xv, int yv, bool b)
{
xVel = 0;
yVel = 0;
player = b;
x = xv;
y = yv;
rect.setRect(x, y);
w = rect.getW();
h = rect.getH();
}

void Sprite::setImage(Image img)
{
i = img;
}

Image Sprite::getImage()
{
return i;
}

void Sprite::tick(std::vector<Sprite> spriteField)
{
for(int i = 0; i < spriteField.size(); i++)
collision(spriteField);
}

void Sprite::setVel(int xv, int yv)
{
xVel += xv;
yVel += yv;

std::cout << "setVel" << x << " " << y << std::endl;
}

void Sprite::move()
{
x += xVel;
y += yVel;

std::cout << "move is" << x << " " << y << std::endl;
}

bool Sprite::collision(Sprite other)
{
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;

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

//Calculate the sides of rect B
leftB = other.x;
rightB = other.x + other.w;
topB = other.y;
bottomB = other.y + other.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;
}

void Sprite::log(std::string log)
{
std::cout << log << std::endl;
}

Rect Sprite::getRect()
{
return rect;
}

int Sprite::getX()
{
return x;
}

int Sprite::getY()
{
return y;
}


and the main.cpp:

int main(int argc, char * args[])
{
GameEngine g(1000, 800);

bool quit = false;

//Create images.
Image i(true, "pong_player.bmp");
Image background(false, "pong_middle.bmp");

//Sprite
Sprite s1(150, 200, true);
s1.setImage(i);
g.addSprite(s1);

while(quit == false)
{
int delay = g.checkFPS();

//Fill screen with black
g.fill();

g.blit(s1.getImage().getSurface(), s1.getRect().get());
//Blit the background
g.blit(background.getSurface(), g.createTempRect(500, 0));

//Update the screen
g.update();
//Check for events
quit = g.events();

g.delayProgram(delay);
}

g.exit();
return 0;
}


And I'm not trying to make a particularly sofisticated game, I'm trying to make a reversed version of Pong where you try to avoid the ball instead of hitting it.
Am I missing something? I see you are setting the xVel and yVel in your sprite class but I do not see those values referenced anywhere for rendering/updating

**EDIT**
removed first edit after another re-read
***EDIT**

Remember to mark someones post as helpful if you found it so.

Journal:

http://www.gamedev.net/blog/908-xxchesters-blog/

Portfolio:

http://www.BrandonMcCulligh.ca

Company:

www.gwnp.ca


Am I missing something? I see you are setting the xVel and yVel in your sprite class but I do not see those values referenced anywhere for rendering/updating

**EDIT**
removed first edit after another re-read
***EDIT**


Well I call the setVel method that sets what the velocity of the sprite should be in the events() method, and now that I look at it it perhaps should be xVel = xv not x += xv but I digress. And directly after that I call the move method() which in turn changes the x and y values.

And they are changed correctly when everytime I check.
By the way the move method I posted was incomplete from what I have been testing. I forgot to add the

rect.setRect(x, y);

At the end of the method. And rect is of a class that contains a SDL_Rect and setRect(x, y); sets the x and y values of the rect. And that rect are then taken in the main method for the blitting of the sprite. Damn this is getting messy.

SO what is happening is that the keypresses are working but the rect does not change.

[quote name='XXChester' timestamp='1311694815' post='4840593']
Am I missing something? I see you are setting the xVel and yVel in your sprite class but I do not see those values referenced anywhere for rendering/updating

**EDIT**
removed first edit after another re-read
***EDIT**


Well I call the setVel method that sets what the velocity of the sprite should be in the events() method, and now that I look at it it perhaps should be xVel = xv not x += xv but I digress. And directly after that I call the move method() which in turn changes the x and y values.

And they are changed correctly when everytime I check.
By the way the move method I posted was incomplete from what I have been testing. I forgot to add the

rect.setRect(x, y);

At the end of the method. And rect is of a class that contains a SDL_Rect and setRect(x, y); sets the x and y values of the rect. And that rect are then taken in the main method for the blitting of the sprite. Damn this is getting messy.

SO what is happening is that the keypresses are working but the rect does not change.
[/quote]

If it's not clear why this does not work, how would you achieve what I'm trying to do here? With moving a sprite while keeping all the SDL functionality away from the main.
Btw, I have gotten everything to work when I hardcode a movement for the sprites or if I have written the event loop in the main instead.

[quote name='XXChester' timestamp='1311694815' post='4840593']
Am I missing something? I see you are setting the xVel and yVel in your sprite class but I do not see those values referenced anywhere for rendering/updating

**EDIT**
removed first edit after another re-read
***EDIT**


Well I call the setVel method that sets what the velocity of the sprite should be in the events() method, and now that I look at it it perhaps should be xVel = xv not x += xv but I digress. And directly after that I call the move method() which in turn changes the x and y values.

And they are changed correctly when everytime I check.
By the way the move method I posted was incomplete from what I have been testing. I forgot to add the

rect.setRect(x, y);

At the end of the method. And rect is of a class that contains a SDL_Rect and setRect(x, y); sets the x and y values of the rect. And that rect are then taken in the main method for the blitting of the sprite. Damn this is getting messy.

SO what is happening is that the keypresses are working but the rect does not change.
[/quote]

If it's not clear why this does not work, how would you achieve what I'm trying to do here? With moving a sprite while keeping all the SDL functionality away from the main.
Btw, I have gotten everything to work when I hardcode a movement for the sprites or if I have written the event loop in the main instead.

This topic is closed to new replies.

Advertisement