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,23 @@
@tool
@icon("res://addons/guide/modifiers/guide_modifier.svg")
class_name GUIDEModifier
extends Resource
## Called when the modifier is started to be used by GUIDE. Can be used to perform
## initializations.
func _begin_usage() -> void :
pass
## Called, when the modifier is no longer used by GUIDE. Can be used to perform
## cleanup.
func _end_usage() -> void:
pass
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
return input
func _editor_name() -> String:
return ""
func _editor_description() -> String:
return ""

View File

@ -0,0 +1 @@
uid://bl8rjl4oaldje

View 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,-6.66265,-2.69876)">
<g transform="matrix(24,0,0,24,11.6286,27.2968)">
<path d="M0.44,-0.259C0.444,-0.251 0.448,-0.243 0.452,-0.234C0.455,-0.225 0.459,-0.216 0.462,-0.207C0.465,-0.216 0.469,-0.225 0.473,-0.234C0.476,-0.242 0.48,-0.251 0.485,-0.26L0.728,-0.7C0.732,-0.708 0.736,-0.712 0.741,-0.714C0.746,-0.716 0.752,-0.717 0.761,-0.717L0.833,-0.717L0.833,-0L0.748,-0L0.748,-0.527C0.748,-0.534 0.748,-0.541 0.748,-0.549C0.748,-0.557 0.749,-0.565 0.75,-0.574L0.504,-0.126C0.496,-0.111 0.484,-0.103 0.469,-0.103L0.455,-0.103C0.44,-0.103 0.428,-0.111 0.42,-0.126L0.169,-0.575C0.17,-0.566 0.171,-0.558 0.171,-0.55C0.172,-0.541 0.172,-0.534 0.172,-0.527L0.172,-0L0.087,-0L0.087,-0.717L0.159,-0.717C0.167,-0.717 0.174,-0.716 0.179,-0.714C0.183,-0.712 0.188,-0.708 0.192,-0.7L0.44,-0.259Z" style="fill:rgb(253,150,0);fill-rule:nonzero;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://j64d8n4am2uh"
path="res://.godot/imported/guide_modifier.svg-8cf939ca3244410aba00f7b558561d72.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/guide/modifiers/guide_modifier.svg"
dest_files=["res://.godot/imported/guide_modifier.svg-8cf939ca3244410aba00f7b558561d72.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

View File

@ -0,0 +1,53 @@
## Converts a position input in viewport coordinates (e.g. from the mouse position input)
## into 3D coordinates (e.g. 3D world coordinates). Useful to get a 3D 'world' position.
## Returns a Vector3.INF if no 3D world coordinates can be determined.
@tool
class_name GUIDEModifier3DCoordinates
extends GUIDEModifier
## The maximum depth of the ray cast used to detect the 3D position.
@export var max_depth:float = 1000.0
## Whether the rays cast should collide with areas.
@export var collide_with_areas:bool = false
## Collision mask to use for the ray cast.
@export_flags_3d_physics var collision_mask:int
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
# if we collide with nothing, no need to even try
if collision_mask == 0:
return Vector3.INF
if not input.is_finite():
return Vector3.INF
var viewport = Engine.get_main_loop().root
var camera:Camera3D = viewport.get_camera_3d()
if camera == null:
return Vector3.INF
var input_position:Vector2 = Vector2(input.x, input.y)
var from:Vector3 = camera.project_ray_origin(input_position)
var to:Vector3 = from + camera.project_ray_normal(input_position) * max_depth
var query:= PhysicsRayQueryParameters3D.create(from, to, collision_mask)
query.collide_with_areas = collide_with_areas
var result = viewport.world_3d.direct_space_state.intersect_ray(query)
if result.has("position"):
return result.position
return Vector3.INF
func _editor_name() -> String:
return "3D coordinates"
func _editor_description() -> String:
return "Converts a position input in viewport coordinates (e.g. from the mouse position input)\n" + \
"into 3D coordinates (e.g. 3D world coordinates). Useful to get a 3D 'world' position."

View File

@ -0,0 +1 @@
uid://cw8qjwdktercg

View File

@ -0,0 +1,47 @@
@tool
## A filter that converts a 2D input into a boolean that is true when the
## input direction matches the selected direction. Note, that north is negative Y,
## because in Godot negative Y is up.
class_name GUIDEModifier8WayDirection
extends GUIDEModifier
enum GUIDEDirection {
EAST = 0,
NORTH_EAST = 1,
NORTH = 2,
NORTH_WEST = 3,
WEST = 4,
SOUTH_WEST = 5,
SOUTH = 6,
SOUTH_EAST = 7
}
## The direction in which the input should point.
@export var direction:GUIDEDirection = GUIDEDirection.EAST
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
if input.is_zero_approx():
return Vector3.ZERO
# get the angle in which the direction is pointing in radians.
var angle_radians = atan2( -input.y, input.x );
var octant = roundi( 8 * angle_radians / TAU + 8 ) % 8;
if octant == direction:
return Vector3.RIGHT # (1, 0, 0) indicating boolean true
else:
return Vector3.ZERO
func _editor_name() -> String:
return "8-way direction"
func _editor_description() -> String:
return "Converts a 2D input into a boolean that is true when the\n" + \
"input direction matches the selected direction. Note, that north is negative Y,\n" + \
"because in Godot negative Y is up."

View File

@ -0,0 +1 @@
uid://cmjelxqb3e7n6

View File

@ -0,0 +1,35 @@
## Converts a position input in viewport coordinates (e.g. from the mouse position input)
## into canvas coordinates (e.g. 2D world coordinates). Useful to get a 2D 'world' position.
@tool
class_name GUIDEModifierCanvasCoordinates
extends GUIDEModifier
## If checked, the input will be treated as relative input (position change)
## rather than absolute input (position).
@export var relative_input:bool:
set(value):
relative_input = value
emit_changed()
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
var viewport = Engine.get_main_loop().root
var transform = viewport.canvas_transform.affine_inverse()
var coordinates = transform * Vector2(input.x, input.y)
if relative_input:
var origin = transform * Vector2.ZERO
coordinates -= origin
return Vector3(coordinates.x, coordinates.y, input.z)
func _editor_name() -> String:
return "Canvas coordinates"
func _editor_description() -> String:
return "Converts a position input in viewport coordinates (e.g. from the mouse position input)\n" + \
"into canvas coordinates (e.g. 2D world coordinates). Useful to get a 2D 'world' position."

View File

@ -0,0 +1 @@
uid://vho2v7ax07ef

View File

@ -0,0 +1,51 @@
@tool
## Applies a separate curve to each input axis.
class_name GUIDEModifierCurve
extends GUIDEModifier
## The curve to apply to the x axis
@export var curve: Curve = default_curve()
## Apply modifier to X axis
@export var x: bool = true
## Apply modifier to Y axis
@export var y: bool = true
## Apply modifier to Z axis
@export var z: bool = true
## Create default curve resource with a smoothstep, 0.0 - 1.0 input/output range
static func default_curve() -> Curve:
var curve = Curve.new()
curve.add_point(Vector2(0.0, 0.0))
curve.add_point(Vector2(1.0, 1.0))
return curve
func _modify_input(input: Vector3, delta: float, value_type: GUIDEAction.GUIDEActionValueType) -> Vector3:
# Curve should never be null
if curve == null:
push_error("No curve added to Curve modifier.")
return input
if not input.is_finite():
return Vector3.INF
# Return vector with enabled axes modified, others remain unchanged.
return Vector3(
curve.sample(input.x) if x else input.x,
curve.sample(input.y) if y else input.y,
curve.sample(input.z) if z else input.z
)
func _editor_name() -> String:
return "Curve"
func _editor_description() -> String:
return "Applies a curve to each input axis."

View File

@ -0,0 +1 @@
uid://trjb6t778n84

View File

@ -0,0 +1,63 @@
@tool
## Inputs between the lower and upper threshold are mapped 0 -> 1.
## Values outside the thresholds are clamped.
class_name GUIDEModifierDeadzone
extends GUIDEModifier
## Lower threshold for the deadzone.
@export_range(0,1) var lower_threshold:float = 0.2:
set(value):
if value > upper_threshold:
lower_threshold = upper_threshold
else:
lower_threshold = value
emit_changed()
## Upper threshold for the deadzone.
@export_range(0,1) var upper_threshold:float = 1.0:
set(value):
if value < lower_threshold:
upper_threshold = lower_threshold
else:
upper_threshold = value
emit_changed()
func _rescale(value:float) -> float:
return min(1.0, (max(0.0, abs(value) - lower_threshold) / (upper_threshold - lower_threshold))) * sign(value)
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if upper_threshold <= lower_threshold:
return input
if not input.is_finite():
return Vector3.INF
match value_type:
GUIDEAction.GUIDEActionValueType.BOOL, GUIDEAction.GUIDEActionValueType.AXIS_1D:
return Vector3(_rescale(input.x), input.y, input.z)
GUIDEAction.GUIDEActionValueType.AXIS_2D:
var v2d = Vector2(input.x, input.y)
if v2d.is_zero_approx():
return Vector3(0, 0, input.z)
v2d = v2d.normalized() * _rescale(v2d.length())
return Vector3(v2d.x, v2d.y, input.z)
GUIDEAction.GUIDEActionValueType.AXIS_3D:
if input.is_zero_approx():
return Vector3.ZERO
return input.normalized() * _rescale(input.length())
_:
push_error("Unsupported value type. This is a bug. Please report it.")
return input
func _editor_name() -> String:
return "Deadzone"
func _editor_description() -> String:
return "Inputs between the lower and upper threshold are mapped 0 -> 1.\n" + \
"Values outside the thresholds are clamped."

View File

@ -0,0 +1 @@
uid://c47lkb48itd6l

View File

@ -0,0 +1,43 @@
## Swizzle the input vector components. Useful to map 1D input to 2D or vice versa.
@tool
class_name GUIDEModifierInputSwizzle
extends GUIDEModifier
enum GUIDEInputSwizzleOperation {
## Swap X and Y axes.
YXZ,
## Swap X and Z axes.
ZYX,
## Swap Y and Z axes.
XZY,
## Y to X, Z to Y, X to Z.
YZX,
## Y to Z, Z to X, X to Y.
ZXY
}
## The new order into which the input should be brought.
@export var order:GUIDEInputSwizzleOperation = GUIDEInputSwizzleOperation.YXZ
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
match order:
GUIDEInputSwizzleOperation.YXZ:
return Vector3(input.y, input.x, input.z)
GUIDEInputSwizzleOperation.ZYX:
return Vector3(input.z, input.y, input.x)
GUIDEInputSwizzleOperation.XZY:
return Vector3(input.x, input.z, input.y)
GUIDEInputSwizzleOperation.YZX:
return Vector3(input.y, input.z, input.x)
GUIDEInputSwizzleOperation.ZXY:
return Vector3(input.z, input.x, input.y)
_:
push_error("Unknown order ", order , " this is most likely a bug, please report it.")
return input
func _editor_name() -> String:
return "Input Swizzle"
func _editor_description() -> String:
return "Swizzle the input vector components. Useful to map 1D input to 2D or vice versa."

View File

@ -0,0 +1 @@
uid://bm5gjgadon6hb

View File

@ -0,0 +1,67 @@
@tool
## Maps an input range to an output range and optionally clamps the output.
class_name GUIDEModifierMapRange
extends GUIDEModifier
## Should the output be clamped to the range?
@export var apply_clamp:bool = true
## The minimum input value
@export var input_min:float = 0.0
## The maximum input value
@export var input_max:float = 1.0
## The minimum output value
@export var output_min:float = 0.0
## The maximum output value
@export var output_max:float = 1.0
## Apply modifier to X axis
@export var x:bool = true
## Apply modifier to Y axis
@export var y:bool = true
## Apply modifier to Z axis
@export var z:bool = true
var _omin:float
var _omax:float
func _begin_usage():
# we calculate the min and max of the output range here, so we can use them later and don't have to
# recalculate them every time the modifier is used
_omin = min(output_min, output_max)
_omax = max(output_min, output_max)
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
var x_value:float = remap(input.x, input_min, input_max, output_min, output_max)
var y_value:float = remap(input.y, input_min, input_max, output_min, output_max)
var z_value:float = remap(input.z, input_min, input_max, output_min, output_max)
if apply_clamp:
# clamp doesn't handle reverse ranges, so we need to use our calculated normalized output range
# to clamp the output values
x_value = clamp(x_value, _omin, _omax)
y_value = clamp(y_value, _omin, _omax)
z_value = clamp(z_value, _omin, _omax)
# Return vector with enabled axes set, others unchanged
return Vector3(
x_value if x else input.x,
y_value if y else input.y,
z_value if z else input.z,
)
func _editor_name() -> String:
return "Map Range"
func _editor_description() -> String:
return "Maps an input range to an output range and optionally clamps the output"

View File

@ -0,0 +1 @@
uid://cs70d8i3sqe7p

View File

@ -0,0 +1,52 @@
## Inverts input per axis.
@tool
class_name GUIDEModifierNegate
extends GUIDEModifier
## Whether the X axis should be inverted.
@export var x:bool = true:
set(value):
if x == value:
return
x = value
_update_caches()
emit_changed()
## Whether the Y axis should be inverted.
@export var y:bool = true:
set(value):
if y == value:
return
y = value
_update_caches()
emit_changed()
## Whether the Z axis should be inverted.
@export var z:bool = true:
set(value):
if z == value:
return
z = value
_update_caches()
emit_changed()
var _multiplier:Vector3 = Vector3.ONE * -1
func _update_caches():
_multiplier.x = -1 if x else 1
_multiplier.y = -1 if y else 1
_multiplier.z = -1 if z else 1
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
return input * _multiplier
func _editor_name() -> String:
return "Negate"
func _editor_description() -> String:
return "Inverts input per axis."

View File

@ -0,0 +1 @@
uid://ckggy40lm0vjc

View File

@ -0,0 +1,17 @@
## Normalizes the input vector.
@tool
class_name GUIDEModifierNormalize
extends GUIDEModifier
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
return input.normalized()
func _editor_name() -> String:
return "Normalize"
func _editor_description() -> String:
return "Normalizes the input vector."

View File

@ -0,0 +1 @@
uid://bs86pentlbwbi

View File

@ -0,0 +1,65 @@
## Limits inputs to positive or negative values.
@tool
class_name GUIDEModifierPositiveNegative
extends GUIDEModifier
enum LimitRange {
POSITIVE = 1,
NEGATIVE = 2
}
## The range of numbers to which the input should be limited
@export var range:LimitRange = LimitRange.POSITIVE
## Whether the X axis should be affected.
@export var x:bool = true:
set(value):
if x == value:
return
x = value
emit_changed()
## Whether the Y axis should be affected.
@export var y:bool = true:
set(value):
if y == value:
return
y = value
emit_changed()
## Whether the Z axis should be affected.
@export var z:bool = true:
set(value):
if z == value:
return
z = value
emit_changed()
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
match range:
LimitRange.POSITIVE:
return Vector3(
max(0, input.x) if x else input.x, \
max(0, input.y) if y else input.y, \
max(0, input.z) if z else input.z \
)
LimitRange.NEGATIVE:
return Vector3(
min(0, input.x) if x else input.x, \
min(0, input.y) if y else input.y, \
min(0, input.z) if z else input.z \
)
# should never happen
return input
func _editor_name() -> String:
return "Positive/Negative"
func _editor_description() -> String:
return "Clamps the input to positive or negative values."

View File

@ -0,0 +1 @@
uid://cbe2gpphnd1fg

View File

@ -0,0 +1,35 @@
@tool
## Scales the input by the given value and optionally, delta time.
class_name GUIDEModifierScale
extends GUIDEModifier
## The scale by which the input should be scaled.
@export var scale:Vector3 = Vector3.ONE:
set(value):
scale = value
emit_changed()
## If true, delta time will be multiplied in addition to the scale.
@export var apply_delta_time:bool = false:
set(value):
apply_delta_time = value
emit_changed()
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
if apply_delta_time:
return input * scale * delta
else:
return input * scale
func _editor_name() -> String:
return "Scale"
func _editor_description() -> String:
return "Scales the input by the given value and optionally, delta time."

View File

@ -0,0 +1 @@
uid://bjm4myqxg4phm

View File

@ -0,0 +1,105 @@
## Stateful modifier which provides a virtual "mouse" cursor driven by input. The modifier
## returns the current cursor position in pixels releative to the origin of the currently
## active window.
@tool
class_name GUIDEModifierVirtualCursor
extends GUIDEModifier
enum ScreenScale {
## Input is not scaled with input screen size. This means that the cursor will
## visually move slower on higher resolutions.
NONE = 0,
## Input is scaled with the longer axis of the screen size (e.g. width in
## landscape mode, height in portrait mode). The cursor will move with
## the same visual speed on all resolutions.
LONGER_AXIS = 1,
## Input is scaled with the shorter axis of the screen size (e.g. height in
## landscape mode, width in portrait mode). The cursor will move with the
## same visual speed on all resolutions.
SHORTER_AXIS = 2
}
## The initial position of the virtual cursor (given in screen relative coordinates)
@export var initial_position:Vector2 = Vector2(0.5, 0.5):
set(value):
initial_position = value.clamp(Vector2.ZERO, Vector2.ONE)
## The cursor movement speed in pixels.
@export var speed:Vector3 = Vector3.ONE
## Screen scaling to be applied to the cursor movement. This controls
## whether the cursor movement speed is resolution dependent or not.
## If set to anything but [code]None[/code] then the input value will
## be multiplied with the window width/height depending on the setting.
@export var screen_scale:ScreenScale = ScreenScale.LONGER_AXIS
## The scale by which the input should be scaled.
## @deprecated: use [member speed] instead.
var scale:Vector3:
get: return speed
set(value): speed = value
## If true, the cursor movement speed is in pixels per second, otherwise it is in pixels
## per frame.
@export var apply_delta_time:bool = true
## Cursor offset in pixels.
var _offset:Vector3 = Vector3.ZERO
## Returns the scaled screen size. This takes Godot's scaling factor for windows into account.
func _get_scaled_screen_size():
# Get window size, including scaling factor
var window = Engine.get_main_loop().get_root()
return window.get_screen_transform().affine_inverse() * Vector2(window.size)
func _begin_usage():
var window_size = _get_scaled_screen_size()
_offset = Vector3(window_size.x * initial_position.x, window_size.y * initial_position.y, 0)
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
# input is invalid, so just return current cursor position
return _offset
var window_size = _get_scaled_screen_size()
input *= speed
if apply_delta_time:
input *= delta
var screen_scale_factor:float = 1.0
match screen_scale:
ScreenScale.LONGER_AXIS:
screen_scale_factor = max(window_size.x, window_size.y)
ScreenScale.SHORTER_AXIS:
screen_scale_factor = min(window_size.x, window_size.y)
input *= screen_scale_factor
# apply input and clamp to window size
_offset = (_offset + input).clamp(Vector3.ZERO, Vector3(window_size.x, window_size.y, 0))
return _offset
func _editor_name() -> String:
return "Virtual Cursor"
func _editor_description() -> String:
return "Stateful modifier which provides a virtual \"mouse\" cursor driven by input. The modifier\n" + \
"returns the current cursor position in pixels releative to the origin of the currently \n" + \
"active window."
# support for legacy properties
func _get_property_list():
return [
{
"name": "scale",
"type": TYPE_VECTOR3,
"usage": PROPERTY_USAGE_NO_EDITOR
}
]

View File

@ -0,0 +1 @@
uid://0ubnfkes0d4r

View File

@ -0,0 +1,26 @@
## Converts the value of the input into window-relative units between 0 and 1.
## E.g. if a mouse cursor moves half a screen to the right and down, then
## this modifier will return (0.5, 0.5).
@tool
class_name GUIDEModifierWindowRelative
extends GUIDEModifier
func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
if not input.is_finite():
return Vector3.INF
var window = Engine.get_main_loop().get_root()
# We want real pixels, so we need to factor in any scaling that the window does.
var window_size:Vector2 = window.get_screen_transform().affine_inverse() * Vector2(window.size)
return Vector3(input.x / window_size.x, input.y / window_size.y, input.z)
func _editor_name() -> String:
return "Window relative"
func _editor_description() -> String:
return "Converts the value of the input into window-relative units between 0 and 1.\n" + \
"E.g. if a mouse cursor moves half a screen to the right and down, then \n" + \
"this modifier will return (0.5, 0.5)."

View File

@ -0,0 +1 @@
uid://cgy4anjdob2tp