gd: added input addon

This commit is contained in:
2025-05-27 19:20:46 +02:00
parent d8a1604af9
commit c8d8c7ec25
683 changed files with 21608 additions and 2 deletions

View File

@ -0,0 +1,177 @@
@icon("res://addons/guide/guide_internal.svg")
@tool
## A mapping from actuated input to a trigger result
class_name GUIDEInputMapping
extends Resource
## Whether the remapping configuration in this input mapping
## should override the configuration of the bound action. Enable
## this, to give a key a custom name or category for remapping.
@export var override_action_settings:bool = false:
set(value):
if override_action_settings == value:
return
override_action_settings = value
emit_changed()
## If true, players can remap this input mapping. Note that the
## action to which this input is bound also needs to be remappable
## for this setting to have an effect.
@export var is_remappable:bool = false:
set(value):
if is_remappable == value:
return
is_remappable = value
emit_changed()
## The display name of the input mapping shown to the player. If empty,
## the display name of the action is used.
@export var display_name:String = "":
set(value):
if display_name == value:
return
display_name = value
emit_changed()
## The display category of the input mapping. If empty, the display name of the
## action is used.
@export var display_category:String = "":
set(value):
if display_category == value:
return
display_category = value
emit_changed()
@export_group("Mappings")
## The input to be actuated
@export var input:GUIDEInput:
set(value):
if value == input:
return
input = value
emit_changed()
## A list of modifiers that preprocess the actuated input before
## it is fed to the triggers.
@export var modifiers:Array[GUIDEModifier] = []:
set(value):
if value == modifiers:
return
modifiers = value
emit_changed()
## A list of triggers that could trigger the mapped action.
@export var triggers:Array[GUIDETrigger] = []:
set(value):
if value == triggers:
return
triggers = value
emit_changed()
## Hint for how long the input must remain actuated (in seconds) before the mapping triggers.
## If the mapping has no hold trigger it will be -1. If it has multiple hold triggers
## the shortest hold time will be used.
var _trigger_hold_threshold:float = -1.0
var _state:GUIDETrigger.GUIDETriggerState = GUIDETrigger.GUIDETriggerState.NONE
var _value:Vector3 = Vector3.ZERO
var _trigger_list:Array[GUIDETrigger] = []
var _implicit_count:int = 0
var _explicit_count:int = 0
## Called when the mapping is started to be used by GUIDE. Calculates
## the number of implicit and explicit triggers so we don't need to do this
## per frame. Also creates a default trigger when none is set.
func _initialize() -> void :
_trigger_list.clear()
_implicit_count = 0
_explicit_count = 0
_trigger_hold_threshold = -1.0
if triggers.is_empty():
# make a default trigger and use that
var default_trigger = GUIDETriggerDown.new()
default_trigger.actuation_threshold = 0
_explicit_count = 1
_trigger_list.append(default_trigger)
return
for trigger in triggers:
match trigger._get_trigger_type():
GUIDETrigger.GUIDETriggerType.EXPLICIT:
_explicit_count += 1
GUIDETrigger.GUIDETriggerType.IMPLICIT:
_implicit_count += 1
_trigger_list.append(trigger)
# collect the hold threshold for hinting the UI about how long
# the input must be held down. This is only relevant for hold triggers
if trigger is GUIDETriggerHold:
if _trigger_hold_threshold == -1:
_trigger_hold_threshold = trigger.hold_treshold
else:
_trigger_hold_threshold = min(_trigger_hold_threshold, trigger.hold_treshold)
func _update_state(delta:float, value_type:GUIDEAction.GUIDEActionValueType):
# Collect the current input value
var input_value:Vector3 = input._value if input != null else Vector3.ZERO
# Run it through all modifiers
for modifier:GUIDEModifier in modifiers:
input_value = modifier._modify_input(input_value, delta, value_type)
_value = input_value
var triggered_implicits:int = 0
var triggered_explicits:int = 0
var triggered_blocked:int = 0
# Run over all triggers
var result:int = GUIDETrigger.GUIDETriggerState.NONE
for trigger:GUIDETrigger in _trigger_list:
var trigger_result:GUIDETrigger.GUIDETriggerState = trigger._update_state(_value, delta, value_type)
trigger._last_value = _value
var trigger_type = trigger._get_trigger_type()
if trigger_result == GUIDETrigger.GUIDETriggerState.TRIGGERED:
match trigger_type:
GUIDETrigger.GUIDETriggerType.EXPLICIT:
triggered_explicits += 1
GUIDETrigger.GUIDETriggerType.IMPLICIT:
triggered_implicits += 1
GUIDETrigger.GUIDETriggerType.BLOCKING:
triggered_blocked += 1
# we only care about the nuances of explicit triggers. implicits and blocking
# can only really return yes or no, so they have no nuance
if trigger_type == GUIDETrigger.GUIDETriggerType.EXPLICIT:
# Higher value results take precedence over lower value results
result = max(result, trigger_result)
# final collection
if triggered_blocked > 0:
# some blocker triggered which means that this cannot succeed
_state = GUIDETrigger.GUIDETriggerState.NONE
return
if triggered_implicits < _implicit_count:
# not all implicits triggered, which also fails this binding
_state = GUIDETrigger.GUIDETriggerState.NONE
return
if _explicit_count == 0 and _implicit_count > 0:
# if no explicits exist, its enough when all implicits trigger
_state = GUIDETrigger.GUIDETriggerState.TRIGGERED
return
# return the best result
_state = result