Move an item in a scene Qt - c++

I try to move an item in a scene and for that, I use QKeypressEvent and moveBy that works both perfectly but I'd like to recover the "key press event", so I decided first, to use a boolean that returns true when the key is pressed and false when it's not, and then to create a new function where I call the moveBy if my boolean is true, but unfortunately is doesn't work.
This is what I've done in my file.cpp
Perso::Perso()
{
right= false;
left= false;
up= false;
down= false;
moveOnMap();
setFlag(QGraphicsItem::ItemIsFocusable);
}
void Perso::moveOnMap(){
if (left) {
moveBy(-10,0);
}
if (right) {
moveBy(10,0);
}
if (up) {
moveBy(0, -10);
}
if (down) {
moveBy(0, +10);
}
}
void Perso::keyPressEvent(QKeyEvent *event){
switch(event->key()){
case Qt::Key_Up:
up=true;
//moveBy(0, -10);
break;
case Qt::Key_Right:
right=true;
// moveBy(10,0);
break;
case Qt::Key_Left:
left=true;
//moveBy(-10,0);
break;
case Qt::Key_Down:
down= true;
//moveBy(0, 10);
break;
}
update();
}
void Perso::keyReleaseEvent(QKeyEvent *event){
switch(event->key()){
case Qt::Key_Up:
up=false;
break;
case Qt::Key_Right:
right= false;
break;
case Qt::Key_Left:
left= false;
break;
case Qt::Key_Down:
down= false;
break;
}
}
Anyone can help me to understand where I am wrong?

I can't see here that you call your moveOnMap(); If in your original code you don't call this method that it is normal that it is not work. You call it only in constructor but you should call this method every key pressing. So try to call this method in your key events:
void Perso::keyPressEvent(QKeyEvent *event){
switch(event->key()){
case Qt::Key_Up:
up=true;
//moveBy(0, -10);
break;
case Qt::Key_Right:
right=true;
// moveBy(10,0);
break;
case Qt::Key_Left:
left=true;
//moveBy(-10,0);
break;
case Qt::Key_Down:
down= true;
//moveBy(0, 10);
break;
}
moveOnMap();
update();
}
void Perso::keyReleaseEvent(QKeyEvent *event){
switch(event->key()){
case Qt::Key_Up:
up=false;
break;
case Qt::Key_Right:
right= false;
break;
case Qt::Key_Left:
left= false;
break;
case Qt::Key_Down:
down= false;
break;
}
moveOnMap();
}

Related

The better way to control player in 2d game ? (sdl2)

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.

How to stop linear rectangle movement from stuttering in sdl2

Here is the code for moving the rectangle while w is pressed
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT)
{
done = false;
}
if (e.type = SDL_KEYDOWN)
{
switch (e.key.keysym.sym)
{
case SDLK_w:
SDL_RenderFillRect(renderer, &player);
player.y -=SPEED;
draw();
break;
case SDLK_s:
SDL_RenderFillRect(renderer, &player);
player.y +=SPEED;
draw();
break;
default:
break;
}
}
}
everything works fine except when it runs it stutters. the rectangle moves by stuttering and it's very annoying

Taking 2 keyboard inputs with sfml

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;
}

Handling multiple keypressess at the same time in SDL

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.

allegro 5 no events work

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.