-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
40a1d59
commit 1bdf7ef
Showing
35 changed files
with
974 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ | |
logs | ||
Thumbs.db | ||
android/ | ||
.venv/ |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
[remap] | ||
|
||
importer="texture" | ||
type="CompressedTexture2D" | ||
uid="uid://dsexrsb8t0vi2" | ||
path="res://.godot/imported/rumble.svg-104961f6551a931675972887ab17d2bc.ctex" | ||
metadata={ | ||
"vram_texture": false | ||
} | ||
|
||
[deps] | ||
|
||
source_file="res://addons/godot-xr-tools/editor/icons/rumble.svg" | ||
dest_files=["res://.godot/imported/rumble.svg-104961f6551a931675972887ab17d2bc.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=1.0 | ||
editor/scale_with_editor_scale=false | ||
editor/convert_colors_with_editor_theme=false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
@tool | ||
class_name XRToolsHandAwareRumbler | ||
extends XRToolsRumbler | ||
|
||
## Rumbler which determines hand at runtime | ||
|
||
func _ready(): | ||
if not event or Engine.is_editor_hint(): | ||
return | ||
event = event.duplicate() | ||
_assign_hand(XRHelpers.get_xr_controller(self)) | ||
|
||
|
||
func _assign_hand(controller: XRController3D) -> bool: | ||
if not is_instance_valid(controller) or not event: | ||
return false | ||
|
||
if controller.tracker == "left_hand": | ||
event.hand = XRToolsRumbleManager.Hand.LEFT | ||
else: | ||
event.hand = XRToolsRumbleManager.Hand.RIGHT | ||
return true | ||
|
||
|
||
## Rumble on the hand which owns the node | ||
func rumble_hand(hand_child: Node3D) -> void: | ||
if _assign_hand(XRHelpers.get_xr_controller(hand_child)): | ||
rumble() | ||
|
||
|
||
# This method verifies the hand has a valid configuration. | ||
func _get_configuration_warnings() -> PackedStringArray: | ||
var warnings := super() | ||
|
||
# Check hand for mesh instance | ||
if event and event.hand != XRToolsRumbleManager.Hand.BOTH: | ||
warnings.append("Hand-Aware Rumbler's Event must be set to 'Both'") | ||
|
||
# Return warnings | ||
return warnings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
@icon("res://addons/godot-xr-tools/editor/icons/rumble.svg") | ||
class_name XRToolsRumbleEvent | ||
extends Resource | ||
|
||
## XR Tools Rumble Event Resource | ||
|
||
## Strength of the rumbling | ||
@export_range(0, 1, 0.10) var magnitude: float = 0.5 | ||
|
||
## Which hand(s) | ||
@export var hand : XRToolsRumbleManager.Hand = XRToolsRumbleManager.Hand.BOTH | ||
|
||
@export_category("Timing") | ||
|
||
## Whether the rumble continues until cleared | ||
@export var indefinite: bool = false | ||
|
||
## Time to rumble (unless indefinite) | ||
@export_range(10, 4000, 10) var duration_ms: int = 300 | ||
|
||
@export_category("Hints") | ||
|
||
## Whether the rumble can be active during a tree pause | ||
@export var active_during_pause: bool = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
@tool | ||
@icon("res://addons/godot-xr-tools/editor/icons/rumble.svg") | ||
class_name XRToolsRumbleManager | ||
extends Node | ||
|
||
|
||
## XR Tools Rumble (Controllers) Manager Script | ||
## | ||
## This script uses the controller's existing rumble intensity variable, | ||
## and allows you to rumble the controller for a certain amount | ||
## of time 'beats'. | ||
## | ||
## Example: something hits you while you're mowing the lawn, | ||
## i.e. a short intense rumble happens during long low rumble. | ||
|
||
## Hand Specifier | ||
enum Hand { | ||
BOTH = 0, ## Rumble Both Hands | ||
LEFT = 1, ## Rumble Left Hand | ||
RIGHT = 2 ## Rumble Right Hand | ||
} | ||
|
||
|
||
## Name in the OpenXR Action Map for haptics | ||
const HAPTIC_ACTION = "haptic" | ||
|
||
|
||
## Initial "Wake-Up" Rumble Magnitude | ||
@export var wakeup_rumble : XRToolsRumbleEvent | ||
|
||
|
||
# All currently-active events (Dictionary<Variant, XRToolsRumbleEvent>) | ||
var _events: Dictionary = {} | ||
|
||
# All currently-active events' time remaining (Dictionary<Variant, int>) | ||
var _time_remaining: Dictionary = {} | ||
|
||
|
||
# Left Controller Reference | ||
@onready var _controller_left_node: XRController3D = XRHelpers.get_left_controller(self) | ||
|
||
# Right Controller Reference | ||
@onready var _controller_right_node: XRController3D = XRHelpers.get_right_controller(self) | ||
|
||
|
||
# Keep track of singular instance | ||
static var _instance: XRToolsRumbleManager | ||
|
||
|
||
## Add support for is_xr_class | ||
func is_xr_class(name: String) -> bool: | ||
return name == "XRToolsRumbleManager" | ||
|
||
|
||
## Get the default Haptics Scale value | ||
static func get_default_haptics_scale() -> float: | ||
var default = 1.0 | ||
|
||
# Check if the project has overridden the addon's default | ||
if ProjectSettings.has_setting("godot_xr_tools/input/haptics_scale"): | ||
default = ProjectSettings.get_setting("godot_xr_tools/input/haptics_scale") | ||
|
||
if default < 0.0 or default > 1.0: | ||
# out of bounds? reset to default | ||
default = 1.0 | ||
|
||
return default | ||
|
||
|
||
## Used to convert gamepad magnitudes to equivalent XR haptic magnitude | ||
static func combine_magnitudes(weak: float, strong: float) -> float: | ||
if strong >= 0.01: | ||
return 0.5 + clamp(strong / 2, 0.0, 0.5) | ||
return clamp(weak / 2, 0.0, 0.5) | ||
|
||
|
||
# Enforce singleton | ||
func _enter_tree(): | ||
if not is_instance_valid(_instance): | ||
_instance = self | ||
else: | ||
self.queue_free() | ||
|
||
|
||
# Clear instance if this is the singleton | ||
func _exit_tree(): | ||
if is_instance_valid(_instance) and _instance == self: | ||
_instance = null | ||
|
||
|
||
# On Ready | ||
func _ready(): | ||
# Some rumble events are active during pause | ||
process_mode = PROCESS_MODE_ALWAYS | ||
|
||
if wakeup_rumble: | ||
_add("wakeup", wakeup_rumble) | ||
|
||
|
||
# Determine how much to - and perform the - rumbles each tick | ||
func _process(delta: float) -> void: | ||
# default to no rumble (ensure it's a float, or it rounds to all or nothing!) | ||
var left_magnitude: float = 0.0 | ||
var right_magnitude: float = 0.0 | ||
|
||
# We'll be subtracting this from the event remaining ms | ||
var delta_ms = int(delta * 1000) | ||
|
||
# Iterate over the events | ||
for key in _events.keys(): | ||
var event : XRToolsRumbleEvent = _events[key] | ||
|
||
# if we're paused and it's not supposed to be active, skip | ||
if get_tree().paused and not event.active_during_pause: | ||
continue | ||
|
||
# If we've passed the threshold from positive to negative, the event is done | ||
if !event.indefinite and _time_remaining[key] < 0: | ||
_remove(key) | ||
continue | ||
|
||
# Reduce the time remaining | ||
_time_remaining[key] -= delta_ms | ||
|
||
# If it's a left or both hand - and of greater magnitude - update left magnitude to be set | ||
if event.hand != Hand.RIGHT and event.magnitude > left_magnitude: | ||
left_magnitude = event.magnitude | ||
|
||
# If it's a right or both hand - and of greater magnitude - update right magnitude to be set | ||
if event.hand != Hand.LEFT and event.magnitude > right_magnitude: | ||
right_magnitude = event.magnitude | ||
|
||
|
||
# now that we're done looping through the events, set the rumbles, scaled | ||
if is_instance_valid(_controller_left_node): | ||
_controller_left_node.trigger_haptic_pulse( | ||
HAPTIC_ACTION, | ||
0, | ||
left_magnitude * XRToolsUserSettings.haptics_scale, | ||
0.1, | ||
0) | ||
|
||
if is_instance_valid(_controller_right_node): | ||
_controller_right_node.trigger_haptic_pulse( | ||
HAPTIC_ACTION, | ||
0, | ||
right_magnitude * XRToolsUserSettings.haptics_scale, | ||
0.1, | ||
0) | ||
|
||
|
||
# actually set an event | ||
func _add(event_key: Variant, event: XRToolsRumbleEvent) -> void: | ||
if not event_key: | ||
push_error("Event key is invalid! ") | ||
return | ||
|
||
if not event: | ||
_remove(event_key) | ||
return | ||
|
||
_events[event_key] = event | ||
_time_remaining[event_key] = event.duration_ms | ||
|
||
|
||
## Adds the event to the list of currently-active rumbles | ||
static func add(event_key: Variant, event: XRToolsRumbleEvent): | ||
if is_instance_valid(event) and is_instance_valid(_instance): | ||
#gdlint:ignore = private-method-call | ||
_instance._add(event_key, event) | ||
|
||
|
||
# Actually remove an event | ||
func _remove(event_key: Variant) -> void: | ||
if event_key != null: | ||
_events.erase(event_key) | ||
_time_remaining.erase(event_key) | ||
|
||
|
||
## Removes the event from the list of currently-active rumbles | ||
static func clear(event_key: Variant): | ||
if is_instance_valid(_instance): | ||
#gdlint:ignore = private-method-call | ||
_instance._remove(event_key) |
Oops, something went wrong.