diff --git a/core/input/input.cpp b/core/input/input.cpp index 4d152c1ac4ac..5927924f0b9a 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -149,6 +149,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed); ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released); ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength); + ClassDB::bind_method(D_METHOD("get_action_duration", "action"), &Input::get_action_duration); ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping); ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed); @@ -326,6 +327,13 @@ float Input::get_action_strength(const StringName &p_action) const { return E->get().strength; } +float Input::get_action_duration(const StringName &p_action) const { + const Map::Element *E = action_state.find(p_action); + if (!E) + return 0.0f; + return (OS::get_singleton()->get_ticks_usec() - E->get().timestamp) / 1000000.0f; +} + float Input::get_joy_axis(int p_device, int p_axis) const { _THREAD_SAFE_METHOD_ int c = _combine_device(p_axis, p_device); @@ -602,6 +610,7 @@ void Input::_parse_input_event_impl(const Ref &p_event, bool p_is_em Action action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); action.idle_frame = Engine::get_singleton()->get_idle_frames(); + action.timestamp = OS::get_singleton()->get_ticks_usec(); action.pressed = p_event->is_action_pressed(E->key()); action.strength = 0.f; action_state[E->key()] = action; diff --git a/core/input/input.h b/core/input/input.h index 91e3b83b951f..3db1fca0fc79 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -115,6 +115,7 @@ class Input : public Object { struct Action { uint64_t physics_frame; uint64_t idle_frame; + uint64_t timestamp; bool pressed; float strength; }; @@ -266,6 +267,7 @@ class Input : public Object { bool is_action_just_pressed(const StringName &p_action) const; bool is_action_just_released(const StringName &p_action) const; float get_action_strength(const StringName &p_action) const; + float get_action_duration(const StringName &p_action) const; float get_joy_axis(int p_device, int p_axis) const; String get_joy_name(int p_idx); diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index fc3c3776cee8..9f5380cf68c3 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -51,6 +51,27 @@ Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer. + + + + + + + Returns the time in seconds for how long the given action has been pressed or kept in the released state. It means that the time resets to [code]0.0[/code] whenever the action's [code]pressed[/code] state is changed. Use [method is_action_pressed] to distinguish between pressed and released durations. + [b]Note:[/b] if the action has not been pressed nor released during the game at all, the method returns [code]0.0[/code] instead. + Example usage of implementing weapon charging mechanics: + [codeblock] + const CHARGE_TIME = 1.0 + var shooting = false + + func _physics_process(_delta): + if Input.is_action_pressed("shoot"): + shooting = Input.get_action_duration("shoot") >= CHARGE_TIME + else: + shooting = false + [/codeblock] + +