Skip to content

Commit

Permalink
Added multi-touch support
Browse files Browse the repository at this point in the history
Changed pointer-event dispatching
Added multi-touch events to viewport_2d_in_3d
Modified virtual-keyboard to use TouchScreenButton
Modified pointer-demo to demonstrate multiple function pointers
Added ability to suppress XRToolsFunctionPointer when close to bodies/areas
Moved laser-pointer to extend out of index finder
  • Loading branch information
Malcolmnixon committed Aug 21, 2023
1 parent ab13127 commit 8b474fd
Show file tree
Hide file tree
Showing 24 changed files with 1,145 additions and 855 deletions.
4 changes: 3 additions & 1 deletion VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
- Added "UI Objects" layer 23 for viewports to support interaction by pointer and poking
- Fixed player scaling issues with crouching and poke
- **minor-breakage** Added support for passing user data between staged scenes with default handling for spawn-points

- Change pointer event dispatching
- Added multi-touch on 2D in 3D viewports and virtual-keyboard
- Added option to disable laser-pointers when close to specific bodies/areas

# 4.1.0
- Enhanced grappling to support collision and target layers
Expand Down
134 changes: 134 additions & 0 deletions addons/godot-xr-tools/events/pointer_event.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
class_name XRToolsPointerEvent

## Types of pointer events
enum Type {
## Pointer entered target
ENTERED,

## Pointer exited target
EXITED,

## Pointer pressed target
PRESSED,

## Pointer released target
RELEASED,

## Pointer moved on target
MOVED
}

## Type of pointer event
var event_type : Type

## Pointer generating event
var pointer : Node3D

## Target of pointer
var target : Node3D

## Point position
var position : Vector3

## Last point position
var last_position : Vector3


## Initialize a new instance of the XRToolsPointerEvent class
func _init(
p_event_type : Type,
p_pointer : Node3D,
p_target : Node3D,
p_position : Vector3,
p_last_position : Vector3) -> void:
event_type = p_event_type
pointer = p_pointer
target = p_target
position = p_position
last_position = p_last_position


## Report a pointer entered event
static func entered(
pointer : Node3D,
target : Node3D,
at : Vector3) -> void:
report(
XRToolsPointerEvent.new(
Type.ENTERED,
pointer,
target,
at,
at))


## Report pointer moved event
static func moved(
pointer : Node3D,
target : Node3D,
to : Vector3,
from : Vector3) -> void:
report(
XRToolsPointerEvent.new(
Type.MOVED,
pointer,
target,
to,
from))


## Report pointer pressed event
static func pressed(
pointer : Node3D,
target : Node3D,
at : Vector3) -> void:
report(
XRToolsPointerEvent.new(
Type.PRESSED,
pointer,
target,
at,
at))


## Report pointer released event
static func released(
pointer : Node3D,
target : Node3D,
at : Vector3) -> void:
report(
XRToolsPointerEvent.new(
Type.RELEASED,
pointer,
target,
at,
at))


## Report a pointer exited event
static func exited(
pointer : Node3D,
target : Node3D,
last : Vector3) -> void:
report(
XRToolsPointerEvent.new(
Type.EXITED,
pointer,
target,
last,
last))


## Report a pointer event
static func report(event : XRToolsPointerEvent) -> void:
# Fire event on pointer
if is_instance_valid(event.pointer):
if event.pointer.has_signal("pointing_event"):
event.pointer.emit_signal("pointing_event", event)

# Fire event/method on the target if it's valid
if is_instance_valid(event.target):
if event.target.has_signal("pointer_event"):
event.target.emit_signal("pointer_event", event)
elif event.target.has_method("pointer_event"):
event.target.pointer_event(event)
145 changes: 54 additions & 91 deletions addons/godot-xr-tools/functions/function_pointer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,8 @@ extends Node3D
## [XRToolsInteractableBody].


## Signal emitted when the pointer enters the target
signal pointer_entered(target)

