godot-cpp-utils/player_input.hpp

111 lines
4.0 KiB
C++
Raw Normal View History

2024-02-13 13:59:01 +00:00
#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>
2024-02-13 13:59:01 +00:00
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)
2024-02-13 13:59:01 +00:00
static void _bind_methods();
public:
/*! A PlayerInput action listener.
2024-05-29 18:23:59 +00:00
*
* 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`.
*/
2024-02-13 13:59:01 +00:00
struct Listener {
friend class PlayerInput;
private:
2024-05-29 18:23:59 +00:00
//! Negative action on axis, evaluates to -1.
gd::String actionNegative{""};
2024-05-29 18:23:59 +00:00
//! Positive action on axis, evaluates to +1.
gd::String actionPositive{""};
2024-05-29 18:23:59 +00:00
/*! The last cached action.
*
* If the newest result matches this, the event will be considered duplicate and ignored (not passed to listener)
*/
2024-02-13 13:59:01 +00:00
float lastCached{0.f};
2024-05-29 18:23:59 +00:00
//! The listening function.
gd::Callable callable;
2024-05-29 18:23:59 +00:00
//! If either actionNegative or actionPositive is a _mouse_ event this will be true
bool isMouseEvent{false};
2024-02-13 13:59:01 +00:00
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);
2024-05-29 18:23:59 +00:00
/*! 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);
2024-05-29 18:23:59 +00:00
//! 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;
2024-02-13 13:59:01 +00:00
};
public:
2024-05-29 18:23:59 +00:00
//! Returns the last stored mouse delta.
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;
2024-02-13 13:59:01 +00:00
2024-05-29 18:23:59 +00:00
//! Start listening for action.
void listen_to(Listener const &listener);
2024-05-29 18:23:59 +00:00
/*! Start listening for action.
*
* Shorthand for `listen_to(Listener(action, callable))`.
*/
void listen_to(gd::String action, gd::Callable callable);
2024-05-29 18:23:59 +00:00
/*! Start listening for action.
*
* Shorthand for `listen_to(Listener(negative, positive, callable))`.
*/
void listen_to(gd::String negative, gd::String positive, gd::Callable callable);
2024-05-29 18:23:59 +00:00
//! Remove any listeners related to node.
2024-02-13 13:59:01 +00:00
void stop_listening(Node *node);
2024-05-29 18:23:59 +00:00
//! Remove listeners exactly equal to listener.
void stop_listening(Listener const &listener);
2024-05-29 18:23:59 +00:00
//! Remove all listeners.
void clear_listeners();
2024-05-29 18:23:59 +00:00
//! set the device observe events from.
void set_device(int id);
private:
2024-05-29 18:23:59 +00:00
//! The last mouse motion, updated by the primary instance
static gd::Vector2 lastMouseMotion;
2024-05-29 18:23:59 +00:00
//! Does a primary instance exist
static bool primaryExists;
2024-05-29 18:23:59 +00:00
/*! Is this the primary instance.
*
* The primary instance is responsible for updating static variables like lastMouseMotion.
*/
bool isPrimary{false};
2024-05-29 18:23:59 +00:00
//! which device to observe events from.
int device{-1};
2024-05-29 18:23:59 +00:00
//! current listeners for this instance
gd::Vector<Listener> listeners{};
2024-02-13 13:59:01 +00:00
};
}
#endif // !PLAYER_INPUT_HPP