1
\$\begingroup\$

Okay so I'm writing a controller class to expand the SFML joystick library capabilities. Since the different controllers I want to use for this game have different integer values mapped to different buttons, I want to be able to pass integer values to the class to map these values to buttons I have defined. As well, SFML can detect whether a button is pressed with sf::Joystick::isButtonPressed(unsigned int joystick, unsigned int button). However, this only detects if a button is currently pressed and thus holding the button will just register as repeated presses. So I wrote my own code to detect for a button press without a hold.

So here's the issue: What is the proper way for the player (outside the class) to access the set of buttons without exposing data? I could have getters for the buttons, but then the buttonPressed method couldn't change the value of held. The only way I could see this working is if I gave full access to the Button's. Or should I go about this a different way? Any help would be greatly appreciated. Here's the relevant code:

// Controller.h

class Controller
{
public:
    struct Button
    {
        unsigned int id;
        bool held;
    };

    // constructor which assigns a controller ID
    // and a set of buttons
    Controller(...); 

    // Checks each frame for each button if 
    // any are not held and sets held to false
    void update();

    bool buttonPressed(Button& button);
private:
    unsigned int controllerId_;
    Button A_, B_, X_, Y_, Z_, R_, L_, 
    START_, D_PAD_UP_, D_PAD_LEFT_, D_PAD_DOWN_, D_PAD_RIGHT_;
};

// Controller.cpp

bool Controller::buttonPressed(Button& button)
{
    if (sf::Joystick::isButtonPressed(controllerId_, button.id) && !button.held)
    {
        button.held = true;
        return true;
    }
    else
    {
        return false;
    }
}
\$\endgroup\$
  • \$\begingroup\$ Do you know you can use the JoystickButtonPressed event to detect a button press? \$\endgroup\$ – Alayric Oct 2 '16 at 11:37
2
\$\begingroup\$

I think the way to go here is let the player access the "virtual" key names, and ask for their current state. You would introduce an enum or a set of constants that map your Button instances to names that can be accessed. Something like the following would do the job:

enum class ButtonName
{
    A, B, X, Y, Z, R, L, START, D_PAD_UP, D_PAD_DOWN, D_PAD_LEFT, D_PAD_RIGHT
};

Now, instead of named members, your Controller class should store a map (or an array, if the enum values are continuous) that maps the button names to their Button representations. So replace your members with std::map<ButtonName, Button> buttonMappings;. Now, for initialization, you can either provide an utility method Controller::MapKey(ButtonName, unsigned int buttonID);, or perhaps just pass in an std::map to the constructor of the Controller instance.

Now, the part where the player accesses becomes really nice to the code that needs to check for controller button presses. You can simply call if (controller.IsButtonPressed(ButtonName::D_PAD_UP)) { ... }. The implementation for IsButtonPressed then simply looks up the Button value for the correct name. So something like the following:

bool Controller::IsButtonPressed(ButtonName name)
{
    Button& button = buttonMappings.at(name);

    if (sf::Joystick::isButtonPressed(controllerId_, button.id) && !button.held)
    {
        button.held = true;
        return true;
    }
    else
    {
        return false;
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.