Add cap sprite to child scene and update project configuration
This commit is contained in:
50
addons/guide/inputs/guide_input.gd
Normal file
50
addons/guide/inputs/guide_input.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
@tool
|
||||
@icon("res://addons/guide/inputs/guide_input.svg")
|
||||
## A class representing some actuated input.
|
||||
class_name GUIDEInput
|
||||
extends Resource
|
||||
|
||||
## The current valueo f this input. Depending on the input type only parts of the
|
||||
## returned vector may be relevant.
|
||||
var _value:Vector3 = Vector3.ZERO
|
||||
|
||||
## Whether this input needs a reset per frame. _input is only called when
|
||||
## there is input happening, but some GUIDE inputs may need to be reset
|
||||
## in the absence of input.
|
||||
func _needs_reset() -> bool:
|
||||
return false
|
||||
|
||||
## Resets the input value to the default value. Is called once per frame if
|
||||
## _needs_reset returns true.
|
||||
func _reset() -> void:
|
||||
_value = Vector3.ZERO
|
||||
|
||||
## Called when an input event happens. Should update the
|
||||
## the input value of this input.
|
||||
func _input(event:InputEvent):
|
||||
pass
|
||||
|
||||
## Returns whether this input is the same input as the other input.
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return false
|
||||
|
||||
## Called when the input is started to be used by GUIDE. Can be used to perform
|
||||
## initializations.
|
||||
func _begin_usage() -> void :
|
||||
pass
|
||||
|
||||
## Called, when the input is no longer used by GUIDE. Can be used to perform
|
||||
## cleanup.
|
||||
func _end_usage() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return ""
|
||||
|
||||
func _editor_description() -> String:
|
||||
return ""
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return -1
|
12
addons/guide/inputs/guide_input.svg
Normal file
12
addons/guide/inputs/guide_input.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1.07241,0,0,1.07396,-3.11767,-2.34767)">
|
||||
<path d="M17.827,2.164C26.061,2.164 32.747,8.85 32.747,17.084C32.747,25.319 26.061,32.004 17.827,32.004C9.592,32.004 2.907,25.319 2.907,17.084C2.907,8.85 9.592,2.164 17.827,2.164ZM17.827,4.857C11.08,4.857 5.604,10.337 5.604,17.084C5.604,23.831 11.08,29.311 17.827,29.311C24.574,29.311 30.05,23.831 30.05,17.084C30.05,10.337 24.574,4.857 17.827,4.857Z" style="fill:rgb(253,150,0);"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0.687353,-2.69876)">
|
||||
<g transform="matrix(24,0,0,24,11.6286,27.2968)">
|
||||
<rect x="0.105" y="-0.717" width="0.097" height="0.717" style="fill:rgb(253,150,0);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
38
addons/guide/inputs/guide_input.svg.import
Normal file
38
addons/guide/inputs/guide_input.svg.import
Normal file
@@ -0,0 +1,38 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://oku7f5t0ox3r"
|
||||
path="res://.godot/imported/guide_input.svg-d7e8ae255db039e6a02cccc3f844cc0e.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/guide/inputs/guide_input.svg"
|
||||
dest_files=["res://.godot/imported/guide_input.svg-d7e8ae255db039e6a02cccc3f844cc0e.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=0.5
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=false
|
59
addons/guide/inputs/guide_input_action.gd
Normal file
59
addons/guide/inputs/guide_input_action.gd
Normal file
@@ -0,0 +1,59 @@
|
||||
## An input that mirrors the action's value while the action is triggered.
|
||||
@tool
|
||||
class_name GUIDEInputAction
|
||||
extends GUIDEInput
|
||||
|
||||
## The action that this input should mirror. This is live tracked, so any change in
|
||||
## the action will update the input.
|
||||
@export var action:GUIDEAction:
|
||||
set(value):
|
||||
if value == action:
|
||||
return
|
||||
action = value
|
||||
emit_changed()
|
||||
|
||||
func _begin_usage():
|
||||
if is_instance_valid(action):
|
||||
action.triggered.connect(_on)
|
||||
action.completed.connect(_off)
|
||||
action.ongoing.connect(_off)
|
||||
if action.is_triggered():
|
||||
_on()
|
||||
return
|
||||
# not triggered or no action.
|
||||
_off()
|
||||
|
||||
|
||||
func _end_usage():
|
||||
if is_instance_valid(action):
|
||||
action.triggered.disconnect(_on)
|
||||
action.completed.disconnect(_off)
|
||||
action.ongoing.disconnect(_off)
|
||||
|
||||
|
||||
func _on() -> void:
|
||||
# on is only called when the action is actually existing, so this is
|
||||
# always not-null here
|
||||
_value = action.value_axis_3d
|
||||
|
||||
func _off() -> void:
|
||||
_value = Vector3.ZERO
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputAction and other.action == action
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputAction: " + str(action) + ")"
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Action"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "An input that mirrors the action's value while the action is triggered."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_3D
|
115
addons/guide/inputs/guide_input_any.gd
Normal file
115
addons/guide/inputs/guide_input_any.gd
Normal file
@@ -0,0 +1,115 @@
|
||||
## Input that triggers if any input from the given device class
|
||||
## is given. Only looks for button inputs, not axis inputs as axes
|
||||
## have a tendency to accidentally trigger.
|
||||
@tool
|
||||
class_name GUIDEInputAny
|
||||
extends GUIDEInput
|
||||
|
||||
|
||||
## Should input from mouse buttons be considered? Deprecated, use
|
||||
## mouse_buttons instead.
|
||||
## @deprecated
|
||||
var mouse:bool:
|
||||
get: return mouse_buttons
|
||||
set(value): mouse_buttons = value
|
||||
|
||||
## Should input from joy buttons be considered. Deprecated, use
|
||||
## joy_buttons instead.
|
||||
## @deprecated
|
||||
var joy:bool:
|
||||
get: return joy_buttons
|
||||
set(value): joy_buttons = value
|
||||
|
||||
## Should input from mouse buttons be considered?
|
||||
@export var mouse_buttons:bool = false
|
||||
|
||||
## Should input from mouse movement be considered?
|
||||
@export var mouse_movement:bool = false
|
||||
|
||||
## Minimum movement distance of the mouse before it is considered
|
||||
## moving.
|
||||
@export var minimum_mouse_movement_distance:float = 1.0
|
||||
|
||||
## Should input from gamepad/joystick buttons be considered?
|
||||
@export var joy_buttons:bool = false
|
||||
|
||||
## Should input from gamepad/joystick axes be considered?
|
||||
@export var joy_axes:bool = false
|
||||
|
||||
## Minimum strength of a single joy axis actuation before it is considered
|
||||
## as actuated.
|
||||
@export var minimum_joy_axis_actuation_strength:float = 0.2
|
||||
|
||||
## Should input from the keyboard be considered?
|
||||
@export var keyboard:bool = false
|
||||
|
||||
## Should input from touch be considered?
|
||||
@export var touch:bool = false
|
||||
|
||||
|
||||
func _needs_reset() -> bool:
|
||||
# Needs reset because we cannot detect the absence of input.
|
||||
return true
|
||||
|
||||
func _input(event:InputEvent):
|
||||
if mouse_buttons and event is InputEventMouseButton:
|
||||
_value = Vector3.RIGHT
|
||||
return
|
||||
|
||||
if mouse_movement and event is InputEventMouseMotion \
|
||||
and event.relative.length() >= minimum_mouse_movement_distance:
|
||||
_value = Vector3.RIGHT
|
||||
return
|
||||
|
||||
if joy_buttons and event is InputEventJoypadButton:
|
||||
_value = Vector3.RIGHT
|
||||
return
|
||||
|
||||
if joy_axes and event is InputEventJoypadMotion \
|
||||
and abs(event.axis_value) >= minimum_joy_axis_actuation_strength:
|
||||
_value = Vector3.RIGHT
|
||||
return
|
||||
|
||||
if keyboard and event is InputEventKey:
|
||||
_value = Vector3.RIGHT
|
||||
return
|
||||
|
||||
if touch and (event is InputEventScreenTouch or event is InputEventScreenDrag):
|
||||
_value = Vector3.RIGHT
|
||||
return
|
||||
|
||||
_value = Vector3.ZERO
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputAny and \
|
||||
other.mouse == mouse and \
|
||||
other.joy == joy and \
|
||||
other.keyboard == keyboard
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Any Input"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Input that triggers if any input from the given device class is given."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.BOOL
|
||||
|
||||
# support for legacy properties
|
||||
func _get_property_list():
|
||||
return [
|
||||
{
|
||||
"name": "mouse",
|
||||
"type": TYPE_BOOL,
|
||||
"usage": PROPERTY_USAGE_NO_EDITOR
|
||||
},
|
||||
{
|
||||
"name": "joy",
|
||||
"type": TYPE_BOOL,
|
||||
"usage": PROPERTY_USAGE_NO_EDITOR
|
||||
}
|
||||
]
|
||||
|
43
addons/guide/inputs/guide_input_joy_axis_1d.gd
Normal file
43
addons/guide/inputs/guide_input_joy_axis_1d.gd
Normal file
@@ -0,0 +1,43 @@
|
||||
## Input from a single joy axis.
|
||||
@tool
|
||||
class_name GUIDEInputJoyAxis1D
|
||||
extends GUIDEInputJoyBase
|
||||
|
||||
## The joy axis to sample
|
||||
@export var axis:JoyAxis = JOY_AXIS_LEFT_X:
|
||||
set(value):
|
||||
if value == axis:
|
||||
return
|
||||
axis = value
|
||||
emit_changed()
|
||||
|
||||
func _input(event:InputEvent):
|
||||
if not event is InputEventJoypadMotion:
|
||||
return
|
||||
|
||||
if event.axis != axis:
|
||||
return
|
||||
|
||||
if joy_index > -1 and event.device != _joy_id:
|
||||
return
|
||||
|
||||
_value.x = event.axis_value
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputJoyAxis1D and \
|
||||
other.axis == axis and \
|
||||
other.joy_index == joy_index
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputJoyAxis1D: axis=" + str(axis) + ", joy_index=" + str(joy_index) + ")"
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Joy Axis 1D"
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "The input from a single joy axis."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_1D
|
58
addons/guide/inputs/guide_input_joy_axis_2d.gd
Normal file
58
addons/guide/inputs/guide_input_joy_axis_2d.gd
Normal file
@@ -0,0 +1,58 @@
|
||||
## Input from two joy axes.
|
||||
class_name GUIDEInputJoyAxis2D
|
||||
extends GUIDEInputJoyBase
|
||||
|
||||
## The joy axis to sample for x input.
|
||||
@export var x:JoyAxis = JOY_AXIS_LEFT_X:
|
||||
set(value):
|
||||
if value == x:
|
||||
return
|
||||
x = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
## The joy axis to sample for y input.
|
||||
@export var y:JoyAxis = JOY_AXIS_LEFT_Y:
|
||||
set(value):
|
||||
if value == y:
|
||||
return
|
||||
y = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
func _input(event:InputEvent):
|
||||
if not event is InputEventJoypadMotion:
|
||||
return
|
||||
|
||||
if event.axis != x and event.axis != y:
|
||||
return
|
||||
|
||||
if joy_index > -1 and event.device != _joy_id:
|
||||
return
|
||||
|
||||
if event.axis == x:
|
||||
_value.x = event.axis_value
|
||||
return
|
||||
|
||||
if event.axis == y:
|
||||
_value.y = event.axis_value
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputJoyAxis2D and \
|
||||
other.x == x and \
|
||||
other.y == y and \
|
||||
other.joy_index == joy_index
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputJoyAxis2D: x=" + str(x) + ", y=" + str(y) + ", joy_index=" + str(joy_index) + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Joy Axis 2D"
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "The input from two Joy axes. Usually from a stick."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_2D
|
35
addons/guide/inputs/guide_input_joy_base.gd
Normal file
35
addons/guide/inputs/guide_input_joy_base.gd
Normal file
@@ -0,0 +1,35 @@
|
||||
## Base class for joystick inputs.
|
||||
@tool
|
||||
class_name GUIDEInputJoyBase
|
||||
extends GUIDEInput
|
||||
|
||||
## The index of the connected joy pad to check. If -1 checks all joypads.
|
||||
@export var joy_index:int = -1:
|
||||
set(value):
|
||||
if value == joy_index:
|
||||
return
|
||||
joy_index = value
|
||||
emit_changed()
|
||||
|
||||
## Cached joystick ID if we use a joy index.
|
||||
var _joy_id:int = -2
|
||||
|
||||
func _begin_usage():
|
||||
Input.joy_connection_changed.connect(_update_joy_id)
|
||||
_update_joy_id(null, null)
|
||||
|
||||
func _end_usage():
|
||||
Input.joy_connection_changed.disconnect(_update_joy_id)
|
||||
|
||||
func _update_joy_id(_ignore, _ignore2):
|
||||
if joy_index < 0:
|
||||
return
|
||||
|
||||
var joypads:Array[int] = Input.get_connected_joypads()
|
||||
if joy_index < joypads.size():
|
||||
_joy_id = joypads[joy_index]
|
||||
else:
|
||||
push_warning("Only ", joypads.size(), " joy pads/sticks connected. Cannot sample in put from index ", joy_index, ".")
|
||||
_joy_id = -2
|
||||
|
||||
|
44
addons/guide/inputs/guide_input_joy_button.gd
Normal file
44
addons/guide/inputs/guide_input_joy_button.gd
Normal file
@@ -0,0 +1,44 @@
|
||||
@tool
|
||||
class_name GUIDEInputJoyButton
|
||||
extends GUIDEInputJoyBase
|
||||
|
||||
@export var button:JoyButton = JOY_BUTTON_A:
|
||||
set(value):
|
||||
if value == button:
|
||||
return
|
||||
button = value
|
||||
emit_changed()
|
||||
|
||||
func _input(event:InputEvent):
|
||||
if not event is InputEventJoypadButton:
|
||||
return
|
||||
|
||||
if event.button_index != button:
|
||||
return
|
||||
|
||||
|
||||
if joy_index > -1 and event.device != _joy_id:
|
||||
return
|
||||
|
||||
_value.x = 1.0 if event.pressed else 0.0
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputJoyButton and \
|
||||
other.button == button and \
|
||||
other.joy_index == joy_index
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputJoyButton: button=" + str(button) + ", joy_index=" + str(joy_index) + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Joy Button"
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "A button press from a joy button."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.BOOL
|
127
addons/guide/inputs/guide_input_key.gd
Normal file
127
addons/guide/inputs/guide_input_key.gd
Normal file
@@ -0,0 +1,127 @@
|
||||
@tool
|
||||
class_name GUIDEInputKey
|
||||
extends GUIDEInput
|
||||
|
||||
## The physical keycode of the key.
|
||||
@export var key:Key:
|
||||
set(value):
|
||||
if value == key:
|
||||
return
|
||||
key = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
@export_group("Modifiers")
|
||||
## Whether shift must be pressed.
|
||||
@export var shift:bool = false:
|
||||
set(value):
|
||||
if value == shift:
|
||||
return
|
||||
shift = value
|
||||
emit_changed()
|
||||
|
||||
## Whether control must be pressed.
|
||||
@export var control:bool = false:
|
||||
set(value):
|
||||
if value == control:
|
||||
return
|
||||
control = value
|
||||
emit_changed()
|
||||
|
||||
## Whether alt must be pressed.
|
||||
@export var alt:bool = false:
|
||||
set(value):
|
||||
if value == alt:
|
||||
return
|
||||
alt = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
## Whether meta/win/cmd must be pressed.
|
||||
@export var meta:bool = false:
|
||||
set(value):
|
||||
if value == meta:
|
||||
return
|
||||
meta = value
|
||||
emit_changed()
|
||||
|
||||
## Whether this input should fire if additional
|
||||
## modifier keys are currently pressed.
|
||||
@export var allow_additional_modifiers:bool = true:
|
||||
set(value):
|
||||
if value == allow_additional_modifiers:
|
||||
return
|
||||
allow_additional_modifiers = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
|
||||
func _input(event:InputEvent):
|
||||
if not event is InputEventKey:
|
||||
return
|
||||
|
||||
# we start assuming the key is not pressed right now
|
||||
_value.x = 0.0
|
||||
|
||||
# the key itself must be pressed
|
||||
if not Input.is_physical_key_pressed(key):
|
||||
return
|
||||
|
||||
# every required modifier must be pressed
|
||||
if shift and not Input.is_physical_key_pressed(KEY_SHIFT):
|
||||
return
|
||||
|
||||
if control and not Input.is_physical_key_pressed(KEY_CTRL):
|
||||
return
|
||||
|
||||
if alt and not Input.is_physical_key_pressed(KEY_ALT):
|
||||
return
|
||||
|
||||
if meta and not Input.is_physical_key_pressed(KEY_META):
|
||||
return
|
||||
|
||||
# unless additional modifiers are allowed, every
|
||||
# unselected modifier must not be pressed (except if the
|
||||
# bound key is actually the modifier itself)
|
||||
|
||||
if not allow_additional_modifiers:
|
||||
if not shift and key != KEY_SHIFT and Input.is_physical_key_pressed(KEY_SHIFT):
|
||||
return
|
||||
|
||||
if not control and key != KEY_CTRL and Input.is_physical_key_pressed(KEY_CTRL):
|
||||
return
|
||||
|
||||
if not alt and key != KEY_ALT and Input.is_physical_key_pressed(KEY_ALT):
|
||||
return
|
||||
|
||||
if not meta and key != KEY_META and Input.is_physical_key_pressed(KEY_META):
|
||||
return
|
||||
|
||||
# we're still here, so all required keys are pressed and
|
||||
# no extra keys are pressed
|
||||
|
||||
_value.x = 1.0
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputKey \
|
||||
and other.key == key \
|
||||
and other.shift == shift \
|
||||
and other.control == control \
|
||||
and other.alt == alt \
|
||||
and other.meta == meta \
|
||||
and other.allow_additional_modifiers == allow_additional_modifiers
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputKey: key=" + str(key) + ", shift=" + str(shift) + ", alt=" + str(alt) + ", control=" + str(control) + ", meta="+ str(meta) + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Key"
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "A button press on the keyboard."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.BOOL
|
47
addons/guide/inputs/guide_input_mouse_axis_1d.gd
Normal file
47
addons/guide/inputs/guide_input_mouse_axis_1d.gd
Normal file
@@ -0,0 +1,47 @@
|
||||
@tool
|
||||
class_name GUIDEInputMouseAxis1D
|
||||
extends GUIDEInput
|
||||
|
||||
enum GUIDEInputMouseAxis {
|
||||
X,
|
||||
Y
|
||||
}
|
||||
|
||||
@export var axis:GUIDEInputMouseAxis:
|
||||
set(value):
|
||||
if value == axis:
|
||||
return
|
||||
axis = value
|
||||
emit_changed()
|
||||
|
||||
# we don't get mouse updates when the mouse is not moving, so this needs to be
|
||||
# reset every frame
|
||||
func _needs_reset() -> bool:
|
||||
return true
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
match axis:
|
||||
GUIDEInputMouseAxis.X:
|
||||
_value.x = event.relative.x
|
||||
GUIDEInputMouseAxis.Y:
|
||||
_value.x = event.relative.y
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputMouseAxis1D and other.axis == axis
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputMouseAxis1D: axis=" + str(axis) + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Mouse Axis 1D"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Relative mouse movement on a single axis."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_1D
|
35
addons/guide/inputs/guide_input_mouse_axis_2d.gd
Normal file
35
addons/guide/inputs/guide_input_mouse_axis_2d.gd
Normal file
@@ -0,0 +1,35 @@
|
||||
@tool
|
||||
class_name GUIDEInputMouseAxis2D
|
||||
extends GUIDEInput
|
||||
|
||||
|
||||
# we don't get mouse updates when the mouse is not moving, so this needs to be
|
||||
# reset every frame
|
||||
func _needs_reset() -> bool:
|
||||
return true
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
if not event is InputEventMouseMotion:
|
||||
return
|
||||
|
||||
_value.x = event.relative.x
|
||||
_value.y = event.relative.y
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputMouseAxis2D
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputMouseAxis2D)"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Mouse Axis 2D"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Relative mouse movement on 2 axes."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_2D
|
65
addons/guide/inputs/guide_input_mouse_button.gd
Normal file
65
addons/guide/inputs/guide_input_mouse_button.gd
Normal file
@@ -0,0 +1,65 @@
|
||||
@tool
|
||||
class_name GUIDEInputMouseButton
|
||||
extends GUIDEInput
|
||||
|
||||
|
||||
@export var button:MouseButton = MOUSE_BUTTON_LEFT:
|
||||
set(value):
|
||||
if value == button:
|
||||
return
|
||||
button = value
|
||||
emit_changed()
|
||||
|
||||
|
||||
func _needs_reset():
|
||||
# mouse wheel up and down can potentially send multiple inputs within a single frame
|
||||
# so we need to smooth this out a bit.
|
||||
return button == MOUSE_BUTTON_WHEEL_UP or button == MOUSE_BUTTON_WHEEL_DOWN
|
||||
|
||||
var _reset_to:Vector3
|
||||
var _was_pressed_this_frame:bool
|
||||
|
||||
func _reset() -> void:
|
||||
_was_pressed_this_frame = false
|
||||
_value = _reset_to
|
||||
|
||||
|
||||
func _input(event:InputEvent):
|
||||
if not event is InputEventMouseButton:
|
||||
return
|
||||
|
||||
if event.button_index != button:
|
||||
return
|
||||
|
||||
|
||||
if _needs_reset():
|
||||
# we always reset to the last event we received in a frame
|
||||
# so after the frame is over we're still in sync.
|
||||
_reset_to.x = 1.0 if event.pressed else 0.0
|
||||
|
||||
if event.pressed:
|
||||
_was_pressed_this_frame = true
|
||||
|
||||
if not event.pressed and _was_pressed_this_frame:
|
||||
# keep pressed state for this frame
|
||||
return
|
||||
|
||||
_value.x = 1.0 if event.pressed else 0.0
|
||||
|
||||
func is_same_as(other:GUIDEInput) -> bool:
|
||||
return other is GUIDEInputMouseButton and other.button == button
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputMouseButton: button=" + str(button) + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Mouse Button"
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "A press of a mouse button. The mouse wheel is also a button."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.BOOL
|
41
addons/guide/inputs/guide_input_mouse_position.gd
Normal file
41
addons/guide/inputs/guide_input_mouse_position.gd
Normal file
@@ -0,0 +1,41 @@
|
||||
@tool
|
||||
class_name GUIDEInputMousePosition
|
||||
extends GUIDEInput
|
||||
|
||||
|
||||
func _begin_usage() -> void :
|
||||
_update_mouse_position()
|
||||
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
if not event is InputEventMouseMotion:
|
||||
return
|
||||
|
||||
_update_mouse_position()
|
||||
|
||||
|
||||
func _update_mouse_position():
|
||||
var position:Vector2 = Engine.get_main_loop().root.get_mouse_position()
|
||||
|
||||
_value.x = position.x
|
||||
_value.y = position.y
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputMousePosition
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputMousePosition)"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Mouse Position"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Position of the mouse in the main viewport."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_2D
|
83
addons/guide/inputs/guide_input_touch_angle.gd
Normal file
83
addons/guide/inputs/guide_input_touch_angle.gd
Normal file
@@ -0,0 +1,83 @@
|
||||
## Input representing angle changes between two fingers.
|
||||
@tool
|
||||
class_name GUIDEInputTouchAngle
|
||||
extends GUIDEInput
|
||||
|
||||
const GUIDETouchState = preload("guide_touch_state.gd")
|
||||
|
||||
## Unit in which the angle should be provided
|
||||
enum AngleUnit {
|
||||
## Angle is provided in radians
|
||||
RADIANS = 0,
|
||||
## Angle is provided in degrees.
|
||||
DEGREES = 1
|
||||
}
|
||||
|
||||
## The unit in which the angle should be provided
|
||||
@export var unit:AngleUnit = AngleUnit.RADIANS
|
||||
|
||||
var _initial_angle:float = INF
|
||||
|
||||
# We use the reset call to calculate the angle for this frame
|
||||
# so it can serve as reference for the next frame
|
||||
func _needs_reset() -> bool:
|
||||
return true
|
||||
|
||||
func _reset():
|
||||
var angle = _calculate_angle()
|
||||
# update initial angle when input is actuated or stops being actuated
|
||||
if is_finite(_initial_angle) != is_finite(angle):
|
||||
_initial_angle = angle
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
if not GUIDETouchState.process_input_event(event):
|
||||
# not touch-related
|
||||
return
|
||||
|
||||
var angle := _calculate_angle()
|
||||
# if either current angle or initial angle is not set,
|
||||
# we are zero
|
||||
if not is_finite(angle) or not is_finite(_initial_angle):
|
||||
_value = Vector3.ZERO
|
||||
return
|
||||
|
||||
# we assume that _initial_distance is never 0 because
|
||||
# you cannot have two fingers physically at the same place
|
||||
# on a touch screen
|
||||
_value = Vector3(angle - _initial_angle, 0, 0)
|
||||
|
||||
|
||||
func _calculate_angle() -> float:
|
||||
var pos1:Vector2 = GUIDETouchState.get_finger_position(0, 2)
|
||||
# if we have no position for first finger, we can immediately abort
|
||||
if not pos1.is_finite():
|
||||
return INF
|
||||
|
||||
var pos2:Vector2 = GUIDETouchState.get_finger_position(1, 2)
|
||||
# if there is no second finger, we can abort as well
|
||||
if not pos2.is_finite():
|
||||
return INF
|
||||
|
||||
# calculate distance for the fingers
|
||||
return -pos1.angle_to_point(pos2)
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputTouchAngle and \
|
||||
other.unit == unit
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputTouchAngle unit=" + ("radians" if unit == AngleUnit.RADIANS else "degrees") + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Touch Angle"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Angle changes of two touching fingers."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_1D
|
44
addons/guide/inputs/guide_input_touch_axis_1d.gd
Normal file
44
addons/guide/inputs/guide_input_touch_axis_1d.gd
Normal file
@@ -0,0 +1,44 @@
|
||||
@tool
|
||||
class_name GUIDEInputTouchAxis1D
|
||||
extends GUIDEInputTouchAxisBase
|
||||
|
||||
enum GUIDEInputTouchAxis {
|
||||
X,
|
||||
Y
|
||||
}
|
||||
|
||||
@export var axis:GUIDEInputTouchAxis:
|
||||
set(value):
|
||||
if value == axis:
|
||||
return
|
||||
axis = value
|
||||
emit_changed()
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputTouchAxis1D and \
|
||||
other.finger_count == finger_count and \
|
||||
other.finger_index == finger_index and \
|
||||
other.axis == axis
|
||||
|
||||
func _apply_value(value:Vector2):
|
||||
match axis:
|
||||
GUIDEInputTouchAxis.X:
|
||||
_value = Vector3(value.x, 0, 0)
|
||||
GUIDEInputTouchAxis.Y:
|
||||
_value = Vector3(value.y, 0, 0)
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputTouchAxis1D finger_count=" + str(finger_count) + \
|
||||
" finger_index=" + str(finger_index) +" axis=" + ("X" if axis == GUIDEInputTouchAxis.X else "Y") + ")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Touch Axis1D"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Relative movement of a touching finger on a single axis."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_1D
|
27
addons/guide/inputs/guide_input_touch_axis_2d.gd
Normal file
27
addons/guide/inputs/guide_input_touch_axis_2d.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
@tool
|
||||
class_name GUIDEInputTouchAxis2D
|
||||
extends GUIDEInputTouchAxisBase
|
||||
|
||||
func _apply_value(value:Vector2):
|
||||
_value = Vector3(value.x, value.y, 0)
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputTouchAxis2D and \
|
||||
other.finger_count == finger_count and \
|
||||
other.finger_index == finger_index
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputTouchAxis2D finger_count=" + str(finger_count) + \
|
||||
" finger_index=" + str(finger_index) +")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Touch Axis2D"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "2D relative movement of a touching finger."
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_2D
|
46
addons/guide/inputs/guide_input_touch_axis_base.gd
Normal file
46
addons/guide/inputs/guide_input_touch_axis_base.gd
Normal file
@@ -0,0 +1,46 @@
|
||||
## Base class for axis-like touch input.
|
||||
@tool
|
||||
class_name GUIDEInputTouchAxisBase
|
||||
extends GUIDEInputTouchBase
|
||||
|
||||
const GUIDETouchState = preload("guide_touch_state.gd")
|
||||
|
||||
var _last_position:Vector2 = Vector2.INF
|
||||
|
||||
# We use the reset call to calculate the position for this frame
|
||||
# so it can serve as reference for the next frame
|
||||
func _needs_reset() -> bool:
|
||||
return true
|
||||
|
||||
func _reset() -> void:
|
||||
_last_position = GUIDETouchState.get_finger_position(finger_index, finger_count)
|
||||
_apply_value(_calculate_value(_last_position))
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
if not GUIDETouchState.process_input_event(event):
|
||||
# not touch-related
|
||||
return
|
||||
|
||||
# calculate live position from the cache
|
||||
var new_position:Vector2 = GUIDETouchState.get_finger_position(finger_index, finger_count)
|
||||
|
||||
_apply_value(_calculate_value(new_position))
|
||||
|
||||
func _apply_value(value:Vector2):
|
||||
pass
|
||||
|
||||
func _calculate_value(new_position:Vector2) -> Vector2:
|
||||
# if we cannot calculate a delta because old or new position
|
||||
# are undefined, we say the delta is zero
|
||||
if not _last_position.is_finite() or not new_position.is_finite():
|
||||
return Vector2.ZERO
|
||||
|
||||
return new_position - _last_position
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputTouchAxis2D and \
|
||||
other.finger_count == finger_count and \
|
||||
other.finger_index == finger_index
|
||||
|
||||
|
22
addons/guide/inputs/guide_input_touch_base.gd
Normal file
22
addons/guide/inputs/guide_input_touch_base.gd
Normal file
@@ -0,0 +1,22 @@
|
||||
## Base class for generic touch input
|
||||
@tool
|
||||
class_name GUIDEInputTouchBase
|
||||
extends GUIDEInput
|
||||
|
||||
## The number of fingers to be tracked.
|
||||
@export_range(1, 5, 1, "or_greater") var finger_count:int = 1:
|
||||
set(value):
|
||||
if value < 1:
|
||||
value = 1
|
||||
finger_count = value
|
||||
emit_changed()
|
||||
|
||||
## The index of the finger for which the position/delta should be reported
|
||||
## (0 = first finger, 1 = second finger, etc.). If -1, reports the average position/delta for
|
||||
## all fingers currently touching.
|
||||
@export_range(-1, 4, 1, "or_greater") var finger_index:int = 0:
|
||||
set(value):
|
||||
if value < -1:
|
||||
value = -1
|
||||
finger_index = value
|
||||
emit_changed()
|
72
addons/guide/inputs/guide_input_touch_distance.gd
Normal file
72
addons/guide/inputs/guide_input_touch_distance.gd
Normal file
@@ -0,0 +1,72 @@
|
||||
## Input representing the distance changes between two fingers.
|
||||
@tool
|
||||
class_name GUIDEInputTouchDistance
|
||||
extends GUIDEInput
|
||||
|
||||
const GUIDETouchState = preload("guide_touch_state.gd")
|
||||
|
||||
var _initial_distance:float = INF
|
||||
|
||||
# We use the reset call to calculate the distance for this frame
|
||||
# so it can serve as reference for the next frame
|
||||
func _needs_reset() -> bool:
|
||||
return true
|
||||
|
||||
func _reset():
|
||||
var distance = _calculate_distance()
|
||||
# update initial distance when input is actuated or stops being actuated
|
||||
if is_finite(_initial_distance) != is_finite(distance):
|
||||
_initial_distance = distance
|
||||
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
if not GUIDETouchState.process_input_event(event):
|
||||
# not touch-related
|
||||
return
|
||||
|
||||
var distance := _calculate_distance()
|
||||
# if either current distance or initial distance is not set,
|
||||
# we are zero
|
||||
if not is_finite(distance) or not is_finite(_initial_distance):
|
||||
_value = Vector3.ZERO
|
||||
return
|
||||
|
||||
# we assume that _initial_distance is never 0 because
|
||||
# you cannot have two fingers physically at the same place
|
||||
# on a touch screen
|
||||
_value = Vector3(distance / _initial_distance, 0, 0)
|
||||
|
||||
|
||||
func _calculate_distance() -> float:
|
||||
var pos1:Vector2 = GUIDETouchState.get_finger_position(0, 2)
|
||||
# if we have no position for first finger, we can immediately abort
|
||||
if not pos1.is_finite():
|
||||
return INF
|
||||
|
||||
var pos2:Vector2 = GUIDETouchState.get_finger_position(1, 2)
|
||||
# if there is no second finger, we can abort as well
|
||||
if not pos2.is_finite():
|
||||
return INF
|
||||
|
||||
# calculate distance for the fingers
|
||||
return pos1.distance_to(pos2)
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputTouchDistance
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputTouchDistance)"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Touch Distance"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Distance of two touching fingers."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_1D
|
47
addons/guide/inputs/guide_input_touch_position.gd
Normal file
47
addons/guide/inputs/guide_input_touch_position.gd
Normal file
@@ -0,0 +1,47 @@
|
||||
@tool
|
||||
class_name GUIDEInputTouchPosition
|
||||
extends GUIDEInputTouchBase
|
||||
|
||||
const GUIDETouchState = preload("guide_touch_state.gd")
|
||||
|
||||
|
||||
func _begin_usage():
|
||||
_value = Vector3.INF
|
||||
|
||||
|
||||
func _input(event:InputEvent) -> void:
|
||||
# update touch state
|
||||
if not GUIDETouchState.process_input_event(event):
|
||||
# not touch-related
|
||||
return
|
||||
|
||||
# update finger position
|
||||
var position := GUIDETouchState.get_finger_position(finger_index, finger_count)
|
||||
if not position.is_finite():
|
||||
_value = Vector3.INF
|
||||
return
|
||||
|
||||
_value = Vector3(position.x, position.y, 0)
|
||||
|
||||
|
||||
func is_same_as(other:GUIDEInput):
|
||||
return other is GUIDEInputTouchPosition and \
|
||||
other.finger_count == finger_count and \
|
||||
other.finger_index == finger_index
|
||||
|
||||
|
||||
func _to_string():
|
||||
return "(GUIDEInputTouchPosition finger_count=" + str(finger_count) + \
|
||||
" finger_index=" + str(finger_index) +")"
|
||||
|
||||
|
||||
func _editor_name() -> String:
|
||||
return "Touch Position"
|
||||
|
||||
|
||||
func _editor_description() -> String:
|
||||
return "Position of a touching finger."
|
||||
|
||||
|
||||
func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
|
||||
return GUIDEAction.GUIDEActionValueType.AXIS_2D
|
73
addons/guide/inputs/guide_touch_state.gd
Normal file
73
addons/guide/inputs/guide_touch_state.gd
Normal file
@@ -0,0 +1,73 @@
|
||||
@tool
|
||||
## Shared information about current touch state. This simplifies implementation of the touch inputs
|
||||
## and avoids having to process the same events multiple times.
|
||||
|
||||
# Cached finger positions
|
||||
static var _finger_positions:Dictionary = {}
|
||||
|
||||
# Events processed this frame.
|
||||
static var _processed_events:Dictionary = {}
|
||||
|
||||
# Last frame we were called
|
||||
static var _last_frame:int = -1
|
||||
|
||||
|
||||
## Processes an input event and updates touch state. Returns true, if the given event
|
||||
## was touch-related.
|
||||
static func process_input_event(event:InputEvent) -> bool:
|
||||
if not event is InputEventScreenTouch and not event is InputEventScreenDrag:
|
||||
return false
|
||||
|
||||
var this_frame = Engine.get_process_frames()
|
||||
|
||||
# if we are in a new frame, clear the processed events
|
||||
if this_frame != _last_frame:
|
||||
_last_frame = this_frame
|
||||
_processed_events.clear()
|
||||
|
||||
# if the event already was processed, skip processing it again
|
||||
if _processed_events.has(event):
|
||||
return true
|
||||
|
||||
_processed_events[event] = true
|
||||
|
||||
var index:int = event.index
|
||||
|
||||
if event is InputEventScreenTouch:
|
||||
if event.pressed:
|
||||
_finger_positions[index] = event.position
|
||||
else:
|
||||
_finger_positions.erase(index)
|
||||
|
||||
if event is InputEventScreenDrag:
|
||||
_finger_positions[index] = event.position
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Gets the finger position of the finger at the given index.
|
||||
## If finger_index is < 0, returns the average of all finger positions.
|
||||
## Will only return a position if the amount of fingers
|
||||
## currently touching matches finger_count.
|
||||
##
|
||||
## If no finger position can be determined, returns Vector2.INF.
|
||||
static func get_finger_position(finger_index:int, finger_count:int) -> Vector2:
|
||||
# if we have no finger positions right now, we can cut it short here
|
||||
if _finger_positions.is_empty():
|
||||
return Vector2.INF
|
||||
|
||||
# If the finger count doesn't match we have no position right now
|
||||
if _finger_positions.size() != finger_count:
|
||||
return Vector2.INF
|
||||
|
||||
# if a finger index is set, use this fingers position, if available
|
||||
if finger_index > -1:
|
||||
return _finger_positions.get(finger_index, Vector2.INF)
|
||||
|
||||
|
||||
var result = Vector2.ZERO
|
||||
for value in _finger_positions.values():
|
||||
result += value
|
||||
|
||||
result /= float(finger_count)
|
||||
return result
|
Reference in New Issue
Block a user