175 lines
5.4 KiB
GDScript
175 lines
5.4 KiB
GDScript
@tool
|
|
class_name VibrationComponent
|
|
extends Node
|
|
|
|
## A small helper node to quickly perform controller vibrations.
|
|
|
|
#signal started_vibration
|
|
|
|
# TODO: Add vibrations on top of one another if they play at the same- or similar time.
|
|
#static var total_weak_vibration: float = 0.0
|
|
#static var total_strong_vibration: float = 0.0
|
|
#static var _vibration_handled: bool = false
|
|
static var min_weak_magnitude_threshold: float = 0.0
|
|
static var min_strong_magnitude_threshold: float = 0.0
|
|
static var min_duration_threshold: float = 0.0
|
|
|
|
## If [code]false[/code], calling [method vibrate] will not start a controller vibration.
|
|
@export var enabled: bool = true:
|
|
get = is_enabled,
|
|
set = set_enabled
|
|
## [param duration] is the duration of the effect in seconds
|
|
## (a duration of [code]0[/code] will try to play the vibration indefinitely).[br]
|
|
## The vibration can be stopped early by calling [method stop_vibration].
|
|
@export var duration: float = 0.15:
|
|
get = get_duration,
|
|
set = set_duration
|
|
## The device index to perform the vibration on.
|
|
@export var device: int = 0:
|
|
get = get_device,
|
|
set = set_device
|
|
## Delay the vibration by this amount.
|
|
@export var delay: float = 0.0
|
|
@export var sync_to_audio: bool = false
|
|
|
|
#region Editor tooling
|
|
@warning_ignore_start("unused_private_class_variable")
|
|
@export_tool_button("Test Vibration", "InputEventJoypadMotion")
|
|
var _editor_test_vibration: Callable = vibrate
|
|
@export_tool_button("Stop Vibration", "MissingNode")
|
|
var _editor_stop_test_vibration: Callable = stop_vibration
|
|
@warning_ignore_restore("unused_private_class_variable")
|
|
#endregion
|
|
|
|
@export_group("Magnitude")
|
|
## [param weak_magnitude] is the strength of the weak motor
|
|
## (between [code]0[/code] and [code]1[/code]).
|
|
@export_range(0.0, 1.0) var weak_magnitude: float = 0.1:
|
|
get = get_weak_magnitude,
|
|
set = set_weak_magnitude
|
|
## [param strong_magnitude] is the strength of the strong motor
|
|
## (between [code]0[/code] and [code]1[/code]).
|
|
@export_range(0.0, 1.0) var strong_magnitude: float = 0.2:
|
|
get = get_strong_magnitude,
|
|
set = set_strong_magnitude
|
|
## Multiplies [member weak_magnitude] and [member strong_magnitude] by this amount.
|
|
@export var magnitude_multiplier: float = 1.0:
|
|
get = get_magnitude_multiplier,
|
|
set = set_magnitude_multiplier
|
|
|
|
var animated_weak_magnitude: float = 0.0:
|
|
set(value):
|
|
animated_weak_magnitude = clampf(value, 0.0, 1.0)
|
|
var animated_strong_magnitude: float = 0.0:
|
|
set(value):
|
|
animated_strong_magnitude = clampf(value, 0.0, 1.0)
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
if (
|
|
can_vibrate()
|
|
and not is_zero_approx(animated_weak_magnitude + animated_strong_magnitude)
|
|
):
|
|
var _weak_magnitude: float = animated_weak_magnitude
|
|
var _strong_magnitude: float = animated_strong_magnitude
|
|
|
|
_weak_magnitude = remap(_weak_magnitude, 0.0, 1.0, min_weak_magnitude_threshold * float(_weak_magnitude > 0.0), 1.0)
|
|
_strong_magnitude = remap(_strong_magnitude, 0.0, 1.0, min_strong_magnitude_threshold * float(_strong_magnitude > 0.0), 1.0)
|
|
|
|
Input.start_joy_vibration.call_deferred(device, _weak_magnitude, _strong_magnitude, delta)
|
|
animated_weak_magnitude = 0.0
|
|
animated_strong_magnitude = 0.0
|
|
|
|
|
|
## Performs the controller vibration based on given parameters of the component.[br]
|
|
## [b]Info[/b]: The [member enabled] parameter must be [code]true[/code].
|
|
func vibrate() -> void:
|
|
if not can_vibrate():
|
|
return
|
|
|
|
if delay > 0.0:
|
|
await get_tree().create_timer(delay).timeout
|
|
|
|
if sync_to_audio:
|
|
var last_mix_time: float = AudioServer.get_time_since_last_mix()
|
|
var output_latency: float = AudioServer.get_output_latency()
|
|
#SPrint.print_msg("Audio Delay: %s" % (last_mix_time + output_latency))
|
|
await get_tree().create_timer(last_mix_time + output_latency).timeout
|
|
|
|
var _weak_magnitude: float = clampf(weak_magnitude * magnitude_multiplier, 0.0, 1.0)
|
|
var _strong_magnitude: float = clampf(strong_magnitude * magnitude_multiplier, 0.0, 1.0)
|
|
|
|
_weak_magnitude = remap(_weak_magnitude, 0.0, 1.0, min_weak_magnitude_threshold * float(_weak_magnitude > 0.0), 1.0)
|
|
_strong_magnitude = remap(_strong_magnitude, 0.0, 1.0, min_strong_magnitude_threshold * float(_strong_magnitude > 0.0), 1.0)
|
|
duration = maxf(duration, min_duration_threshold)
|
|
|
|
Input.start_joy_vibration(device, _weak_magnitude, _strong_magnitude, duration)
|
|
|
|
#started_vibration.emit()
|
|
|
|
|
|
## Stops the vibration of the joypad, based on the [member device] parameter,
|
|
## started with [method vibrate].
|
|
func stop_vibration() -> void:
|
|
Input.stop_joy_vibration(device)
|
|
|
|
|
|
## Don't vibrate if the user has it turned off.
|
|
func can_vibrate() -> bool:
|
|
if not Engine.is_editor_hint():
|
|
if (
|
|
not InputManager.using_controller
|
|
#or not ProjectSettings.get_setting("game/input/controller_vibrations", true)
|
|
):
|
|
return false
|
|
|
|
return enabled
|
|
|
|
|
|
func set_enabled(value: bool) -> void:
|
|
enabled = value
|
|
|
|
|
|
func is_enabled() -> bool:
|
|
return enabled
|
|
|
|
|
|
func set_device(device_id: int) -> void:
|
|
device = device_id
|
|
|
|
|
|
func get_device() -> int:
|
|
return device
|
|
|
|
|
|
func set_duration(length: float) -> void:
|
|
duration = length
|
|
|
|
|
|
func get_duration() -> float:
|
|
return duration
|
|
|
|
|
|
func set_magnitude_multiplier(multiplier_value: float) -> void:
|
|
magnitude_multiplier = multiplier_value
|
|
|
|
|
|
func get_magnitude_multiplier() -> float:
|
|
return magnitude_multiplier
|
|
|
|
|
|
func set_weak_magnitude(weak_value: float) -> void:
|
|
weak_magnitude = weak_value
|
|
|
|
|
|
func get_weak_magnitude() -> float:
|
|
return weak_magnitude
|
|
|
|
|
|
func set_strong_magnitude(strong_value: float) -> void:
|
|
strong_magnitude = strong_value
|
|
|
|
|
|
func get_strong_magnitude() -> float:
|
|
return strong_magnitude
|