## Signal emitted when the pointer moves on the target
signal pointer_moved(target, from, to)

## Signal emitted when the pointer is pressed on the target
signal pointer_pressed(target, at)

## Signal emitted when the pointer is released on the target
signal pointer_released(target, at)

## Signal emitted when the pointer exits the target collision object
signal pointer_exited(target)
## Signal emitted when this object points at another object
signal pointing_event(event)


## Enumeration of laser show modes
Expand All @@ -47,14 +35,17 @@ enum LaserLength {
## Default pointer collision mask of 21:pointable and 23:ui-objects
const DEFAULT_MASK := 0b0000_0000_0101_0000_0000_0000_0000_0000

## Default pointer collision mask of 23:ui-objects
const SUPPRESS_MASK := 0b0000_0000_0100_0000_0000_0000_0000_0000


@export_group("General")

## Pointer enabled
@export var enabled : bool = true: set = set_enabled

## Y Offset for pointer
@export var y_offset : float = -0.05: set = set_y_offset
@export var y_offset : float = -0.013: set = set_y_offset

## Pointer distance
@export var distance : float = 10: set = set_distance
Expand Down Expand Up @@ -98,6 +89,14 @@ const DEFAULT_MASK := 0b0000_0000_0101_0000_0000_0000_0000_0000
## Enable pointer collision with areas
@export var collide_with_areas : bool = false: set = set_collide_with_areas

@export_group("Suppression")

## Suppress radius
@export var suppress_radius : float = 0.2: set = set_suppress_radius

## Suppress mask
@export_flags_3d_physics var suppress_mask : int = SUPPRESS_MASK: set = set_suppress_mask


## Current target node
var target : Node3D = null
Expand Down Expand Up @@ -174,6 +173,8 @@ func _ready():
_update_collision_mask()
_update_collide_with_bodies()
_update_collide_with_areas()
_update_suppress_radius()
_update_suppress_mask()


# Called on each frame to update the pickup
Expand All @@ -195,7 +196,11 @@ func _process(_delta):
# Find the new pointer target
var new_target : Node3D
var new_at : Vector3
if enabled and $RayCast.is_colliding():
var suppress_area := $SuppressArea
if (enabled and
not $SuppressArea.has_overlapping_bodies() and
not $SuppressArea.has_overlapping_areas() and
$RayCast.is_colliding()):
new_at = $RayCast.get_collision_point()
if target:
# Locked to 'target' even if we're colliding with something else
Expand All @@ -211,34 +216,34 @@ func _process(_delta):
# Handle pointer changes
if new_target and not last_target:
# Pointer entered new_target
_report_entered(new_target)
XRToolsPointerEvent.entered(self, new_target, new_at)

# Pointer moved on new_target
_report_moved(new_target, new_at, new_at)
# Pointer moved on new_target for the first time
XRToolsPointerEvent.moved(self, new_target, new_at, new_at)

# Update visible artifacts for hit
_visible_hit(new_at)
elif not new_target and last_target:
# Pointer exited last_target
_report_exited(last_target)
XRToolsPointerEvent.exited(self, last_target, last_collided_at)

# Update visible artifacts for miss
_visible_miss()
elif new_target != last_target:
# Pointer exited last_target
_report_exited(last_target)
XRToolsPointerEvent.exited(self, last_target, last_collided_at)

# Pointer entered new_target
_report_entered(new_target)
XRToolsPointerEvent.entered(self, new_target, new_at)

# Pointer moved on new_target
_report_moved(new_target, last_collided_at, new_at)
XRToolsPointerEvent.moved(self, new_target, new_at, new_at)

# Move visible artifacts
_visible_move(new_at)
elif new_at != last_collided_at:
# Pointer moved on new_target
_report_moved(new_target, last_collided_at, new_at)
XRToolsPointerEvent.moved(self, new_target, new_at, last_collided_at)

# Move visible artifacts
_visible_move(new_at)
Expand Down Expand Up @@ -339,6 +344,19 @@ func set_collide_with_areas(p_new_value : bool) -> void:
_update_collide_with_areas()


# Set suppress radius property
func set_suppress_radius(p_suppress_radius : float) -> void:
suppress_radius = p_suppress_radius
if is_inside_tree():
_update_suppress_radius()


func set_suppress_mask(p_suppress_mask : int) -> void:
suppress_mask = p_suppress_mask
if is_inside_tree():
_update_suppress_mask()


# Pointer Y offset update handler
func _update_y_offset() -> void:
$Laser.position.y = y_offset * _world_scale
Expand Down Expand Up @@ -377,6 +395,16 @@ func _update_collide_with_areas() -> void:
$RayCast.collide_with_areas = collide_with_areas


# Pointer suppress_radius update handler
func _update_suppress_radius() -> void:
$SuppressArea/CollisionShape3D.shape.radius = suppress_radius


# Pointer suppress_mask update handler
func _update_suppress_mask() -> void:
$SuppressArea.collision_mask = suppress_mask


# Pointer visible artifacts update handler
func _update_pointer() -> void:
if enabled and last_target:
Expand All @@ -391,14 +419,14 @@ func _button_pressed() -> void:
# Report pressed
target = $RayCast.get_collider()
last_collided_at = $RayCast.get_collision_point()
_report_pressed(target, last_collided_at)
XRToolsPointerEvent.pressed(self, target, last_collided_at)


# Pointer-activation button released handler
func _button_released() -> void:
if target:
# Report release
_report_released(target, last_collided_at)
XRToolsPointerEvent.released(self, target, last_collided_at)
target = null
last_collided_at = Vector3(0, 0, 0)

Expand Down Expand Up @@ -426,71 +454,6 @@ func _update_laser_active_material(hit : bool) -> void:
$Laser.set_surface_override_material(0, laser_material)


# Report events for pointer entering collision object
func _report_entered(node : Node3D) -> void:
# Fire entered event
pointer_entered.emit(node)

# Fire event/method on the node if it's valid
if is_instance_valid(node):
if node.has_signal("pointer_entered"):
node.emit_signal("pointer_entered")
elif node.has_method("pointer_entered"):
node.pointer_entered()


# Report events for pointer moved on node
func _report_moved(node : Node3D, from : Vector3, to : Vector3) -> void:
# Fire moved event
pointer_moved.emit(node, from, to)

# Fire event/method on the node if it's valid
if is_instance_valid(node):
if node.has_signal("pointer_moved"):
node.emit_signal("pointer_moved", from, to)
elif node.has_method("pointer_moved"):
node.pointer_moved(from, to)


# Report events for pointer pressed on 'node'
func _report_pressed(node : Node3D, at : Vector3) -> void:
# Fire pressed event
pointer_pressed.emit(node, at)

# Fire event/method on the node if it's valid
if is_instance_valid(node):
if node.has_signal("pointer_pressed"):
node.emit_signal("pointer_pressed", at)
elif node.has_method("pointer_pressed"):
node.pointer_pressed(at)


# Report events for pointer released on 'node'
func _report_released(node : Node3D, at : Vector3) -> void:
# Fire released event
pointer_released.emit(node, at)

# Fire event/method on the node if it's valid
if is_instance_valid(node):
if node.has_signal("pointer_released"):
node.emit_signal("pointer_released", at)
elif node.has_method("pointer_released"):
node.pointer_released(at)


# Report events for pointer exiting node
func _report_exited(node : Node3D) -> void:
# Fire exited event
pointer_exited.emit(node)

# Fire event/method on the node if it's valid
if is_instance_valid(node):
if node.has_signal("pointer_exited"):
node.emit_signal("pointer_exited")
elif node.has_method("pointer_exited"):
node.pointer_exited()


# Update the visible artifacts to show a hit
func _visible_hit(at : Vector3) -> void:
# Show target if enabled
Expand Down
Loading

0 comments on commit 8b474fd

Please sign in to comment.