SFML community forums

Help => General => Topic started by: valenciano on May 12, 2018, 05:28:39 pm

Title: Handle multiple pressed Keys in a switch statement
Post by: valenciano on May 12, 2018, 05:28:39 pm
Hello !

I'd like to design a little game in which, a little ship (a Triangle) would move on the screen.
The problem is that I'd like to make the ship rotate when multiple keys are pressed (see below).

But the compiler refuses :

make all (in directory: /home//Desktop/C++)
g++ -c main.cpp Game.cpp Ship.cpp
Game.cpp: In member function ‘void Game::run()’:
Game.cpp:56:6: error: duplicate case value
      case((sf::Keyboard::Down) && (sf::Keyboard::Right)):
      ^~~~
Game.cpp:53:6: note: previously used here
      case((sf::Keyboard::Up) && (sf::Keyboard::Left)):
      ^~~~
Makefile:8: recipe for target 'all' failed
make: *** [all] Error 1
Compilation failed.
 

void Game::run()
{
        window.create(sf::VideoMode(800,600), "Test", sf::Style::Default);
                window.setVerticalSyncEnabled(true);
       
        std::unique_ptr<Ship> player = std::make_unique<Ship>(10,10,40);
       
        while(window.isOpen() == true)
        {
                sf::Event ev;
               
                while(window.pollEvent(ev) == true)
                {
                        if(ev.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                        if(ev.type == sf::Event::KeyPressed)
                        {
                                switch(ev.key.code)
                                {
                                        case(sf::Keyboard::Escape):
                                                window.close();
                                                break;
                                        case(sf::Keyboard::Up):
                                                player->move_y(-10);
                                                break;
                                        case(sf::Keyboard::Down):
                                                player->move_y(10);
                                                break;
                                        case(sf::Keyboard::Left):
                                                player->move_x(-10);
                                                break;
                                        case(sf::Keyboard::Right):
                                                player->move_x(10);
                                                break;
                                        case((sf::Keyboard::Up) && (sf::Keyboard::Left)):
                                                player->rotate(10);
                                                break;
                                        case((sf::Keyboard::Down) && (sf::Keyboard::Right)):
                                                player->rotate(-10);
                                                break;
                                        default:
                                                break;
                                }
                        }
                }
               
                window.clear(sf::Color::Black);
                player->drawOn(&window);
                window.display();
        }
}

Regards
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: Laurent on May 12, 2018, 09:15:54 pm
A 'case' in a 'switch' is not an expression, it must be a single compile-time integral constant.

The syntax to execute the same code for multiple constants is:
case sf::Keyboard::Up:
case sf::Keyboard::Left:
   ...
   break;

But since you already have different code for these constants alone, this won't work as you can't have the same constant multiple times in the same 'switch'. So maybe a sequence of 'if'/'else if' is better in this case.
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: valenciano on May 12, 2018, 10:46:00 pm
Thanks for your answer Laurent,

I changed my code but there is no rotations when I simultaneously press Up and Left for example.

sf::Event ev;
               
                while(window.pollEvent(ev) == true)
                {
                        if(ev.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                        if(ev.type == sf::Event::KeyPressed)
                        {
                               
                                switch(ev.key.code)
                                {
                                        case(sf::Keyboard::Escape):
                                                window.close();
                                                break;
                                        case(sf::Keyboard::Up):
                                                player->move_y(-10);
                                                break;
                                        case(sf::Keyboard::Down):
                                                player->move_y(10);
                                                break;
                                        case(sf::Keyboard::Left):
                                                player->rotate(10);
                                                break;
                                        case(sf::Keyboard::Right):
                                                player->move_x(10);
                                                break;
                                }
                                if((ev.key.code == sf::Keyboard::Up) && (ev.key.code == sf::Keyboard::Left))
                                {
                                                player->rotate(10);
                                }
                                if((ev.key.code == sf::Keyboard::Down) && (ev.key.code == sf::Keyboard::Right))
                                {
                                                player->rotate(10);
                                }
                        }
                }
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: Laurent on May 13, 2018, 08:50:58 am
How do you expect a single variable to be equal to 2 different values at the same time? ::)

This logic cannot be tested in the event loop, you should rather use real-time keyboard state (see sf::Keyboard) outside the event loop.
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: valenciano on May 13, 2018, 03:52:10 pm
Ahah yeah you are right !

I reviewed my code, here are the changes :

#include <iostream>
#include <SFML/Graphics.hpp>
#include <memory>
#include "Game.hpp"
#include "Ship.hpp"

Game::Game()
{
        std::cout << "Object created : Game" << std::endl;
}

Game::~Game()
{
        std::cout << "Object destroyed : Game" << std::endl;
}

void Game::run()
{
        window.create(sf::VideoMode(800,600), "Test", sf::Style::Default);
                window.setVerticalSyncEnabled(true);
       
        std::unique_ptr<Ship> player = std::make_unique<Ship>(10,10,40);
       
        while(window.isOpen() == true)
        {
                sf::Event ev;
               
                while(window.pollEvent(ev) == true)
                {
                        if(ev.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                        if(ev.type == sf::Event::KeyPressed)
                        {
                                //Escape
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                                {
                                        window.close();
                                }
                                //Left + !(Up && Down)
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) == false)
                                {
                                                player->move_x(-10);
                                }
                                //Left + (Up && Down)
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) == true)
                                {
                                                player->rotate(10);
                                }
                                //Right + !(Up && Down)
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) == false)
                                {
                                                player->move_x(10);
                                }
                                //Right + (Up && Down)
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) == true )
                                {
                                                player->rotate(10);
                                }
                                //Down + !(Left && Right)
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) == false)
                                {
                                                player->move_y(10);
                                }
                                //Up + !(Left && Right)
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) == false )
                                {
                                                player->move_y(-10);
                                }
                               
                        }
                }
               
                window.clear(sf::Color::Black);
                player->drawOn(&window);
                window.display();
        }
}
 

