Search code examples
c++commandsfmlnull-pointer

How do I correctly bind keys using the command pattern?


I've been working on a game using c++ and sfml and I've been trying to implement the command pattern as seen in the link below: https://gameprogrammingpatterns.com/command.html. More specifically, I am trying to implement the command pattern so that it can be used for any character in the scene.

I've set up a general command class:

class Command
{
public:
    ~Command();
    virtual void execute(Character& character) = 0;

};

And then a bunch of classes that inherit from this class, for example:

#include "Command.h"

class WalkDownCommand : public Command
{
public:
    virtual void execute(Character& character) override
    {
        character.walkDown();
    }
};

Then I created a character class that contains all the functions for walking, and a shape to represent it's body:



#include <SFML\Graphics.hpp>


class Character {

public:
    Character();
    ~Character();

    void draw(sf::RenderWindow* renderWindow);
    void walkRight();
    void walkLeft();
    void walkUp();
    void walkDown();
private:
    sf::CircleShape* tempShape;

};

These functions are then called using their respective command Class. I've also created a HandleInput function that checks whether a key is pressed and returns a reference to a specific command object:

#include "Command.h"

class InputHandler
{
public:

    Command* handleInput();
    
private:
    Command* W_KEY;
    Command* A_KEY;
    Command* S_KEY;
    Command* D_KEY;

};

The handleInput function looks as follows:

Command* InputHandler::handleInput()
{
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
    {
        std::cout << "W key is pressed" << std::endl;
        return W_KEY;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
    {
        std::cout << " A key is pressed" << std::endl;
        return A_KEY;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
    {
        std::cout << "S key is pressed" << std::endl;
        return S_KEY;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
    {
        std::cout << "D key is pressed" << std::endl;
        return D_KEY;
    }

    return NULL;
    
}

In the games main loop, I created a Command pointer object that calls the handleInput function to check for input. If it finds a command, it executes this command ('gloon' is the object of type Character):

Command* command = inputHandler.handleInput();
        if (command)
        {
            command->execute(gloon);
        }

When running this, the handleInput function gets correctly called and then returns one of the pressed keys. However, the program crashes right after, stating: Exception thrown: read access violation. command was 0xFFFFFFFFFFFFFFFF.

In the link I showed of the beginning of the page, the command pattern description also states that I need to bind the Command* objects to the correct function. This might be what is causing the issue, but I'm having trouble to understand how to do this. Any help is appreciated!


Solution

  • Maybe, try something like this (to initialize pointers in your class InputHandler):

        #include "Command.h"
        
        class InputHandler
        {
        public:
            InputHandler()
            { 
                W_KEY = new WalkUpCommand; 
                A_KEY = new WalkLeftCommand; 
                D_KEY = new WalkRightCommand; 
                S_KEY = new WalkDownCommand;
            }
            ~InputHandler() 
            {
                delete W_KEY;
                delete A_KEY;
                delete S_KEY;
                delete D_KEY;
            }
            Command* handleInput();
            
        private:
            Command* W_KEY;
            Command* A_KEY;
            Command* S_KEY;
            Command* D_KEY;
        
        };
    

    I'm not sure, but hope it will be helpful