gd: added input addon
This commit is contained in:
177
addons/guide/guide_input_mapping.gd
Normal file
177
addons/guide/guide_input_mapping.gd
Normal 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
|
||||
|
||||
|
Reference in New Issue
Block a user