mirror of
https://github.com/NoelFB/blah.git
synced 2025-06-29 19:25:26 +08:00
new input binding/mapping implementation
This commit is contained in:
@ -28,9 +28,8 @@
|
||||
#include "blah/images/packer.h"
|
||||
|
||||
#include "blah/input/input.h"
|
||||
#include "blah/input/virtual_stick.h"
|
||||
#include "blah/input/virtual_button.h"
|
||||
#include "blah/input/virtual_axis.h"
|
||||
#include "blah/input/binding.h"
|
||||
#include "blah/input/binding_registry.h"
|
||||
|
||||
#include "blah/math/calc.h"
|
||||
#include "blah/math/circle.h"
|
||||
|
261
include/blah/input/binding.h
Normal file
261
include/blah/input/binding.h
Normal file
@ -0,0 +1,261 @@
|
||||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
#include <blah/containers/stackvector.h>
|
||||
#include <blah/math/point.h>
|
||||
#include <blah/math/vec2.h>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
// Represents a Controller Trigger or a single direction of a Controller Axis.
|
||||
// Used in the Binding implementation.
|
||||
struct BoundTrigger
|
||||
{
|
||||
// Controller Index we're bound to
|
||||
int controller = 0;
|
||||
|
||||
// The Axis we're bound to
|
||||
Axis axis = Axis::None;
|
||||
|
||||
// Minimum value of the axis
|
||||
float threshold = 0.01f;
|
||||
|
||||
// requires a positive value
|
||||
// otherwise requires a negative value
|
||||
bool positive = true;
|
||||
|
||||
BoundTrigger() = default;
|
||||
BoundTrigger(Axis axis);
|
||||
BoundTrigger(int controller, Axis axis, float threshold, bool positive);
|
||||
|
||||
bool is_down(float axis_value) const;
|
||||
|
||||
// helper functions for frequent use cases
|
||||
static BoundTrigger left_stick_left(int controller, float threshold);
|
||||
static BoundTrigger left_stick_right(int controller, float threshold);
|
||||
static BoundTrigger left_stick_up(int controller, float threshold);
|
||||
static BoundTrigger left_stick_down(int controller, float threshold);
|
||||
static BoundTrigger right_stick_left(int controller, float threshold);
|
||||
static BoundTrigger right_stick_right(int controller, float threshold);
|
||||
static BoundTrigger right_stick_up(int controller, float threshold);
|
||||
static BoundTrigger right_stick_down(int controller, float threshold);
|
||||
static BoundTrigger left_trigger(int controller, float threshold);
|
||||
static BoundTrigger right_trigger(int controller, float threshold);
|
||||
};
|
||||
|
||||
struct BoundButton
|
||||
{
|
||||
// Controller Index we're bound to
|
||||
int controller = 0;
|
||||
|
||||
// Button we're bound to
|
||||
Button button = Button::None;
|
||||
|
||||
BoundButton() = default;
|
||||
BoundButton(Button button);
|
||||
BoundButton(int controller, Button button);
|
||||
};
|
||||
|
||||
// Single input Binding
|
||||
class Binding
|
||||
{
|
||||
public:
|
||||
|
||||
// Input Buffer for press events
|
||||
float press_buffer = 0;
|
||||
|
||||
// Input Buffer for release events
|
||||
float release_buffer = 0;
|
||||
|
||||
// List of bound Keys
|
||||
StackVector<Key, 16> keys;
|
||||
|
||||
// List of bound Buttons
|
||||
StackVector<BoundButton, 16> buttons;
|
||||
|
||||
// List of bound Triggers / Axis
|
||||
StackVector<BoundTrigger, 16> triggers;
|
||||
|
||||
// List of bound Mouse buttons
|
||||
StackVector<MouseButton, 16> mouse;
|
||||
|
||||
// if the binding has been pressed
|
||||
bool pressed() const;
|
||||
|
||||
// if the binding has been released
|
||||
bool released() const;
|
||||
|
||||
// if the binding is currently held
|
||||
bool down() const;
|
||||
|
||||
// returns the binding's value from 0-1
|
||||
float value() const;
|
||||
|
||||
// returns the bindings signed value (0 or 1)
|
||||
int sign() const;
|
||||
|
||||
// returns the timestamp of the last time the binding was pressed
|
||||
double timestamp() const;
|
||||
|
||||
// updates the binding state
|
||||
void update();
|
||||
|
||||
// consumes the current press, and pressed() will return false until the next press
|
||||
void consume_press();
|
||||
|
||||
// consumes the current release, and released() will return false until the next release
|
||||
void consume_release();
|
||||
|
||||
// adds a key to the binding
|
||||
void add(Key key);
|
||||
|
||||
// adds a button to the binding
|
||||
void add(BoundButton button);
|
||||
|
||||
// adds an trigger to the binding
|
||||
void add(BoundTrigger trigger);
|
||||
|
||||
// adds a mouse button to the binding
|
||||
void add(MouseButton mouse);
|
||||
|
||||
// adds an input to the binding
|
||||
template<typename T, typename T2, typename ... Args>
|
||||
void add(T first, T2 second, const Args&... args)
|
||||
{
|
||||
add(first);
|
||||
add(second, args...);
|
||||
}
|
||||
|
||||
// assigns all the bindings to the specific controller
|
||||
void set_controller(int index);
|
||||
|
||||
// removes all bindings
|
||||
void clear();
|
||||
|
||||
private:
|
||||
double m_last_timestamp = 0;
|
||||
double m_last_press_time = -1;
|
||||
double m_last_release_time = -1;
|
||||
float m_value = 0.0f;
|
||||
bool m_pressed = false;
|
||||
bool m_released = false;
|
||||
bool m_down = false;
|
||||
bool m_press_consumed = false;
|
||||
bool m_release_consumed = false;
|
||||
|
||||
bool get_pressed() const;
|
||||
bool get_released() const;
|
||||
bool get_down() const;
|
||||
float get_value() const;
|
||||
};
|
||||
|
||||
// Represents a Bound Axis (ex. Left/Right movement, or a Trigger)
|
||||
class AxisBinding
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Overlap
|
||||
{
|
||||
Newer,
|
||||
Older,
|
||||
Cancel
|
||||
};
|
||||
|
||||
// Negative Value Binding
|
||||
Binding negative;
|
||||
|
||||
// Positive Value Binding
|
||||
Binding positive;
|
||||
|
||||
// How to handle overlaps (ex. Left and Right are both held)
|
||||
Overlap overlap = Overlap::Newer;
|
||||
|
||||
// Current Value from -1 to 1
|
||||
float value() const;
|
||||
|
||||
// Current value, either -1, 0, or 1
|
||||
int sign() const;
|
||||
|
||||
// updates the Binding
|
||||
void update();
|
||||
|
||||
// consumes the press buffer
|
||||
void consume_press();
|
||||
|
||||
// consumes the release buffer
|
||||
void consume_release();
|
||||
|
||||
// Adds a negative & positive binding pair
|
||||
template<typename NegativeT, typename PositiveT>
|
||||
void add(NegativeT negative, PositiveT positive)
|
||||
{
|
||||
this->negative.add(negative);
|
||||
this->positive.add(positive);
|
||||
}
|
||||
|
||||
// Adds a Stick binding
|
||||
void add_left_stick_x(int controller, float threshold);
|
||||
void add_left_stick_y(int controller, float threshold);
|
||||
void add_right_stick_x(int controller, float threshold);
|
||||
void add_right_stick_y(int controller, float threshold);
|
||||
|
||||
// assigns all the bindings to the specific controller
|
||||
void set_controller(int index);
|
||||
|
||||
// Clears all Bindings
|
||||
void clear();
|
||||
};
|
||||
|
||||
class StickBinding
|
||||
{
|
||||
public:
|
||||
|
||||
// An optional threshold for circular thresholds
|
||||
float round_threshold = 0.0f;
|
||||
|
||||
// X Axis Binding
|
||||
AxisBinding x;
|
||||
|
||||
// Y Axis Binding
|
||||
AxisBinding y;
|
||||
|
||||
// Current Value, -1 to 1
|
||||
Vec2 value() const;
|
||||
|
||||
// Current value, either -1, 0, or 1
|
||||
Point sign() const;
|
||||
|
||||
// Updates the Binding
|
||||
void update();
|
||||
|
||||
// Consumes the Press Buffer
|
||||
void consume_press();
|
||||
|
||||
// Consumes the Release Buffer
|
||||
void consume_release();
|
||||
|
||||
// Adds directional bindings
|
||||
template<typename LeftT, typename RightT, typename UpT, typename DownT>
|
||||
void add(LeftT left, RightT right, UpT up, DownT down)
|
||||
{
|
||||
x.negative.add(left);
|
||||
x.positive.add(right);
|
||||
y.negative.add(up);
|
||||
y.positive.add(down);
|
||||
}
|
||||
|
||||
// Adds the dpad binding
|
||||
void add_dpad(int controller);
|
||||
|
||||
// Adds the left stick binding
|
||||
void add_left_stick(int controller, float threshold);
|
||||
|
||||
// Adds the right stick binding
|
||||
void add_right_stick(int controller, float threshold);
|
||||
|
||||
// assigns all the bindings to the specific controller
|
||||
void set_controller(int index);
|
||||
|
||||
// Clears all the bindings
|
||||
void clear();
|
||||
};
|
||||
}
|
37
include/blah/input/binding_registry.h
Normal file
37
include/blah/input/binding_registry.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <blah/input/binding.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <memory>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
using BindingRef = std::shared_ptr<Binding>;
|
||||
using AxisBindingRef = std::shared_ptr<AxisBinding>;
|
||||
using StickBindingRef = std::shared_ptr<StickBinding>;
|
||||
|
||||
// Optional registry to automatically update bindings.
|
||||
// You can register different types of bindings here and until they are
|
||||
// no longer used, they will be updated without having to explicitely call
|
||||
// their update methods
|
||||
class BindingRegistry
|
||||
{
|
||||
public:
|
||||
// registers a new binding
|
||||
static BindingRef register_binding();
|
||||
|
||||
// registers a new axis binding
|
||||
static AxisBindingRef register_axis();
|
||||
|
||||
// registers a new stick binding
|
||||
static StickBindingRef register_stick();
|
||||
|
||||
// updates all the bindings. This is called
|
||||
// automatically by the App loop.
|
||||
static void update();
|
||||
|
||||
private:
|
||||
static Vector<std::weak_ptr<Binding>> bindings;
|
||||
static Vector<std::weak_ptr<AxisBinding>> axes;
|
||||
static Vector<std::weak_ptr<StickBinding>> sticks;
|
||||
};
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
// A virtual controller axis, which can be used to map multiple
|
||||
// inputs to an axis. Note that you must call `update` every frame!
|
||||
class VirtualAxis
|
||||
{
|
||||
private:
|
||||
struct KeysNode
|
||||
{
|
||||
Key positive = Key::Unknown;
|
||||
Key negative = Key::Unknown;
|
||||
|
||||
int value = 0;
|
||||
|
||||
void init(Key negative, Key positive);
|
||||
void update();
|
||||
};
|
||||
|
||||
struct ButtonsNode
|
||||
{
|
||||
int gamepad_id = 0;
|
||||
Button positive = Button::None;
|
||||
Button negative = Button::None;
|
||||
|
||||
int value = 0;
|
||||
|
||||
void init(int gamepad_id, Button negative, Button positive);
|
||||
void update();
|
||||
};
|
||||
|
||||
struct AxisNode
|
||||
{
|
||||
int gamepad_id = 0;
|
||||
Axis axis = Axis::None;
|
||||
float deadzone = 0;
|
||||
|
||||
float value = 0;
|
||||
|
||||
void init(int gamepad_id, Axis axis, float deadzone);
|
||||
void update();
|
||||
};
|
||||
|
||||
KeysNode m_keys[Input::max_virtual_nodes];
|
||||
ButtonsNode m_buttons[Input::max_virtual_nodes];
|
||||
AxisNode m_axes[Input::max_virtual_nodes];
|
||||
int m_keys_len = 0;
|
||||
int m_buttons_len = 0;
|
||||
int m_axes_len = 0;
|
||||
|
||||
float m_press_buffer = 0;
|
||||
float m_release_buffer = 0;
|
||||
float m_repeat_delay = 0;
|
||||
float m_repeat_interval = 0;
|
||||
|
||||
float m_value = 0;
|
||||
int m_value_i = 0;
|
||||
float m_last_value = 0;
|
||||
int m_last_value_i = 0;
|
||||
bool m_pressed = false;
|
||||
bool m_released = false;
|
||||
double m_last_press_time = -1;
|
||||
double m_last_release_time = -1;
|
||||
double m_repeat_press_time = -1;
|
||||
|
||||
public:
|
||||
VirtualAxis& add_keys(Key negative, Key positive);
|
||||
VirtualAxis& add_buttons(int gamepad_id, Button negative, Button positive);
|
||||
VirtualAxis& add_axis(int gamepad_id, Axis axis, float deadzone);
|
||||
VirtualAxis& repeat(float m_repeat_delay, float m_repeat_interval);
|
||||
VirtualAxis& press_buffer(float duration);
|
||||
VirtualAxis& release_buffer(float duration);
|
||||
|
||||
void update();
|
||||
float value() const { return m_value; }
|
||||
int value_i() const { return m_value_i; }
|
||||
float last_value() const { return m_last_value; }
|
||||
int last_value_i() const { return m_last_value_i; }
|
||||
bool pressed() const { return m_pressed; }
|
||||
bool released() const { return m_released; }
|
||||
void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; }
|
||||
void clear_release_buffer() { m_last_release_time = -1; m_released = false; }
|
||||
};
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
class VirtualButton
|
||||
{
|
||||
private:
|
||||
struct KeyNode
|
||||
{
|
||||
Key key = Key::Unknown;
|
||||
|
||||
bool down = false;
|
||||
bool pressed = false;
|
||||
bool released = false;
|
||||
|
||||
void init(Key key);
|
||||
void update();
|
||||
};
|
||||
|
||||
struct ButtonNode
|
||||
{
|
||||
int gamepad_id = 0;
|
||||
Button button = Button::None;
|
||||
|
||||
bool down = false;
|
||||
bool pressed = false;
|
||||
bool released = false;
|
||||
|
||||
void init(int gamepad_id, Button button);
|
||||
void update();
|
||||
};
|
||||
|
||||
struct AxisNode
|
||||
{
|
||||
int gamepad_id = 0;
|
||||
Axis axis = Axis::None;
|
||||
float threshold = 0;
|
||||
bool greater_than = false;
|
||||
|
||||
bool down = false;
|
||||
bool pressed = false;
|
||||
bool released = false;
|
||||
|
||||
void init(int gamepad_id, Axis axis, float threshold, bool greater_than);
|
||||
void update();
|
||||
};
|
||||
|
||||
KeyNode m_keys[Input::max_virtual_nodes];
|
||||
ButtonNode m_buttons[Input::max_virtual_nodes];
|
||||
AxisNode m_axes[Input::max_virtual_nodes];
|
||||
int m_keys_len = 0;
|
||||
int m_buttons_len = 0;
|
||||
int m_axes_len = 0;
|
||||
|
||||
float m_press_buffer = 0;
|
||||
float m_release_buffer = 0;
|
||||
float m_repeat_delay = 0;
|
||||
float m_repeat_interval = 0;
|
||||
|
||||
bool m_down = false;
|
||||
bool m_pressed = false;
|
||||
bool m_released = false;
|
||||
double m_last_press_time = -1;
|
||||
double m_last_release_time = -1;
|
||||
double m_repeat_press_time = -1;
|
||||
|
||||
public:
|
||||
VirtualButton& add_key(Key key);
|
||||
VirtualButton& add_button(int gamepad_id, Button button);
|
||||
VirtualButton& add_axis(int gamepad_id, Axis axis, float threshold, bool greater_than);
|
||||
VirtualButton& repeat(float m_repeat_delay, float m_repeat_interval);
|
||||
VirtualButton& press_buffer(float duration);
|
||||
VirtualButton& release_buffer(float duration);
|
||||
|
||||
void update();
|
||||
bool down() const { return m_down; }
|
||||
bool pressed() const { return m_pressed; }
|
||||
bool released() const { return m_released; }
|
||||
void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; }
|
||||
void clear_release_buffer() { m_last_release_time = -1; m_released = false; }
|
||||
};
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
#include <blah/math/vec2.h>
|
||||
#include <blah/math/point.h>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
// A virtual controller stick, which can be used to map multiple
|
||||
// inputs to a stick. Note that you must call `update` every frame!
|
||||
class VirtualStick
|
||||
{
|
||||
private:
|
||||
struct KeysNode
|
||||
{
|
||||
Key left;
|
||||
Key right;
|
||||
Key up;
|
||||
Key down;
|
||||
|
||||
Point value;
|
||||
|
||||
void init(Key left, Key right, Key up, Key down);
|
||||
void update();
|
||||
};
|
||||
|
||||
struct ButtonsNode
|
||||
{
|
||||
int gamepad_id;
|
||||
Button left;
|
||||
Button right;
|
||||
Button up;
|
||||
Button down;
|
||||
|
||||
Point value;
|
||||
|
||||
void init(int gamepad_id, Button left, Button right, Button up, Button down);
|
||||
void update();
|
||||
};
|
||||
|
||||
struct AxesNode
|
||||
{
|
||||
int gamepad_id;
|
||||
Axis horizontal;
|
||||
Axis vertical;
|
||||
float deadzone;
|
||||
|
||||
Vec2 value;
|
||||
|
||||
void init(int gamepad_id, Axis horizontal, Axis vertical, float deadzone);
|
||||
void update();
|
||||
};
|
||||
|
||||
KeysNode m_keys[Input::max_virtual_nodes];
|
||||
ButtonsNode m_buttons[Input::max_virtual_nodes];
|
||||
AxesNode m_axes[Input::max_virtual_nodes];
|
||||
int m_keys_len = 0;
|
||||
int m_buttons_len = 0;
|
||||
int m_axes_len = 0;
|
||||
|
||||
float m_press_buffer = 0;
|
||||
float m_release_buffer = 0;
|
||||
float m_repeat_delay = 0;
|
||||
float m_repeat_interval = 0;
|
||||
|
||||
Vec2 m_value = Vec2();
|
||||
Point m_value_i = Point();
|
||||
Vec2 m_last_value = Vec2();
|
||||
Point m_last_value_i = Point();
|
||||
bool m_pressed = false;
|
||||
bool m_released = false;
|
||||
|
||||
float m_i_deadzone;
|
||||
double m_last_press_time = -1;
|
||||
double m_last_release_time = -1;
|
||||
double m_repeat_press_time = -1;
|
||||
|
||||
public:
|
||||
VirtualStick();
|
||||
VirtualStick(float iDeadzone);
|
||||
VirtualStick& add_keys(Key left, Key right, Key up, Key down);
|
||||
VirtualStick& add_buttons(int gamepad_id, Button left, Button right, Button up, Button down);
|
||||
VirtualStick& add_axes(int gamepad_id, Axis horizontal, Axis vertical, float deadzone);
|
||||
VirtualStick& repeat(float m_repeat_delay, float m_repeat_interval);
|
||||
VirtualStick& press_buffer(float duration);
|
||||
VirtualStick& release_buffer(float duration);
|
||||
|
||||
void update();
|
||||
const Vec2& value() const { return m_value; }
|
||||
const Point& value_i() const { return m_value_i; }
|
||||
const Vec2& last_value() const { return m_last_value; }
|
||||
const Point& last_value_i() const { return m_last_value_i; }
|
||||
bool pressed() const { return m_pressed; }
|
||||
bool released() const { return m_released; }
|
||||
void clear_press_buffer() { m_last_press_time = 0; }
|
||||
void clear_release_buffer() { m_last_release_time = 0; }
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user