-
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
71f1457
commit d98e613
Showing
40 changed files
with
976 additions
and
38 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@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 | ||
|
||
## Whether the rumble can be active during a tree pause | ||
@export var active_during_pause: bool = false | ||
|
||
@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 |
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,161 @@ | ||
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. | ||
|
||
|
||
## Name in the OpenXR Action Map for haptics | ||
const HAPTIC_ACTION := &"haptic" # TODO: Migrate | ||
|
||
# Shorthand for all trackers, in use to be substituted with _queues.keys() | ||
const ALL_TRACKERS := [&"all"] | ||
|
||
|
||
# A Queue Per Haptic device (Dictionary<StringName, XRToolsRumbleManagerQueue>) | ||
var _queues: Dictionary = {} | ||
|
||
|
||
## Add support for is_xr_class | ||
func is_xr_class(p_name: String) -> bool: | ||
return p_name == "XRToolsRumbleManager" | ||
|
||
|
||
## Get the default Haptics Scale value | ||
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 | ||
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) | ||
|
||
|
||
# On Ready | ||
func _ready(): | ||
if Engine.is_editor_hint(): | ||
return | ||
|
||
# Some rumble events are active during pause | ||
process_mode = PROCESS_MODE_ALWAYS | ||
|
||
# Create a queues for standard controllers | ||
_queues[&"left_hand"] = XRToolsRumbleManagerQueue.new() | ||
_queues[&"right_hand"] = XRToolsRumbleManagerQueue.new() | ||
|
||
|
||
# Determine how much to - and perform the - rumbles each tick | ||
func _process(delta: float) -> void: | ||
if Engine.is_editor_hint(): | ||
return | ||
|
||
# We'll be subtracting this from the event remaining ms | ||
var delta_ms = int(delta * 1000) | ||
|
||
for tracker_name in _queues: | ||
var haptic_queue : XRToolsRumbleManagerQueue = _queues[tracker_name] | ||
|
||
# default to noXRToolsRumbleManagerQueuensure it's a float, or it rounds to all or nothing!) | ||
var magnitude: float = 0.0 | ||
|
||
# Iterate over the events | ||
for key in haptic_queue.events.keys(): | ||
var event : XRToolsRumbleEvent = haptic_queue.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 haptic_queue.time_remaining[key] < 0: | ||
clear(key, [tracker_name]) | ||
continue | ||
|
||
# Reduce the time remaining | ||
haptic_queue.time_remaining[key] -= delta_ms | ||
|
||
# If it's of greater magnitude, update left magnitude to be set | ||
if event.magnitude > magnitude: | ||
magnitude = event.magnitude | ||
|
||
# scale the final magnitude | ||
magnitude *= XRToolsUserSettings.haptics_scale | ||
|
||
# Make that tracker rumble | ||
if magnitude > 0: | ||
XRServer.primary_interface.trigger_haptic_pulse( | ||
HAPTIC_ACTION, | ||
tracker_name, # if the tracker name isn't valid, it will error but continue | ||
0, | ||
magnitude, | ||
0.1, | ||
0) | ||
|
||
|
||
# Add an event | ||
func add(event_key: Variant, event: XRToolsRumbleEvent, | ||
trackers: Array = ALL_TRACKERS) -> void: | ||
if not event_key: | ||
push_error("Event key is invalid!") | ||
return | ||
|
||
if not event: | ||
clear(event_key, trackers) | ||
return | ||
|
||
# Substitube the shorthand for all trackers with the real thing | ||
if trackers == ALL_TRACKERS: | ||
trackers = _queues.keys() | ||
|
||
for tracker in trackers: | ||
if tracker is XRNode3D: | ||
tracker = tracker.tracker | ||
|
||
# Create queue first time a target is suggested | ||
if not _queues.has(tracker): | ||
_queues[tracker] = XRToolsRumbleManagerQueue.new() | ||
|
||
# Add the event and it's remaining time to the respective queues | ||
_queues[tracker].events[event_key] = event | ||
_queues[tracker].time_remaining[event_key] = event.duration_ms | ||
|
||
|
||
# Remove an event | ||
func clear(event_key: Variant, trackers: Array = ALL_TRACKERS) -> void: | ||
if not event_key: | ||
push_error("Event key is invalid!") | ||
return | ||
|
||
# Substitube the shorthand for all trackers with the real thing | ||
if trackers == ALL_TRACKERS: | ||
trackers = _queues.keys() | ||
|
||
for tracker in trackers: | ||
if tracker is XRNode3D: | ||
tracker = tracker.tracker | ||
|
||
# Ignore if the queue doesn't exist | ||
if not _queues.has(tracker): | ||
continue | ||
|
||
# Remove the event and it's remaining time from the respective queues | ||
_queues[tracker].events.erase(event_key) | ||
_queues[tracker].time_remaining.erase(event_key) |
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,12 @@ | ||
class_name XRToolsRumbleManagerQueue | ||
extends Resource | ||
|
||
# All currently-active events (Dictionary<Variant, XRToolsRumbleEvent>) | ||
var events: Dictionary | ||
|
||
# All currently-active events' time remaining (Dictionary<Variant, int>) | ||
var time_remaining: Dictionary | ||
|
||
func _init(): | ||
events = {} | ||
time_remaining = {} |
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,76 @@ | ||
@tool | ||
@icon("res://addons/godot-xr-tools/editor/icons/rumble.svg") | ||
class_name XRToolsRumbler | ||
extends Node | ||
|
||
## XR Tools Rumbler | ||
## | ||
## A node you attach to handle (contain and make easy to activate/cancel) | ||
## a particular rumble event. | ||
|
||
## The details of this rumbler | ||
@export var event: XRToolsRumbleEvent : set = _set_event | ||
|
||
@export var target: XRNode3D | ||
|
||
## Activate the event | ||
func rumble() -> void: | ||
if is_instance_valid(target): | ||
XRToolsRumbleManager.add(self, event, [target.tracker]) | ||
|
||
|
||
## Cancel the event | ||
func cancel() -> void: | ||
XRToolsRumbleManager.clear(self) | ||
|
||
|
||
## Rumble on the hand which owns the node | ||
func rumble_hand(hand_child: Node3D) -> void: | ||
var hand: XRNode3D = XRHelpers.get_xr_controller(hand_child) | ||
if is_instance_valid(hand): | ||
XRToolsRumbleManager.add(self, event, [hand.tracker]) | ||
|
||
|
||
## Cancel rumble for the hand which owns the node | ||
func cancel_hand(hand_child: Node3D) -> void: | ||
var hand: XRNode3D = XRHelpers.get_xr_controller(hand_child) | ||
if is_instance_valid(hand): | ||
XRToolsRumbleManager.clear(self, [hand.tracker]) | ||
|
||
|
||
## Activate the event, if provided the XR player body | ||
func rumble_if_player_body(body: Node3D) -> void: | ||
if is_instance_valid(body) and body is XRToolsPlayerBody: | ||
rumble() | ||
|
||
|
||
## Cancel rumble for the event, if provided the XR player body | ||
func cancel_if_player_body(body: Node3D) -> void: | ||
if is_instance_valid(body) and body is XRToolsPlayerBody: | ||
cancel() | ||
|
||
|
||
## Activate the event during an active pointer event | ||
func rumble_pointer(event : XRToolsPointerEvent) -> void: | ||
if event.event_type == XRToolsPointerEvent.Type.PRESSED: | ||
rumble_hand(event.pointer) | ||
elif event.event_type == XRToolsPointerEvent.Type.RELEASED: | ||
cancel_hand(event.pointer) | ||
|
||
|
||
func _set_event(p_event: XRToolsRumbleEvent) -> void: | ||
event = p_event | ||
update_configuration_warnings() | ||
|
||
|
||
# This method verifies the hand has a valid configuration. | ||
func _get_configuration_warnings() -> PackedStringArray: | ||
var warnings := PackedStringArray() | ||
|
||
# Check hand for animation player | ||
if not event: | ||
warnings.append("Rumbler must have a rumble event") | ||
|
||
# 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,10 @@ | ||
[gd_resource type="Resource" script_class="XRToolsRumbleEvent" load_steps=2 format=3 uid="uid://brci6umrcd157"] | ||
|
||
[ext_resource type="Script" path="res://addons/godot-xr-tools/rumble/rumble_event.gd" id="1_r2qd4"] | ||
|
||
[resource] | ||
script = ExtResource("1_r2qd4") | ||
magnitude = 0.5 | ||
active_during_pause = true | ||
indefinite = false | ||
duration_ms = 10 |
Oops, something went wrong.