The other day I sat down and thought about the buttons API and I’ve come up with a few ideas for improving it.
Firstly, I think it would be good to scrap all the aBtn()
/aHeld()
/aReleased()
functions.
There’s a lot of them and I honestly think they muddy the waters and confuse the API rather than being useful.
(If they are still needed they could be included on a different class that acts as an adaptor.)
For the main API, I have two suggestions that differ mainly in wording.
Option 1:
class Buttons
{
public:
// Manually called to update the button state.
// Typically called once per frame/once per logic update.
void update(void);
// True if the button has just been pressed
// (i.e. true for one update only)
bool isPressed(Button button);
// True if the button has just been released
// (i.e. true for one update only)
bool isReleased(Button button);
// True if the button is currently pressed.
// (i.e. true for multiple updates)
bool isHeld(Button button);
// True if the button is currently released.
// (i.e. true for multiple updates)
// Equivalent to !isHeld(button)
bool isNotHeld(Button button);
};
Option2:
class Buttons
{
public:
// Manually called to update the button state.
// Typically called once per frame/once per logic update.
void update(void);
// True if the button is currently pressed.
// (i.e. true for multiple updates)
bool isPressed(Button button);
// True if the button is currently released.
// (i.e. true for multiple updates)
// Equivalent to !isPressed(button)
bool isReleased(Button button);
// True if the button has just been pressed
// (i.e. true for one update only)
bool justPressed(Button button);
// True if the button has just been released
// (i.e. true for one update only)
bool justReleased(Button button);
};
The timing aspect would still exist, but I think it should be an optional extra because most games can function on the minimal API.
I’m not sure if the timed API should be an adaptor class or a part of the main buttons class that can be enabled, but I’ll present it as an adaptor for now.
class ButtonTiming
{
public:
// True if the button is has been held for the given number of updates.
// Is true once and won't be true again until the button is released.
bool isHeldOnce(Button button, uint16_t numberOfUpdates);
// True if the button is has been held for the given number of updates.
// Can be true multiple times until the button is released.
bool isHeldRepeat(Button button, uint16_t numberOfUpdates);
// Returns the number of updates that the button has been held for.
uint16_t updatesHeld(Button button);
};
It may also be possible to develop an API that uses actual time instead of the number of updates.
I chose to use the terminology ‘number of updates’ rather than ‘number of frames’ because it’s entirely possible that update
might be called more than once per frame.
As an extra thing, it might be a good idea to provide a pure virtual button class based on these interfaces with a concrete implementation handling the buttons.
Then if people want to attempt multiplayer games (e.g. through use of a bluetooth/wifi/serial hat) they could create an alternate implementation that would have the wired/wireless multiplayer link as its back-end.
This would allow the programmer to program their game objects to respond to a single interface but automatically allow them to respond to both real button presses and to input from a wired/wireless link.
Liskov substitution in action.
This might be better to have in a different library though, if the main library’s aim is to be kept small and simple.