implement touch system
This commit is contained in:
parent
fdbd3f9d96
commit
9a4b493d72
|
@ -140,7 +140,7 @@ Thus I've decided to use a custom event system that is similar to the one used i
|
|||
| Group | Description |
|
||||
| -- | -- |
|
||||
| `entity` | Marks the object as being an entity placed in space |
|
||||
| `ui_focus` | The element can be focused |
|
||||
| `ui_focus` | The element can be focused, can be a parent |
|
||||
| `ui_focus_skip` | The focus will not be reset. Useful for keyboard |
|
||||
|
||||
|
||||
|
|
|
@ -16,16 +16,19 @@ shape = SubResource("BoxShape3D_vi3eg")
|
|||
|
||||
[node name="Previous" parent="." instance=ExtResource("1_8opk3")]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -0.07, 0, 0)
|
||||
focusable = true
|
||||
label = "skip_previous"
|
||||
icon = true
|
||||
|
||||
[node name="Play" parent="." instance=ExtResource("1_8opk3")]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -4.65661e-08, 0, 0)
|
||||
focusable = true
|
||||
label = "pause"
|
||||
icon = true
|
||||
|
||||
[node name="Next" parent="." instance=ExtResource("1_8opk3")]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.07, 0, 0)
|
||||
focusable = true
|
||||
label = "skip_next"
|
||||
icon = true
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ mesh = SubResource("BoxMesh_ir3co")
|
|||
[node name="Raycast" parent="XROrigin3D/XRControllerRight" instance=ExtResource("3_67lii")]
|
||||
|
||||
[node name="Hands" parent="XROrigin3D" node_paths=PackedStringArray("ray_left", "ray_right") instance=ExtResource("4_v8xu6")]
|
||||
transform = Transform3D(0.999968, -1.39576e-11, 0, 9.52038e-12, 0.999984, -2.59206e-11, -2.91038e-11, 5.22959e-11, 0.999984, 0, 0, 0)
|
||||
ray_left = NodePath("../XRControllerLeft/Raycast")
|
||||
ray_right = NodePath("../XRControllerRight/Raycast")
|
||||
|
||||
|
|
|
@ -2,15 +2,19 @@ extends Node3D
|
|||
|
||||
const Pointer = preload("res://lib/utils/pointer/pointer.gd")
|
||||
const Initiator = preload("res://lib/utils/pointer/initiator.gd")
|
||||
const Finger = preload("res://lib/utils/touch/finger.gd")
|
||||
const Touch = preload("res://lib/utils/touch/touch.gd")
|
||||
|
||||
@onready var hand_right: OpenXRHand = $XRHandRight
|
||||
@onready var hand_left: OpenXRHand = $XRHandLeft
|
||||
@export var ray_left: RayCast3D
|
||||
@export var ray_right: RayCast3D
|
||||
var initiator: Initiator = Initiator.new()
|
||||
var touch: Touch
|
||||
var pointer: Pointer
|
||||
var press_distance = 0.03
|
||||
var grip_distance = 0.05
|
||||
var grip_distance = 0.03
|
||||
var close_distance = 0.1
|
||||
|
||||
var pressed_left = false
|
||||
var pressed_right = false
|
||||
|
@ -18,6 +22,11 @@ var grabbed_left = false
|
|||
var grabbed_right = false
|
||||
|
||||
func _ready():
|
||||
touch = Touch.new({
|
||||
Finger.Type.INDEX_RIGHT: $XRHandRight/IndexTip/IndexArea
|
||||
})
|
||||
add_child(touch)
|
||||
|
||||
_ready_hand(hand_right)
|
||||
|
||||
func _ready_hand(hand: OpenXRHand):
|
||||
|
@ -40,31 +49,55 @@ func _process_hand(hand: OpenXRHand):
|
|||
var distance_trigger = index_tip.global_position.distance_to(thumb_tip.global_position)
|
||||
var distance_grab = middle_tip.global_position.distance_to(thumb_tip.global_position)
|
||||
|
||||
var distance_target = _ray.get_collision_point().distance_to(_ray.global_position)
|
||||
|
||||
var trigger_close = distance_trigger <= press_distance
|
||||
var grab_close = distance_grab <= grip_distance
|
||||
var distance_close = distance_target <= close_distance
|
||||
|
||||
if hand == hand_left:
|
||||
if distance_trigger <= press_distance && !pressed_left:
|
||||
initiator.on_press.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_left = true
|
||||
elif distance_trigger > press_distance && pressed_left:
|
||||
initiator.on_release.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_left = false
|
||||
|
||||
if distance_grab <= grip_distance && !grabbed_left:
|
||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||
grabbed_left = true
|
||||
elif distance_grab > grip_distance && grabbed_left:
|
||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||
grabbed_left = false
|
||||
|
||||
if !distance_close:
|
||||
if trigger_close && !pressed_left:
|
||||
initiator.on_press.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_left = true
|
||||
elif !trigger_close && pressed_left:
|
||||
initiator.on_release.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_left = false
|
||||
|
||||
if grab_close && !grabbed_left:
|
||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||
grabbed_left = true
|
||||
elif !grab_close && grabbed_left:
|
||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||
grabbed_left = false
|
||||
else:
|
||||
if trigger_close && !grabbed_right:
|
||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = true
|
||||
elif !trigger_close && grabbed_right:
|
||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = false
|
||||
else:
|
||||
if distance_trigger <= press_distance && !pressed_right:
|
||||
initiator.on_press.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_right = true
|
||||
elif distance_trigger > press_distance && pressed_right:
|
||||
initiator.on_release.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_right = false
|
||||
if !distance_close:
|
||||
if trigger_close && !pressed_right:
|
||||
initiator.on_press.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_right = true
|
||||
elif !trigger_close && pressed_right:
|
||||
initiator.on_release.emit(Initiator.EventType.TRIGGER)
|
||||
pressed_right = false
|
||||
|
||||
if distance_grab <= grip_distance && !grabbed_right:
|
||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = true
|
||||
elif distance_grab > grip_distance && grabbed_right:
|
||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = false
|
||||
if grab_close && !grabbed_right:
|
||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = true
|
||||
elif !grab_close && grabbed_right:
|
||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = false
|
||||
|
||||
else:
|
||||
if trigger_close && !grabbed_right:
|
||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = true
|
||||
elif !trigger_close && grabbed_right:
|
||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||
grabbed_right = false
|
|
@ -1,9 +1,16 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://bsx12q23v8apy"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://bsx12q23v8apy"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/system/hands/hands.gd" id="1_c4f76"]
|
||||
[ext_resource type="PackedScene" uid="uid://c0kow4g10wolq" path="res://assets/models/hands_steam/right_hand.glb" id="1_uekbj"]
|
||||
[ext_resource type="PackedScene" uid="uid://dt4ksvogfctkr" path="res://assets/models/hands_steam/left_hand.glb" id="2_n73lt"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_dopke"]
|
||||
radius = 0.001
|
||||
height = 0.02
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_wty44"]
|
||||
size = Vector3(0.0274034, 0.194213, 0.133443)
|
||||
|
||||
[node name="Hands" type="Node3D"]
|
||||
script = ExtResource("1_c4f76")
|
||||
|
||||
|
@ -62,6 +69,16 @@ external_skeleton = NodePath("../right_hand/Armature/Skeleton3D")
|
|||
[node name="Marker3D" type="Marker3D" parent="XRHandRight/IndexTip"]
|
||||
gizmo_extents = 0.02
|
||||
|
||||
[node name="IndexArea" type="Area3D" parent="XRHandRight/IndexTip"]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0.01)
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRHandRight/IndexTip/IndexArea"]
|
||||
transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0)
|
||||
shape = SubResource("CapsuleShape3D_dopke")
|
||||
|
||||
[node name="ThumbTip" type="BoneAttachment3D" parent="XRHandRight"]
|
||||
transform = Transform3D(0.937246, -0.0284254, 0.347508, -0.348179, -0.129158, 0.928488, 0.0184906, -0.991216, -0.130949, -0.0498677, -0.112777, -0.0230909)
|
||||
bone_name = "Thumb_Tip_R"
|
||||
|
@ -82,5 +99,14 @@ external_skeleton = NodePath("../right_hand/Armature/Skeleton3D")
|
|||
[node name="Marker3D" type="Marker3D" parent="XRHandRight/MiddleTip"]
|
||||
gizmo_extents = 0.02
|
||||
|
||||
[node name="AnimatableBody3D" type="AnimatableBody3D" parent="XRHandRight"]
|
||||
transform = Transform3D(1, 0, 4.7579e-13, 0, 1, 0, -3.16048e-12, 1.77636e-15, 1, 5.36442e-07, -9.16771e-10, 0.0208378)
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRHandRight/AnimatableBody3D"]
|
||||
transform = Transform3D(1, 0, 4.7579e-13, -1.16415e-10, 1, 0, -1.04364e-11, 1.77636e-15, 1, -0.0166854, -0.0757538, 4.16786e-07)
|
||||
shape = SubResource("BoxShape3D_wty44")
|
||||
|
||||
[editable path="XRHandLeft/left_hand"]
|
||||
[editable path="XRHandRight/right_hand"]
|
||||
|
|
|
@ -71,8 +71,8 @@ func create_key(key: Key):
|
|||
var key_node = button_scene.instantiate()
|
||||
|
||||
key_node.label = EventKey.key_to_string(key, caps)
|
||||
key_node.add_to_group("ui_focus_skip")
|
||||
key_node.get_node("Label").font_size = 32
|
||||
key_node.focusable = false
|
||||
key_node.font_size = 32
|
||||
key_node.set_meta("key", key)
|
||||
|
||||
return key_node
|
||||
|
|
|
@ -15,20 +15,23 @@ size = Vector3(0.79, 0.01, 0.26)
|
|||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0)
|
||||
script = ExtResource("1_maojw")
|
||||
|
||||
[node name="Backspace" parent="." groups=["ui_focus_skip"] instance=ExtResource("1_xdpwr")]
|
||||
[node name="Backspace" parent="." instance=ExtResource("1_xdpwr")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.66, 0, 0.02)
|
||||
focusable = false
|
||||
label = "backspace"
|
||||
icon = true
|
||||
metadata/key = 4194308
|
||||
|
||||
[node name="Caps" parent="." groups=["ui_focus_skip"] instance=ExtResource("1_xdpwr")]
|
||||
[node name="Caps" parent="." instance=ExtResource("1_xdpwr")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.06, 0, 0.15)
|
||||
focusable = false
|
||||
label = "keyboard_capslock"
|
||||
icon = true
|
||||
toggleable = true
|
||||
|
||||
[node name="Paste" parent="." groups=["ui_focus_skip"] instance=ExtResource("1_xdpwr")]
|
||||
[node name="Paste" parent="." instance=ExtResource("1_xdpwr")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.66, 0, 0.18)
|
||||
focusable = false
|
||||
label = "assignment"
|
||||
icon = true
|
||||
|
||||
|
|
|
@ -1,15 +1,32 @@
|
|||
@tool
|
||||
|
||||
extends StaticBody3D
|
||||
extends Node3D
|
||||
class_name Button3D
|
||||
|
||||
const Proxy = preload("res://lib/utils/proxy.gd")
|
||||
|
||||
signal on_button_down()
|
||||
signal on_button_up()
|
||||
|
||||
const IconFont = preload("res://assets/icons/icons.tres")
|
||||
|
||||
@onready var label_node: Label3D = $Label
|
||||
@onready var label_node: Label3D = $Body/Label
|
||||
@onready var finger_area: Area3D = $FingerArea
|
||||
|
||||
@export var focusable: bool = true:
|
||||
set(value):
|
||||
focusable = value
|
||||
if !is_node_ready(): await ready
|
||||
if value:
|
||||
$Body.add_to_group("ui_focus_skip")
|
||||
else:
|
||||
$Body.remove_from_group("ui_focus_skip")
|
||||
|
||||
@export var font_size: int = 10:
|
||||
set(value):
|
||||
font_size = value
|
||||
if !is_node_ready(): await ready
|
||||
label_node.font_size = value
|
||||
@export var label: String = "":
|
||||
set(value):
|
||||
label = value
|
||||
|
@ -25,30 +42,44 @@ const IconFont = preload("res://assets/icons/icons.tres")
|
|||
label_node.font_size = 48
|
||||
label_node.width = 1000
|
||||
label_node.autowrap_mode = TextServer.AUTOWRAP_OFF
|
||||
else:
|
||||
label_node.font = null
|
||||
label_node.font_size = font_size
|
||||
label_node.width = 50
|
||||
label_node.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
|
||||
|
||||
@export var toggleable: bool = false
|
||||
@export var disabled: bool = false
|
||||
@export var external_state: bool = false
|
||||
@export var initial_active: bool = false
|
||||
var active: bool = false :
|
||||
var external_value: Proxy = null
|
||||
var active: bool = false:
|
||||
get:
|
||||
if external_value != null:
|
||||
return external_value.value
|
||||
return active
|
||||
set(value):
|
||||
animation_player.stop()
|
||||
if value == active:
|
||||
return
|
||||
|
||||
active = value
|
||||
|
||||
if active:
|
||||
animation_player.play("down")
|
||||
if external_value != null:
|
||||
external_value.value = value
|
||||
else:
|
||||
animation_player.play_backwards("down")
|
||||
active = value
|
||||
update_animation()
|
||||
|
||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||
|
||||
func _ready():
|
||||
if initial_active:
|
||||
active = true
|
||||
|
||||
func update_animation():
|
||||
print(1)
|
||||
var length = animation_player.get_animation("down").length
|
||||
|
||||
if active && animation_player.current_animation_position != length:
|
||||
print(2)
|
||||
animation_player.play("down")
|
||||
elif !active && animation_player.current_animation_position != 0:
|
||||
print(3)
|
||||
animation_player.play_backwards("down")
|
||||
|
||||
func _on_press_down(event):
|
||||
if disabled:
|
||||
|
@ -57,22 +88,17 @@ func _on_press_down(event):
|
|||
|
||||
AudioPlayer.play_effect("click")
|
||||
|
||||
if external_state || toggleable:
|
||||
if toggleable:
|
||||
return
|
||||
|
||||
active = true
|
||||
on_button_down.emit()
|
||||
|
||||
|
||||
|
||||
func _on_press_up(event):
|
||||
if disabled:
|
||||
event.bubbling = false
|
||||
return
|
||||
|
||||
if external_state:
|
||||
return
|
||||
|
||||
if toggleable:
|
||||
active = !active
|
||||
|
||||
|
@ -83,3 +109,53 @@ func _on_press_up(event):
|
|||
else:
|
||||
active = false
|
||||
on_button_up.emit()
|
||||
|
||||
func _on_touch_enter(event: EventTouch):
|
||||
animation_player.stop()
|
||||
animation_player.speed_scale = 0
|
||||
animation_player.current_animation = "down"
|
||||
_touch_change(event)
|
||||
|
||||
func _on_touch_move(event: EventTouch):
|
||||
_touch_change(event)
|
||||
|
||||
func _on_touch_leave(_event: EventTouch):
|
||||
animation_player.stop()
|
||||
animation_player.speed_scale = 1
|
||||
|
||||
if toggleable:
|
||||
active = !active
|
||||
if active:
|
||||
on_button_up.emit()
|
||||
else:
|
||||
on_button_down.emit()
|
||||
|
||||
|
||||
func _touch_change(event: EventTouch):
|
||||
if disabled:
|
||||
event.bubbling = false
|
||||
return
|
||||
|
||||
var pos = Vector3(0, 1, 0)
|
||||
for finger in event.fingers:
|
||||
var finger_pos = to_local(finger.area.global_position)
|
||||
if pos.y > finger_pos.y:
|
||||
pos = finger_pos
|
||||
|
||||
var button_height = finger_area.get_node("CollisionShape3D").shape.size.y
|
||||
var button_center = finger_area.position.y
|
||||
|
||||
var percent = clamp((button_center + button_height / 2 - pos.y) / (button_height / 2), 0, 1)
|
||||
|
||||
if !active && percent < 1:
|
||||
on_button_down.emit()
|
||||
elif active && percent >= 1:
|
||||
on_button_up.emit()
|
||||
|
||||
animation_player.seek(percent * animation_player.current_animation_length, true)
|
||||
|
||||
if toggleable:
|
||||
return
|
||||
|
||||
active = percent < 1
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=8 format=3 uid="uid://bsjqdvkt0u87c"]
|
||||
[gd_scene load_steps=9 format=3 uid="uid://bsjqdvkt0u87c"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/ui/components/button/button.gd" id="1_74x7g"]
|
||||
[ext_resource type="ArrayMesh" uid="uid://iv4lk77axlk4" path="res://assets/immersive_home/button.obj" id="2_cve3l"]
|
||||
|
@ -15,60 +15,50 @@ length = 0.001
|
|||
tracks/0/type = "bezier"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position:y")
|
||||
tracks/0/path = NodePath("Body:scale:y")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"handle_modes": PackedInt32Array(0),
|
||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
|
||||
"points": PackedFloat32Array(1, -0.25, 0, 0.25, 0),
|
||||
"times": PackedFloat32Array(0)
|
||||
}
|
||||
tracks/1/type = "bezier"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("MeshInstance3D:position:y")
|
||||
tracks/1/path = NodePath("Body:position:y")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"handle_modes": PackedInt32Array(0),
|
||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
|
||||
"points": PackedFloat32Array(0.01, -0.25, 0, 0.25, 0),
|
||||
"times": PackedFloat32Array(0)
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_iu2ed"]
|
||||
resource_name = "down"
|
||||
length = 0.2
|
||||
step = 0.01
|
||||
tracks/0/type = "bezier"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position:y")
|
||||
tracks/0/path = NodePath("Body:scale:y")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"handle_modes": PackedInt32Array(0, 0),
|
||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, -0.01, -0.25, 0, 0.25, 0),
|
||||
"points": PackedFloat32Array(1, -0.25, 0, 0.12, -0.00966179, 0.500747, -0.13, 0.00874269, 0.25, 0),
|
||||
"times": PackedFloat32Array(0, 0.2)
|
||||
}
|
||||
tracks/1/type = "bezier"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("MeshInstance3D:mesh:size:y")
|
||||
tracks/1/path = NodePath("Body:position:y")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"handle_modes": PackedInt32Array(0, 0),
|
||||
"points": PackedFloat32Array(0.02, -0.25, 0, 0.25, 0, 0.01, -0.25, 0, 0.25, 0),
|
||||
"times": PackedFloat32Array(0, 0.2)
|
||||
}
|
||||
tracks/2/type = "bezier"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("MeshInstance3D:position:y")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"handle_modes": PackedInt32Array(0, 0),
|
||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0.005, -0.25, 0, 0.25, 0),
|
||||
"points": PackedFloat32Array(0.0101447, -0.25, 0, 0.12, 0.000134136, 0.0051993, -0.12, 0.000145131, 0.25, 0),
|
||||
"times": PackedFloat32Array(0, 0.2)
|
||||
}
|
||||
|
||||
|
@ -78,28 +68,45 @@ _data = {
|
|||
"down": SubResource("Animation_iu2ed")
|
||||
}
|
||||
|
||||
[node name="Button" type="StaticBody3D" groups=["ui_focus"]]
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_bqjii"]
|
||||
size = Vector3(0.0501598, 0.0195937, 0.0501598)
|
||||
|
||||
[node name="Button" type="Node3D" groups=["ui_focus"]]
|
||||
script = ExtResource("1_74x7g")
|
||||
focusable = null
|
||||
label = "Example Text"
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0)
|
||||
[node name="Body" type="StaticBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.01, 0)
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Body"]
|
||||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, -0.005, 0)
|
||||
mesh = ExtResource("2_cve3l")
|
||||
skeleton = NodePath("../..")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_8s8ln")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Body"]
|
||||
shape = SubResource("ConvexPolygonShape3D_o4j7g")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_sbgno")
|
||||
}
|
||||
|
||||
[node name="Label" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.011, 0)
|
||||
[node name="Label" type="Label3D" parent="Body"]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.005, 0)
|
||||
pixel_size = 0.001
|
||||
text = "Example Text"
|
||||
font_size = 10
|
||||
outline_size = 0
|
||||
autowrap_mode = 3
|
||||
width = 50.0
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_sbgno")
|
||||
}
|
||||
|
||||
[node name="FingerArea" type="Area3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0101447, 0)
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
monitoring = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="FingerArea"]
|
||||
shape = SubResource("BoxShape3D_bqjii")
|
||||
|
|
|
@ -68,6 +68,10 @@ func _process(_delta):
|
|||
if get_tree().debug_collisions_hint && OS.get_name() != "Android":
|
||||
_draw_debug_text_gaps()
|
||||
|
||||
func _on_press_down(event):
|
||||
var pos_x = label.to_local(event.ray.get_collision_point()).x
|
||||
text_handler.update_caret_position(pos_x)
|
||||
|
||||
func _on_press_move(event):
|
||||
var ray_pos = event.ray.global_position
|
||||
var ray_dir = -event.ray.global_transform.basis.z
|
||||
|
@ -86,10 +90,7 @@ func _on_press_move(event):
|
|||
caret.position.x = text_handler.get_caret_position()
|
||||
label.text = text_handler.get_display_text()
|
||||
|
||||
func _on_focus_in(event):
|
||||
var pos_x = label.to_local(event.ray.get_collision_point()).x
|
||||
text_handler.update_caret_position(pos_x)
|
||||
|
||||
func _on_focus_in(_event):
|
||||
caret.position.x = text_handler.get_caret_position()
|
||||
label.text = text_handler.get_display_text()
|
||||
caret.show()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends Object
|
||||
extends RefCounted
|
||||
|
||||
var label: Label3D
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
script = ExtResource("1_rbo86")
|
||||
|
||||
[node name="Button" parent="." instance=ExtResource("2_go2es")]
|
||||
focusable = true
|
||||
|
||||
[node name="Clickable" type="Node" parent="."]
|
||||
script = ExtResource("3_6wicx")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
extends Node3D
|
||||
|
||||
const Device = preload("./device/device.tscn")
|
||||
const Entity = preload("./entity/entity.tscn")
|
||||
const ButtonScene = preload("res://content/ui/components/button/button.tscn")
|
||||
const EntityCreator = preload("./entity_creator.gd")
|
||||
|
||||
@onready var devices_node: GridContainer3D = $Devices
|
||||
|
@ -101,33 +100,33 @@ func render_devices():
|
|||
for device in page_devices:
|
||||
var info = device.values()[0]
|
||||
|
||||
var device_instance = Device.instantiate()
|
||||
device_instance.id = device.keys()[0]
|
||||
device_instance.get_node("Clickable").on_click.connect(func(_event):
|
||||
_on_device_click(device_instance.id)
|
||||
var button_instance = ButtonScene.instantiate()
|
||||
button_instance.label = info["name"]
|
||||
button_instance.on_button_down.connect(func():
|
||||
_on_device_click(device.keys()[0])
|
||||
)
|
||||
devices_node.add_child(device_instance)
|
||||
device_instance.set_device_name.call_deferred(info["name"])
|
||||
devices_node.add_child(button_instance)
|
||||
|
||||
devices_node._update_container()
|
||||
|
||||
func render_entities():
|
||||
var entities = get_page()
|
||||
|
||||
var back_button = Entity.instantiate()
|
||||
back_button.get_node("Clickable").on_click.connect(func(_event):
|
||||
var back_button = ButtonScene.instantiate()
|
||||
back_button.label = "arrow_back"
|
||||
back_button.icon = true
|
||||
back_button.on_button_down.connect(func():
|
||||
_on_entity_click("#back")
|
||||
)
|
||||
devices_node.add_child(back_button)
|
||||
back_button.set_entity_name("#back")
|
||||
|
||||
for entity in entities:
|
||||
var entity_instance = Entity.instantiate()
|
||||
entity_instance.get_node("Clickable").on_click.connect(func(_event):
|
||||
var button_instance = ButtonScene.instantiate()
|
||||
button_instance.label = entity
|
||||
button_instance.on_button_down.connect(func():
|
||||
_on_entity_click(entity)
|
||||
)
|
||||
devices_node.add_child(entity_instance)
|
||||
entity_instance.set_entity_name(entity)
|
||||
devices_node.add_child(button_instance)
|
||||
|
||||
devices_node._update_container()
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://crrb0l3ekuotj"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://crrb0l3ekuotj"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/ui/menu/edit/edit_menu.gd" id="1_34cbn"]
|
||||
[ext_resource type="Script" path="res://content/ui/menu/grid.gd" id="3_0xvyw"]
|
||||
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="4_tvimg"]
|
||||
[ext_resource type="Script" path="res://content/functions/clickable.gd" id="6_pf8jy"]
|
||||
|
||||
[node name="EditMenu" type="Node3D"]
|
||||
script = ExtResource("1_34cbn")
|
||||
|
@ -26,16 +25,12 @@ outline_size = 0
|
|||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.19, 0.01, 0.27)
|
||||
|
||||
[node name="NextPageButton" parent="Buttons" instance=ExtResource("4_tvimg")]
|
||||
focusable = true
|
||||
label = "navigate_next"
|
||||
icon = true
|
||||
|
||||
[node name="Clickable" type="Node" parent="Buttons/NextPageButton"]
|
||||
script = ExtResource("6_pf8jy")
|
||||
|
||||
[node name="PreviousPageButton" parent="Buttons" instance=ExtResource("4_tvimg")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.08, 0, 0)
|
||||
focusable = true
|
||||
label = "navigate_before"
|
||||
icon = true
|
||||
|
||||
[node name="Clickable" type="Node" parent="Buttons/PreviousPageButton"]
|
||||
script = ExtResource("6_pf8jy")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends Object
|
||||
extends RefCounted
|
||||
|
||||
const Switch = preload("res://content/entities/switch/switch.tscn")
|
||||
const Light = preload("res://content/entities/light/light.tscn")
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
extends Node3D
|
||||
|
||||
const Proxy = preload("res://lib/utils/proxy.gd")
|
||||
|
||||
@onready var _controller := XRHelpers.get_xr_controller(self)
|
||||
|
||||
@onready var nav_view = $AnimationContainer/Navigation/View
|
||||
|
@ -34,10 +36,25 @@ func _ready():
|
|||
show_menu = !show_menu
|
||||
)
|
||||
|
||||
select_menu(nav_edit)
|
||||
var nav_buttons = [
|
||||
nav_view,
|
||||
nav_edit,
|
||||
nav_room,
|
||||
nav_automate,
|
||||
nav_settings
|
||||
]
|
||||
|
||||
func _on_click(event):
|
||||
select_menu(event.target)
|
||||
for nav_button in nav_buttons:
|
||||
var getter = func():
|
||||
return nav_button == selected_nav
|
||||
|
||||
var setter = func(value):
|
||||
if value:
|
||||
select_menu(nav_button)
|
||||
|
||||
nav_button.external_value = Proxy.new(getter, setter)
|
||||
|
||||
select_menu(nav_edit)
|
||||
|
||||
func select_menu(nav):
|
||||
if _is_valid_nav(nav) == false || selected_nav == nav:
|
||||
|
@ -46,13 +63,15 @@ func select_menu(nav):
|
|||
for child in content.get_children():
|
||||
content.remove_child(child)
|
||||
|
||||
if selected_nav != null:
|
||||
selected_nav.active = false
|
||||
var old_nav = selected_nav
|
||||
|
||||
selected_nav = nav
|
||||
|
||||
if old_nav != null:
|
||||
old_nav.update_animation()
|
||||
|
||||
if selected_nav != null:
|
||||
selected_nav.active = true
|
||||
selected_nav.update_animation()
|
||||
var menu = _nav_to_menu(selected_nav)
|
||||
if menu != null:
|
||||
content.add_child(menu)
|
||||
|
|
|
@ -165,38 +165,38 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0, 0)
|
|||
|
||||
[node name="View" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.03)
|
||||
focusable = true
|
||||
label = "visibility"
|
||||
icon = true
|
||||
toggleable = true
|
||||
external_state = true
|
||||
|
||||
[node name="Edit" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.09)
|
||||
focusable = true
|
||||
label = "widgets"
|
||||
icon = true
|
||||
toggleable = true
|
||||
external_state = true
|
||||
|
||||
[node name="Room" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.15)
|
||||
focusable = true
|
||||
label = "view_in_ar"
|
||||
icon = true
|
||||
toggleable = true
|
||||
external_state = true
|
||||
|
||||
[node name="Automate" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.21)
|
||||
focusable = true
|
||||
label = "schema"
|
||||
icon = true
|
||||
toggleable = true
|
||||
external_state = true
|
||||
|
||||
[node name="Settings" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.27)
|
||||
focusable = true
|
||||
label = "settings"
|
||||
icon = true
|
||||
toggleable = true
|
||||
external_state = true
|
||||
|
||||
[node name="Content" type="Node3D" parent="AnimationContainer"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0, 0)
|
||||
|
|
|
@ -18,6 +18,8 @@ script = ExtResource("1_ch4jb")
|
|||
[node name="TeleportRoot" type="Node3D" parent="."]
|
||||
|
||||
[node name="Ground" type="StaticBody3D" parent="TeleportRoot"]
|
||||
collision_layer = 5
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="TeleportRoot/Ground"]
|
||||
shape = SubResource("WorldBoundaryShape3D_08sv0")
|
||||
|
@ -44,6 +46,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.01, 0)
|
|||
|
||||
[node name="ToggleEdit" parent="Interface" instance=ExtResource("3_whl7a")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0, 0.05)
|
||||
focusable = true
|
||||
label = "room_preferences"
|
||||
icon = true
|
||||
toggleable = true
|
||||
|
|
|
@ -9,6 +9,8 @@ bounce = 0.7
|
|||
radius = 0.08
|
||||
|
||||
[node name="Ball" type="RigidBody3D"]
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
physics_material_override = SubResource("PhysicsMaterial_f6jtg")
|
||||
angular_damp = 4.0
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ extends Node3D
|
|||
const ball_scene = preload("./ball.tscn")
|
||||
const credits_scene = preload("./credits.tscn")
|
||||
|
||||
@onready var clickable = $Content/Button/Clickable
|
||||
@onready var ball_button = $Content/Button
|
||||
@onready var connection_status = $Content/ConnectionStatus
|
||||
|
||||
@onready var input_url = $Content/InputURL
|
||||
|
@ -15,10 +15,12 @@ const credits_scene = preload("./credits.tscn")
|
|||
func _ready():
|
||||
background.visible = false
|
||||
|
||||
clickable.on_click.connect(func(event):
|
||||
ball_button.on_button_down.connect(func():
|
||||
var ball = ball_scene.instantiate()
|
||||
ball.transform = event.controller.transform
|
||||
ball.linear_velocity = -event.controller.transform.basis.z * 5 + Vector3(0, 5, 0)
|
||||
var controller = XRHelpers.get_right_controller(self)
|
||||
|
||||
ball.transform = controller.transform
|
||||
ball.linear_velocity = -controller.transform.basis.z * 5 + Vector3(0, 5, 0)
|
||||
get_tree().root.add_child(ball)
|
||||
)
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ outline_size = 0
|
|||
|
||||
[node name="Button" parent="Content" instance=ExtResource("1_faxng")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0458097, 0, 0.253575)
|
||||
focusable = true
|
||||
label = "sports_basketball"
|
||||
icon = true
|
||||
|
||||
|
@ -84,6 +85,7 @@ horizontal_alignment = 0
|
|||
|
||||
[node name="Connect" parent="Content" instance=ExtResource("1_faxng")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.25, 0, 0.12)
|
||||
focusable = true
|
||||
label = "wifi"
|
||||
icon = true
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
extends Event
|
||||
class_name EventFocus
|
||||
|
||||
var ray: RayCast3D
|
||||
var target: Node
|
||||
var previous_target: Node
|
12
lib/events/event_touch.gd
Normal file
12
lib/events/event_touch.gd
Normal file
|
@ -0,0 +1,12 @@
|
|||
extends EventBubble
|
||||
class_name EventTouch
|
||||
|
||||
const Finger = preload("res://lib/utils/touch/finger.gd")
|
||||
|
||||
var fingers: Array[Finger] = []
|
||||
|
||||
func has_finger(finger: Finger.Type):
|
||||
for f in fingers:
|
||||
if f.type == finger:
|
||||
return true
|
||||
return false
|
|
@ -20,37 +20,40 @@ signal on_key_up(event: EventKey)
|
|||
signal on_focus_in(event: EventFocus)
|
||||
signal on_focus_out(event: EventFocus)
|
||||
|
||||
signal on_touch_enter(event: EventTouch)
|
||||
signal on_touch_move(event: EventTouch)
|
||||
signal on_touch_leave(event: EventTouch)
|
||||
|
||||
var _active_node: Node = null
|
||||
|
||||
func emit(type: String, event: Event):
|
||||
if event is EventBubble:
|
||||
_bubble_call(type, event.target, event)
|
||||
if type == "press_down":
|
||||
_handle_focus(event)
|
||||
else:
|
||||
_root_call(type, event)
|
||||
|
||||
func is_focused(node: Node):
|
||||
return _active_node == node
|
||||
|
||||
func _handle_focus(event: EventPointer):
|
||||
if event.target != null && event.target.is_in_group("ui_focus_skip"):
|
||||
func _handle_focus(event: EventBubble):
|
||||
var target = event.target
|
||||
|
||||
if target != null && target.is_in_group("ui_focus_skip"):
|
||||
return
|
||||
|
||||
var event_focus = EventFocus.new()
|
||||
event_focus.previous_target = _active_node
|
||||
event_focus.target = event.target
|
||||
event_focus.ray = event.ray
|
||||
event_focus.target = target
|
||||
|
||||
if _active_node != null && _active_node.has_method(FN_PREFIX + "focus_out"):
|
||||
_active_node.call(FN_PREFIX + "focus_out", event_focus)
|
||||
on_focus_out.emit(event_focus)
|
||||
|
||||
if event.target == null || event.target.is_in_group("ui_focus") == false:
|
||||
if target == null || target.is_in_group("ui_focus") == false:
|
||||
_active_node = null
|
||||
return
|
||||
|
||||
_active_node = event.target
|
||||
_active_node = target
|
||||
|
||||
if _active_node != null && _active_node.has_method(FN_PREFIX + "focus_in"):
|
||||
_active_node.call(FN_PREFIX + "focus_in", event_focus)
|
||||
|
@ -70,6 +73,9 @@ func _bubble_call(type: String, target: Variant, event: EventBubble):
|
|||
if event.bubbling == false:
|
||||
return false
|
||||
|
||||
if type == "press_down" || type == "touch_enter":
|
||||
_handle_focus(event)
|
||||
|
||||
for child in target.get_children():
|
||||
if child is Function && child.has_method(FN_PREFIX + type):
|
||||
child.call(FN_PREFIX + type, event)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends Object
|
||||
extends RefCounted
|
||||
|
||||
enum Type {
|
||||
CONTROLLER_LEFT,
|
||||
|
|
14
lib/utils/proxy.gd
Normal file
14
lib/utils/proxy.gd
Normal file
|
@ -0,0 +1,14 @@
|
|||
extends RefCounted
|
||||
|
||||
var gettable: Callable
|
||||
var settable: Callable
|
||||
|
||||
func _init(gettable: Callable, settable: Callable):
|
||||
self.gettable = gettable
|
||||
self.settable = settable
|
||||
|
||||
var value: Variant:
|
||||
get:
|
||||
return gettable.call()
|
||||
set(new_value):
|
||||
settable.call(new_value)
|
17
lib/utils/touch/finger.gd
Normal file
17
lib/utils/touch/finger.gd
Normal file
|
@ -0,0 +1,17 @@
|
|||
extends RefCounted
|
||||
|
||||
enum Type {
|
||||
THUMB_RIGHT,
|
||||
INDEX_RIGHT,
|
||||
MIDDLE_RIGHT,
|
||||
RING_RIGHT,
|
||||
LITTLE_RIGHT,
|
||||
THUMB_LEFT,
|
||||
INDEX_LEFT,
|
||||
MIDDLE_LEFT,
|
||||
RING_LEFT,
|
||||
LITTLE_LEFT,
|
||||
}
|
||||
|
||||
var type: Type
|
||||
var area: Area3D
|
57
lib/utils/touch/touch.gd
Normal file
57
lib/utils/touch/touch.gd
Normal file
|
@ -0,0 +1,57 @@
|
|||
extends Node
|
||||
|
||||
const Finger = preload("res://lib/utils/touch/finger.gd")
|
||||
|
||||
## Record<Finger.Type, Area3D>
|
||||
var finger_areas: Dictionary
|
||||
|
||||
var areas_entered = {}
|
||||
|
||||
func _init(finger_areas: Dictionary):
|
||||
self.finger_areas = finger_areas
|
||||
|
||||
func _ready():
|
||||
for finger_type in finger_areas.keys():
|
||||
finger_areas[finger_type].area_entered.connect(func(area):
|
||||
_on_area_entered(finger_type, area)
|
||||
)
|
||||
|
||||
finger_areas[finger_type].area_exited.connect(func(area):
|
||||
_on_area_exited(finger_type, area)
|
||||
)
|
||||
|
||||
func _physics_process(_delta):
|
||||
for area in areas_entered.keys():
|
||||
_emit_event("touch_move", area)
|
||||
|
||||
func _on_area_entered(finger_type, area):
|
||||
if areas_entered.has(area):
|
||||
if !areas_entered[area].has(finger_type):
|
||||
areas_entered[area].append(finger_type)
|
||||
_emit_event("touch_enter", area)
|
||||
else:
|
||||
areas_entered[area] = [finger_type]
|
||||
_emit_event("touch_enter", area)
|
||||
|
||||
func _on_area_exited(finger_type, area):
|
||||
if areas_entered.has(area):
|
||||
if areas_entered[area].has(finger_type):
|
||||
areas_entered[area].erase(finger_type)
|
||||
|
||||
if areas_entered[area].size() == 0:
|
||||
_emit_event("touch_leave", area)
|
||||
areas_entered.erase(area)
|
||||
|
||||
func _emit_event(type: String, target):
|
||||
var event = EventTouch.new()
|
||||
event.target = target
|
||||
var fingers: Array[Finger] = []
|
||||
for finger_type in areas_entered[target]:
|
||||
var finger = Finger.new()
|
||||
finger.type = finger_type
|
||||
finger.area = finger_areas[finger_type]
|
||||
fingers.append(finger)
|
||||
|
||||
event.fingers = fingers
|
||||
|
||||
EventSystem.emit(type, event)
|
Loading…
Reference in New Issue
Block a user