Now it works, but the idea would be to to rotations and not to move on the left or the right. How can I do it ?
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: Laurent on May 13, 2018, 06:14:53 pm
As I said, you should do it outside the event loop.

Quote
Now it works, but the idea would be to to rotations and not to move on the left or the right. How can I do it ?
That's what the 'else' keyword is for ;)

You should really take the time to think about it and rewrite your code correctly. I think you're lost in your conditions, because to me they don't make sense (and the implementation doesn't even match the comments).
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: valenciano on May 14, 2018, 01:21:17 am
Great this time it works for good !

//Left : If Left Key is pressed
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
        //Left rotation: If Left + Either Down or Up are pressed
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up)))
        {
                player->rotate(10);
        }
        else
        {
                player->move_x(-10);
        }
}

//Right : If Right Key is pressed
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
        //Right rotation : If Right + Either Down or Up are pressed
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up)))
        {
                player->rotate(-10);
        }
        else
        {
                player->move_x(10);
        }
}

//Up : If only Up Key is pressed
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) == false && sf::Keyboard::isKeyPressed(sf::Keyboard::Right) == false))
{
        player->move_y(-10);
}

//Down : If only Down Key is pressed
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) == false && sf::Keyboard::isKeyPressed(sf::Keyboard::Right) == false))
{
        player->move_y(10);
}

How can I make the game smoother ? Because it doesn't feel that smooth when I play with the ship : I'd like to move the ship with just the key pressed one time without that repeated effect (kind of delay between movements)
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: Laurent on May 14, 2018, 06:36:53 am
No, I won't say it a 3rd time. Please read my previous replies carefully.
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: valenciano on May 14, 2018, 02:17:35 pm
"Outside the event loop" -> Got it !  ;)

void Game::run()
{
        window.create(sf::VideoMode(800,600), "Test", sf::Style::Default);
                window.setVerticalSyncEnabled(true);
               
        sf::SoundBuffer buffer;
       
        if(!buffer.loadFromFile("ship.ogg"))
        {
                std::cerr << "Failed to load ship sound" << std::endl;
        }
        else
        {
                std::unique_ptr<Ship> player = std::make_unique<Ship>(10,10,40);
               
                sf::Sound ship_sound;
                        ship_sound.setBuffer(buffer);
       
                while(window.isOpen() == true)
                {
                        sf::Event ev;
                       
                        while(window.pollEvent(ev) == true)
                        {
                                if(ev.type == sf::Event::Closed)
                                {
                                        window.close();
                                }
                                if(ev.type == sf::Event::KeyPressed)
                                {
                                        if(ev.key.code == sf::Keyboard::Escape)
                                        {
                                                window.close();
                                        }
                                }
                        }
                       
                        //Left : If only Left Key is pressed
                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                        {
                                //Left rotation: If Left + Either Down or Up are pressed
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up)))
                                {
                                        player->rotate(10);
                                }
                                else
                                {
                                        player->move_x(-10);
                                }
                        }
                       
                        //Right : If only Right Key is pressed
                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                        {
                                //Right rotation : If Right + Either Down or Up are pressed
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up)))
                                {
                                        player->rotate(-10);
                                }
                                else
                                {
                                        player->move_x(10);
                                }
                        }

                        //Up : If only Up Key is pressed
                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) == false && sf::Keyboard::isKeyPressed(sf::Keyboard::Right) == false))
                        {
                                player->move_y(-10);
                        }
                       
                        //Down : If only Down Key is pressed
                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) == false && sf::Keyboard::isKeyPressed(sf::Keyboard::Right) == false))
                        {
                                player->move_y(10);
                        }
                       
                        window.clear(sf::Color::Black);
                        player->drawOn(&window);
                        window.display();
                }
        }
}

It's smooth now !
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: Tigre Pablito on May 16, 2018, 03:52:06 pm
                        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                        {
                                //Left rotation: If Left + Either Down or Up are pressed
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up)))
                                {
                                        player->rotate(10);
                                }
                                else
                                {
                                        player->move_x(-10);
                                }
                        }

The first 'if' is not necesary because you check if Left is pressed in the 2nd one  ;) . Same with the check of the Right key
Title: Re: Handle multiple pressed Keys in a switch statement
Post by: Laurent on May 16, 2018, 04:57:47 pm
Quote
The first 'if' is not necesary because you check if Left is pressed in the 2nd one
Wrong. If you remove the first 'if', then the 'else' will execute in different conditions.