I'm doing this like this, in .hpp file:
class Player
{
public:
Player(){}
Player(){}
virtual ~Player(){}
void handler(SDL_Event event);
void update()
{
move(velocityForwardX, velocityForwardY);
move(-velocityBackwardX, -velocityBackwardY);
/* the player moves from it current position. */
}
protected:
int speed = 5;
int velocityForwardX = 0;
int velocityForwardY = 0;
int velocityBackwardX = 0;
int velocityBackwardY = 0;
};
in .cpp file:
#include "Player.h"
void Player::handler(SDL_Event event)
{
if(event.type == SDL_KEYDOWN){
switch(event.key.keysym.sym)
{
case SDLK_d:
velocityForwardX = speed;
break;
case SDLK_q:
velocityBackwardX = speed;
break;
case SDLK_z:
velocityBackwardY = speed;
break;
case SDLK_s:
velocityForwardY = speed;
break;
default:
break;
}
}
else if(event.type == SDL_KEYUP){
switch(event.key.keysym.sym)
{
case SDLK_d:
velocityForwardX = 0;
break;
case SDLK_q:
velocityBackwardX = 0;
break;
case SDLK_z:
velocityBackwardY = 0;
break;
case SDLK_s:
velocityForwardY = 0;
break;
default:
break;
}
}}
like this I can presse any key and release it and the player move well. It also works if two opposite keys are pressed then one is release so the player is going in the right direction. Can we make it easier ? (sorry for my english)
You could store only one variable per direction and add and subtract speed when pressing and releasing a button, e.g.
switch(event.key.keysym.sym)
{
case SDLK_d:
velocityX += speed;
break;
case SDLK_q:
velocityX -= speed;
break;
case SDLK_z:
velocityY -= speed;
break;
case SDLK_s:
velocityY += speed;
break;
default:
break;
}
// similar for key release
With this if you press opposite x direction keys simultaniously, velocityX will be 0, and the same for the y direction and velocityY.
Related
How do I make my "game" take 2 key inputs, for example if the user clicks w and d he moves up right.
btw, the variable eventCheck is an Event object
here's my current code(obviously not the full code just the event code):
while (window.isOpen()) {
Event eventCheck;
while (window.pollEvent(eventCheck)) {
switch (eventCheck.type) {
case Event::Closed:
window.close();
break;
case Event::KeyPressed:
switch (eventCheck.key.code) {
case Keyboard::W:
if (Keyboard::isKeyPressed(Keyboard::A)) {
const Vector2f spritePos = sprite.getPosition();
sprite.setPosition(spritePos.x, spritePos.y - 5);}
break;
case Keyboard::A:
if (Keyboard::isKeyPressed(Keyboard::A)) {
const Vector2f spritePos = sprite.getPosition();
sprite.setPosition(spritePos.x - 5, spritePos.y);}
break;
case Keyboard::S:
if (Keyboard::isKeyPressed(Keyboard::S)) {
const Vector2f spritePos = sprite.getPosition();
sprite.setPosition(spritePos.x, spritePos.y + 5);}
break;
case Keyboard::D:
if (Keyboard::isKeyPressed(Keyboard::D)) {
const Vector2f spritePos = sprite.getPosition();
sprite.setPosition(spritePos.x + 5, spritePos.y);}
break;
}
}
break;
}
window.clear(Color(0,0,0,255));
window.draw(sprite);
window.display();
}
return 0;
1.) SFML has event polling through sf::Event and real time key state access provided through sf::Keyboard. If you only need to handle a single key press, your best bet is to poll them through window.pollEvent otherwise it's usually always better to get the state of a key and react based on the state. In this case you are mixing event polling with keyboard states. Choose one or the other.
2.) Not using sf:: removes a lot of clarity from the code
Now onto the code!
I wouldn't poll any user input inside events. I would get the state of the keys:
// Once per game loop
void ProcessInput()
{
int keyCount = 0;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
keyCount++;
//Move Character Up, The more keys are pressed, the more i would mess around with speed/velocity here
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
keyCount++;
//Move Character Left, The more keys are pressed, the more i would mess around with speed/velocity here
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
keyCount++;
//Move Character Down, The more keys are pressed, the more i would mess around with speed/velocity here
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
keyCount++;
//Move Character Right, The more keys are pressed, the more i would mess around with speed/velocity here
}
}
Depending on the amount of keys the user pressed, you would want to move your character less since they could move more diagonally than vertically/horizontally, but mess around with speed and velocity as you see fit.
I ended up doing
bool moveL = false;
bool moveU = false;
bool moveD = false;
bool moveR = false;
while (window.isOpen()) {
Event eventCheck;
while (window.pollEvent(eventCheck)) {
switch (eventCheck.type) {
case Event::Closed:
window.close();
break;
case Event::KeyReleased:
switch (eventCheck.key.code) {
case Keyboard::A:
moveL = false;
break;
case Keyboard::W:
moveU = false;
break;
case Keyboard::S:
moveD = false;
break;
case Keyboard::D:
moveR = false;
break;
}
break;
case Event::KeyPressed:
switch (eventCheck.key.code) {
case Keyboard::A:
moveL = true;
break;
case Keyboard::W:
moveU = true;
break;
case Keyboard::S:
moveD = true;
break;
case Keyboard::D:
moveR = true;
break;
case Keyboard::Space:
jump(sprite, window);
break;
}
const Vector2f spritePos = sprite.getPosition();
if (moveD && moveR) {
sprite.setPosition(spritePos.x + 5, spritePos.y + 5);
}
else if (moveL && moveU) {
sprite.setPosition(spritePos.x - 5, spritePos.y - 5);
}
else if (moveU && moveD) {
sprite.setPosition(spritePos.x, spritePos.y);
}
else if (moveU && moveR) {
sprite.setPosition(spritePos.x + 5, spritePos.y - 5);
}
else if (moveD && moveL) {
sprite.setPosition(spritePos.x - 5, spritePos.y + 5);
}
else if (moveL) {
sprite.setPosition(spritePos.x - 5, spritePos.y);
}
else if (moveR) {
sprite.setPosition(spritePos.x + 5, spritePos.y);
}
else if (moveU) {
sprite.setPosition(spritePos.x, spritePos.y - 5);
}
else if (moveD) {
sprite.setPosition(spritePos.x, spritePos.y + 5);
}
break;
}
}
window.clear(Color(0,0,0,255));
window.draw(sprite);
window.display();
}
return 0;
}
In my project I am having trouble getting a simple switch statement to work for SDL input. Here is the example:
SDL_Event event;
SDL_PollEvent(&event);
if (event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_a: m_x -= 30;
break;
case SDLK_d: m_x += 30;
break;
case SDLK_w: m_y -= 30;
break;
case SDLK_s: m_y += 30;
break;
}
}
When I run this, first off it seems SDL_KEYDOWN isn't being recognized. Nor are my cases. So I switched the code to:
SDL_Event event;
SDL_PollEvent(&event);
if (event.type == 771)
{
switch (event.key.keysym.sym)
{
case SDLK_a: m_x -= 30;
break;
case SDLK_d: m_x += 30;
break;
case SDLK_w: m_y -= 30;
break;
case SDLK_s: m_y += 30;
break;
default: m_y += 1;
}
}
This causes the default case to run when I hold or press any key, so my object moves according to m_y += 1. If I remove the default case and try pressing w,a,s, or d, nothing happens. If i keep m_y += 1, but use SDL_KEYDOWN instead of 771, nothing happens. (I got the 771 code by printing the event.type whenever a key is being pressed).
You call SDL_PollEvent() only once, so it gives the event which occurred first which might not be SDL_KEYDOWN.
You must make a main loop to handle your events:
SDL_Event event;
bool quit=false;
while(!quit)
{
while(SDL_PollEvent(&event)
{
if(event.type==SDL_KEYDOWN)
{
....
}
else if(event.type==SDL_QUIT)
{
quit=true;
}
}
}
This loop takes care of the events which you don't care about(for e.g. MOUSEMOTION).
And you can also use switch with event.type if you are going to handle many different types of events.
I'm making a simple top down 2D shooter, where you move with WASD and shoot in the direction you're looking at with space. I can move and shoot just fine, but I can't do them both at the same time. For example if I'm shooting and start moving, my character will stop shooting until I release and press space again, and if I then start moving in another direction I have to release and press space again.
Here's my main method:
int main(int argc, char* args[])
{
if (!init())
{
log("Failed to initialize!\n");
}
else
{
log("Initialized SDL and SDL subsystems. \nLoading assets:\n");
if (!loadAssets())
{
printf("Failed to load assets!\n");
}
else
{
log("All assets loaded successfully.\n");
bool running = true;
SDL_Event e;
std::vector<Shot> shots;
LTimer shotTimer;
float cooldown = 250.0f;
float previousCooldown = 0.0f;
Player player;
log("Game running.\n");
shotTimer.start();
while (running)
{
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
log("SDL_QUIT event triggered.\n");
running = false;
}
else if (e.type == SDL_KEYDOWN)
{
switch (e.key.keysym.sym)
{
case SDLK_ESCAPE:
{
running = false;
break;
}
}
}
player.handleEvent(e);
if (SDL_GetTicks() - previousCooldown > cooldown)
{
previousCooldown = SDL_GetTicks();
shots = shoot(e, player, shots);
}
}
player.move();
for (int i = 0; i < shots.size(); i++)
{
shots[i].move();
}
/*if (shotTimer.getTicks() >= cooldown)
shotTimer.restart();*/
SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
SDL_RenderClear(renderer);
background.render(0, 0);
for (int i = 0; i < shots.size(); i++)
{
shots[i].render();
}
player.render();
SDL_RenderPresent(renderer);
}
}
}
close();
return 0;
}
Here's my shoot() function, which is probably what's causing this:
std::vector<Shot> shoot(SDL_Event& e, Player player, std::vector<Shot> shots)
{
bool shoot = false;
if (e.type = SDL_KEYDOWN && e.key.repeat == 1)
{
switch (e.key.keysym.sym)
{
case SDLK_SPACE:
{
shoot = true;
break;
}
}
}
else if (e.type = SDL_KEYUP && e.key.repeat == 1)
{
switch (e.key.keysym.sym)
{
case SDLK_SPACE:
{
shoot = false;
break;
}
}
}
if (shoot)
{
Shot newShot(player.getDir(), player);
shots.push_back(newShot);
}
return shots;
}
And this is how I move the player
void Player::handleEvent(SDL_Event& e)
{
if (e.type == SDL_KEYDOWN && e.key.repeat == 0)
{
switch (e.key.keysym.sym)
{
case SDLK_w: mVelY -= PLAYER_VEL; mDir = 0; break;
case SDLK_s: mVelY += PLAYER_VEL; mDir = 1; break;
case SDLK_d: mVelX += PLAYER_VEL; mDir = 2; break;
case SDLK_a: mVelX -= PLAYER_VEL; mDir = 3; break;
}
}
else if (e.type == SDL_KEYUP && e.key.repeat == 0)
{
switch (e.key.keysym.sym)
{
case SDLK_w: mVelY += PLAYER_VEL; break;
case SDLK_s: mVelY -= PLAYER_VEL; break;
case SDLK_d: mVelX -= PLAYER_VEL; break;
case SDLK_a: mVelX += PLAYER_VEL; break;
}
}
}
Separate your event polling from the rest of the game logic.
Poll all events once per frame in a separate function and store the state of the keystates into an array. Then, when you need the state, simply check the array.
You can also use SDL_GetKeyboardState to sample the surrent state of the keys, without having to handle the key events yourself.
no events work in my "game" if I test the actions themselves that should happen (like if I put the moving function into the loop itself or the firing function, it works perfectly), but no event works, closing the display, with esc or pressing X, any pressed key, nothing is seen.
I cannot find the mistake in my code, could anyone please help? The game loop is bellow and all of the main function is here : http://pastebin.ca/2468619
while(!done)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
std::cout << "EXITING MOFO";
done= true;
}
else if(ev.type == ALLEGRO_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_A:
keys[A] = true;
break;
case ALLEGRO_KEY_S:
keys[S] = true;
break;
case ALLEGRO_KEY_D:
keys[D] = true;
break;
case ALLEGRO_KEY_W:
keys[W] = true;
break;
case ALLEGRO_KEY_SPACE:
fireWeapon(0);
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = true;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = true;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = true;
break;
case ALLEGRO_KEY_ENTER:
std::cout << "FUCK";
fireWeapon(1);
break;
}
}
else if(ev.type == ALLEGRO_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_A:
keys[A] = false;
break;
case ALLEGRO_KEY_S:
keys[S] = false;
break;
case ALLEGRO_KEY_D:
keys[D] = false;
break;
case ALLEGRO_KEY_W:
keys[W] = false;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = false;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = false;
break;
case ALLEGRO_KEY_UP:
keys[UP] = false;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = false;
break;
}
}
else if(ev.type == ALLEGRO_EVENT_TIMER)
{
render = true;
moveTank();
updateBullet(0);
updateBullet(1);
}
if(render && al_is_event_queue_empty(event_queue))
{
render = false;
//al_set_target_bitmap(back);
//al_clear_to_color(al_map_rgb(0,0,0));
drawTank(0);
drawTank(1);
drawBullet(0);
drawBullet(1);
//setupDebris();
al_flip_display();
al_clear_to_color(al_map_rgb(0,0,0));
}
I watched the same tutorial.
You have to add
al_register_event_source(event_queue, al_get_display_event_source(display))
to main.
I've been following LazyFoo's tutorial for a while. But I haven't been able to get this to initialize a week a go. I went back to it recently, after error checking, I found it that the window initializes properly, but the images won't load. What is the reason for it?
#include "SDL/SDL.h"
#include <string>
//setting screen info
const int SCH=640;
const int SCW=480;
const int BBP=32;
const char* name = "TEHGAEM";
// sprite height and width
const int SPH=45;
const int SPW=45;
//initilize event
SDL_Event event;
//loading surfaces for screen, sprite, and temp sprite
SDL_Surface *screen=NULL;
SDL_Surface *sprite=NULL;
SDL_Surface *temp = NULL;
//making class for movable objects
class Player
{
private:
int x,y;
int xVel,yVel;
public:
Player();
void show();
void move();
void handle_input();
};
//initializing variables
Player::Player()
{
x=0;
y=0;
xVel=0;
yVel=0;
}
//intended to show player picture
void Player::show()
{
SDL_Rect pos;
pos.x=x;
pos.y=y;
SDL_BlitSurface(sprite, NULL, screen, &pos);
SDL_UpdateRects(screen, 1, &pos);
}
//setting input
void Player::handle_input()
{
if (event.type ==SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel -= SPH /2; break;
case SDLK_DOWN: yVel += SPH /2; break;
case SDLK_LEFT: xVel -=SPW /2; break;
case SDLK_RIGHT: xVel +=SPW /2; break;
}
}
if (event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: yVel += SPH /2; break;
case SDLK_DOWN: yVel -= SPH /2; break;
case SDLK_LEFT: xVel +=SPW /2; break;
case SDLK_RIGHT: xVel -=SPW /2; break;
}
}
}
void Player::move()
{
x=+xVel;
y=+yVel;
if (x >= SCW)
{
x-10;
}
if (y >= SCH)
{
y-10;
}
}
//initializing program
bool init()
{
if (SDL_Init(SDL_INIT_EVERYTHING)==-1)
{
return false;
}
screen = SDL_SetVideoMode(SCH,SCW,BBP, SDL_SWSURFACE);
if (screen == NULL)
{
return false;
}
SDL_WM_SetCaption(name, NULL);
return true;
}
//loading images
bool somethings()
{
temp = SDL_LoadBMP("sprite.bmp");
if (temp == NULL)
{
return false;
}
sprite = SDL_DisplayFormat (temp);
if (sprite ==NULL)
{
return false;
}
SDL_FreeSurface(temp);
return true;
}
//clean up function
void clean()
{
SDL_FreeSurface(sprite);
SDL_Quit();
}
int main(int argc, char* args[])
{
Player P1;
bool quit;
if (init() == false)
{
return 1;
}
if (somethings() ==false)
{
return 1;
}
while (quit ==false)
{
while (SDL_PollEvent(&event))
{
P1.handle_input();
if (event.type == SDL_QUIT)
{
quit == true;
}
}
if (SDL_Flip(screen) ==-1)
{
return 1;
}
P1.move();
P1.show();
}
clean();
return 0;
}
This isn't completely related to your problem but the varible bool quit; isn't defined as true or false before the main while( quit == false ) { ... }loop. This could produce undefined while loop behavior.
int main(int argc, char* args[])
{
Player P1;
bool quit = false; // CHANGE THIS AND SEE WHAT HAPPENS
if (init() == false)
{
return 1;
}
if (somethings() ==false)
{
return 1;
}
while (quit ==false)
{
while (SDL_PollEvent(&event))
{
P1.handle_input();
if (event.type == SDL_QUIT)
{
quit == true;
}
}
if (SDL_Flip(screen) ==-1)
{
return 1;
}
P1.move();
P1.show();
}
clean();
return 0;
}
About the images not loading, step through your program with a debugger and watch your somethings()function and follow the variables temp and sprite.
Make sure your "sprite.bmp" file is located in the running directory of this program. I tested it and it works for me.
Also this has no effect:
if (x >= SCW)
{
x-10;
}
if (y >= SCH)
{
y-10;
}
You probably wanted to say x -= 10; and y -= 10;.
This makes your 'player' jump back to the original position immediately:
if (event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: yVel += SPH /2; break;
case SDLK_DOWN: yVel -= SPH /2; break;
case SDLK_LEFT: xVel +=SPW /2; break;
case SDLK_RIGHT: xVel -=SPW /2; break;
}
}
You probably only need to handle SDL_KEYDOWN event.
Hope that helps.
There are big chances that you aren't loading the bitmap. But anything that you are trying to print on the screen and wasn't loaded can terminate the app.