87 lines
3.3 KiB
C++
87 lines
3.3 KiB
C++
#ifndef PLAYER_INPUT_HPP
|
|
#define PLAYER_INPUT_HPP
|
|
|
|
#include <optional>
|
|
#include <godot_cpp/classes/input.hpp>
|
|
#include <godot_cpp/classes/input_event.hpp>
|
|
#include <godot_cpp/classes/node.hpp>
|
|
#include <godot_cpp/templates/vector.hpp>
|
|
#include <godot_cpp/variant/callable.hpp>
|
|
|
|
namespace gd = godot;
|
|
|
|
namespace utils {
|
|
/*! An event-driven input observer.
|
|
*
|
|
* Listen for events with `listen_to`, registering godot input action names to callbacks. It's possible to register an "axis" by registering a listener with a positive and negative action.
|
|
*/
|
|
class PlayerInput : public gd::Node {
|
|
GDCLASS(PlayerInput, gd::Node)
|
|
static void _bind_methods();
|
|
public:
|
|
/*! A PlayerInput action listener.
|
|
* A listener is a combination of a positive and negative action and a callable.
|
|
* The expected callable signature is `void (godot::Ref<godot::InputEvent> event, float value)`
|
|
* actions can also be "special" actions prefixed with `_`.
|
|
* Special actions include `_mouse_up`, `_mouse_down`, `_mouse_left`, and `_mouse_right`.
|
|
*/
|
|
struct Listener {
|
|
friend class PlayerInput;
|
|
private:
|
|
// the two actions, evaluated as positive - negative
|
|
gd::String actionNegative{""};
|
|
gd::String actionPositive{""};
|
|
// the last cached action, if the newest result matches this, the event will be considered
|
|
// duplicate and ignored (not passed to listener)
|
|
float lastCached{0.f};
|
|
gd::Callable callable;
|
|
// if either actionNegative or actionPositive is a _mouse_ event this will be true
|
|
bool isMouseEvent{false};
|
|
|
|
public:
|
|
Listener() = default;
|
|
Listener(gd::String negative, gd::String positive, gd::Callable callable);
|
|
Listener(gd::String action, gd::Callable callable);
|
|
// evaluate the current state of an action.
|
|
static std::optional<float> evaluate_action(gd::String const &action);
|
|
// check if this event has any chance to result in a trigger, does not evaluate the event or
|
|
// poll current input state
|
|
bool has_changed(gd::Ref<gd::InputEvent> const &event);
|
|
// evaluate the event for changes to either actionPositive or actionNegative
|
|
float evaluate(gd::Ref<gd::InputEvent> const &event);
|
|
|
|
bool operator==(PlayerInput::Listener const& b) const;
|
|
};
|
|
private:
|
|
// the last mouse motion, updated by the primary instance
|
|
static gd::Vector2 lastMouseMotion;
|
|
// does a primary instance exist
|
|
static bool primaryExists;
|
|
// is this the primary instance
|
|
// the primary instance is responsible for updating static
|
|
// variables like lastMouseMotion
|
|
bool isPrimary{false};
|
|
|
|
// current listeners for this instance
|
|
gd::Vector<Listener> listeners{};
|
|
public:
|
|
static gd::Vector2 get_last_mouse_motion();
|
|
|
|
virtual void _enter_tree() override;
|
|
virtual void _exit_tree() override;
|
|
virtual void _unhandled_input(gd::Ref<gd::InputEvent> const &event) override;
|
|
virtual void _process(double deltaTime) override;
|
|
|
|
void listen_to(Listener const &listener);
|
|
void listen_to(gd::String action, gd::Callable callable);
|
|
void listen_to(gd::String negative, gd::String positive, gd::Callable callable);
|
|
|
|
void stop_listening(Node *node);
|
|
void stop_listening(Listener const &listener);
|
|
void clear_listeners();
|
|
};
|
|
}
|
|
|
|
|
|
#endif // !PLAYER_INPUT_HPP
|