gd: added input addon
This commit is contained in:
254
addons/guide/guide_action.gd
Normal file
254
addons/guide/guide_action.gd
Normal file
@ -0,0 +1,254 @@
|
||||
@tool
|
||||
@icon("res://addons/guide/guide_action.svg")
|
||||
class_name GUIDEAction
|
||||
extends Resource
|
||||
|
||||
enum GUIDEActionValueType {
|
||||
BOOL = 0,
|
||||
AXIS_1D = 1,
|
||||
AXIS_2D = 2,
|
||||
AXIS_3D = 3
|
||||
}
|
||||
|
||||
enum GUIDEActionState {
|
||||
TRIGGERED,
|
||||
ONGOING,
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
## The name of this action. Required when this action should be used as
|
||||
## Godot action. Also displayed in the debugger.
|
||||
@export var name:StringName:
|
||||
set(value):
|
||||
if name == value:
|
||||
return
|
||||
name = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
## The action value type.
|
||||
@export var action_value_type: GUIDEActionValueType = GUIDEActionValueType.BOOL:
|
||||
set(value):
|
||||
if action_value_type == value:
|
||||
return
|
||||
action_value_type = value
|
||||
emit_changed()
|
||||
|
||||
## If this action triggers, lower-priority actions cannot trigger
|
||||
## if they share input with this action unless these actions are
|
||||
## chorded with this action.
|
||||
@export var block_lower_priority_actions:bool = true:
|
||||
set(value):
|
||||
if block_lower_priority_actions == value:
|
||||
return
|
||||
block_lower_priority_actions = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
@export_category("Godot Actions")
|
||||
## If true, then this action will be emitted into Godot's
|
||||
## built-in action system. This can be helpful to interact with
|
||||
## code using this system, like Godot's UI system. Actions
|
||||
## will be emitted on trigger and completion (e.g. button down
|
||||
## and button up).
|
||||
@export var emit_as_godot_actions:bool = false:
|
||||
set(value):
|
||||
if emit_as_godot_actions == value:
|
||||
return
|
||||
emit_as_godot_actions = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
@export_category("Action Remapping")
|
||||
|
||||
## If true, players can remap this action. To be remappable, make sure
|
||||
## that a name and the action type are properly set.
|
||||
@export var is_remappable:bool:
|
||||
set(value):
|
||||
if is_remappable == value:
|
||||
return
|
||||
is_remappable = value
|
||||
emit_changed()
|
||||
|
||||
## The display name of the action shown to the player.
|
||||
@export var display_name:String:
|
||||
set(value):
|
||||
if display_name == value:
|
||||
return
|
||||
display_name = value
|
||||
emit_changed()
|
||||
|
||||
## The display category of the action shown to the player.
|
||||
@export var display_category:String:
|
||||
set(value):
|
||||
if display_category == value:
|
||||
return
|
||||
display_category = value
|
||||
emit_changed()
|
||||
|
||||
## Emitted every frame while the action is triggered.
|
||||
signal triggered()
|
||||
|
||||
## Emitted when the action started evaluating.
|
||||
signal started()
|
||||
|
||||
## Emitted every frame while the action is still evaluating.
|
||||
signal ongoing()
|
||||
|
||||
## Emitted when the action finished evaluating.
|
||||
signal completed()
|
||||
|
||||
## Emitted when the action was cancelled.
|
||||
signal cancelled()
|
||||
|
||||
var _last_state:GUIDEActionState = GUIDEActionState.COMPLETED
|
||||
|
||||
var _value_bool:bool
|
||||
## Returns the value of this action as bool.
|
||||
var value_bool:bool:
|
||||
get: return _value_bool
|
||||
|
||||
## Returns the value of this action as float.
|
||||
var value_axis_1d:float:
|
||||
get: return _value.x
|
||||
|
||||
var _value_axis_2d:Vector2 = Vector2.ZERO
|
||||
## Returns the value of this action as Vector2.
|
||||
var value_axis_2d:Vector2:
|
||||
get: return _value_axis_2d
|
||||
|
||||
var _value:Vector3 = Vector3.ZERO
|
||||
## Returns the value of this action as Vector3.
|
||||
var value_axis_3d:Vector3:
|
||||
get: return _value
|
||||
|
||||
|
||||
var _elapsed_seconds:float
|
||||
## The amount of seconds elapsed since the action started evaluating.
|
||||
var elapsed_seconds:float:
|
||||
get: return _elapsed_seconds
|
||||
|
||||
var _elapsed_ratio:float
|
||||
## The ratio of the elapsed time to the hold time. This is a percentage
|
||||
## of the hold time that has passed. If the action has no hold time, this will
|
||||
## be 0 when the action is not triggered and 1 when the action is triggered.
|
||||
## Otherwise, this will be a value between 0 and 1.
|
||||
var elapsed_ratio:float:
|
||||
get: return _elapsed_ratio
|
||||
|
||||
var _triggered_seconds:float
|
||||
## The amount of seconds elapsed since the action triggered.
|
||||
var triggered_seconds:float:
|
||||
get: return _triggered_seconds
|
||||
|
||||
|
||||
## This is a hint for how long the input must remain actuated (in seconds) before the action triggers.
|
||||
## It depends on the mapping in which this action is used. If the mapping has no hold trigger it will be -1.
|
||||
## In general, you should not access this variable directly, but rather the `elapsed_ratio` property of the action
|
||||
## which is a percentage of the hold time that has passed.
|
||||
var _trigger_hold_threshold:float = -1.0
|
||||
|
||||
func _triggered(value:Vector3, delta:float) -> void:
|
||||
_triggered_seconds += delta
|
||||
_elapsed_ratio = 1.0
|
||||
_update_value(value)
|
||||
_last_state = GUIDEActionState.TRIGGERED
|
||||
triggered.emit()
|
||||
_emit_godot_action_maybe(true)
|
||||
|
||||
func _started(value:Vector3) -> void:
|
||||
_elapsed_ratio = 0.0
|
||||
_update_value(value)
|
||||
_last_state = GUIDEActionState.ONGOING
|
||||
started.emit()
|
||||
ongoing.emit()
|
||||
|
||||
func _ongoing(value:Vector3, delta:float) -> void:
|
||||
_elapsed_seconds += delta
|
||||
if _trigger_hold_threshold > 0:
|
||||
_elapsed_ratio = _elapsed_seconds / _trigger_hold_threshold
|
||||
_update_value(value)
|
||||
var was_triggered:bool = _last_state == GUIDEActionState.TRIGGERED
|
||||
_last_state = GUIDEActionState.ONGOING
|
||||
ongoing.emit()
|
||||
# if the action reverts from triggered to ongoing, this counts as
|
||||
# releasing the action for the godot action system.
|
||||
if was_triggered:
|
||||
_emit_godot_action_maybe(false)
|
||||
|
||||
|
||||
func _cancelled(value:Vector3) -> void:
|
||||
_elapsed_seconds = 0
|
||||
_elapsed_ratio = 0
|
||||
_update_value(value)
|
||||
_last_state = GUIDEActionState.COMPLETED
|
||||
cancelled.emit()
|
||||
completed.emit()
|
||||
|
||||
func _completed(value:Vector3) -> void:
|
||||
_elapsed_seconds = 0
|
||||
_elapsed_ratio = 0
|
||||
_triggered_seconds = 0
|
||||
_update_value(value)
|
||||
_last_state = GUIDEActionState.COMPLETED
|
||||
completed.emit()
|
||||
_emit_godot_action_maybe(false)
|
||||
|
||||
func _emit_godot_action_maybe(pressed:bool) -> void:
|
||||
if not emit_as_godot_actions:
|
||||
return
|
||||
|
||||
if name.is_empty():
|
||||
push_error("Cannot emit action into Godot's system because name is empty.")
|
||||
return
|
||||
|
||||
var godot_action = InputEventAction.new()
|
||||
godot_action.action = name
|
||||
godot_action.strength = _value.x
|
||||
godot_action.pressed = pressed
|
||||
Input.parse_input_event(godot_action)
|
||||
|
||||
func _update_value(value:Vector3):
|
||||
match action_value_type:
|
||||
GUIDEActionValueType.BOOL, GUIDEActionValueType.AXIS_1D:
|
||||
_value_bool = abs(value.x) > 0
|
||||
_value_axis_2d = Vector2(abs(value.x), 0)
|
||||
_value = Vector3(value.x, 0, 0)
|
||||
GUIDEActionValueType.AXIS_2D:
|
||||
_value_bool = abs(value.x) > 0
|
||||
_value_axis_2d = Vector2(value.x, value.y)
|
||||
_value = Vector3(value.x, value.y, 0)
|
||||
GUIDEActionValueType.AXIS_3D:
|
||||
_value_bool = abs(value.x) > 0
|
||||
_value_axis_2d = Vector2(value.x, value.y)
|
||||
_value = value
|
||||
|
||||
## Returns whether the action is currently triggered. Can be used for a
|
||||
## polling style input.
|
||||
func is_triggered() -> bool:
|
||||
return _last_state == GUIDEActionState.TRIGGERED
|
||||
|
||||
|
||||
## Returns whether the action is currently completed. Can be used for a
|
||||
## polling style input.
|
||||
func is_completed() -> bool:
|
||||
return _last_state == GUIDEActionState.COMPLETED
|
||||
|
||||
|
||||
## Returns whether the action is currently completed. Can be used for a
|
||||
## polling style input.
|
||||
func is_ongoing() -> bool:
|
||||
return _last_state == GUIDEActionState.ONGOING
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
# Try to give the most user friendly name
|
||||
if display_name != "":
|
||||
return display_name
|
||||
|
||||
if name != "":
|
||||
return name
|
||||
|
||||
return resource_path.get_file().replace(".tres", "")
|
||||
|
||||
|
Reference in New Issue
Block a user