Merge pull request #17 from Nitwel/testing

Add buttons and improve interface
This commit is contained in:
Nitwel 2023-11-11 18:27:46 +01:00 committed by GitHub
commit 1e7288caab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 588 additions and 93 deletions

View File

@ -39,6 +39,7 @@ For example, the entity of name `lights.smart_lamp_1` would control the kitchen
├── assets (Files like logos or assets that are shared across scenes)
├── content/ (Main files of the project)
│ ├── entities (Entities that can be placed into the room)
│ ├── functions (Generic functions that can be used in scenes)
│ └── ui (User Interface Scenes and related files)
└── lib/ (Code that is global or shared across scenes)
├── globals (Globally running scripts)
@ -80,11 +81,14 @@ func watch_state(entity: String, callback: Callable[entity: Entity]) -> Callable
### Interaction Events
Each time a button is pressed on the primary controller, a ray-cast is done to be able to interact with devices or the UI.
Additionally, each event will bubble up until the root node is reached, allowing to handle events on parents.
In case that an event of a specific node has to be reacted on, use the `Clickable` function node.
```python
InteractionEvent {
"controller": XRController3D, # The controller that triggered the event
"ray": RayCast3D, # The ray-cast that triggered the event
"target": Node3D, # The node that was hit by the ray-cast
}
```
@ -100,6 +104,18 @@ InteractionEvent {
| `_on_ray_enter` | `[event: InteractionEvent]` | The ray-cast enters the the collision body |
| `_on_ray_leave` | `[event: InteractionEvent]` | The ray-cast leaves the the collision body |
### Functions
In order to implement generic features, a set of functions is available to be used in the project.
#### Movable
The `Movable` node allows to move a node around in the room. It uses the grab events in order to transform the parent node.
#### Clickable
The `Clickable` allows to access events of the parent using signals this node emits.
### Testing without a VR Headset
In order to test without a headset, press the run project (F5) button in Godot and ignore the prompt that OpenXR failed to start.

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:034fb07ad84872c283141a5f2ae34989b349cdf77328cab5458a9263f58e4967
size 2984138
oid sha256:d9423ef5121871fe9f60a673f76728265d2618f318a14e73affb4257cb42f73d
size 3906893

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a00d470585d14a17ca080c46003908207238e9595ea99adc4c40e759d9c13c58
size 10494

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://tr8yrx470k03"
path.s3tc="res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.s3tc.ctex"
path.etc2="res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/materials/arrow_right.png"
dest_files=["res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.s3tc.ctex", "res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
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=0

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7d62537d8aa4fee28ed5484c8c7ba96c2c9a7fa7bc0740e79420f01105602ca5
size 43035

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bo55nohs0wsgf"
path.s3tc="res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.s3tc.ctex"
path.etc2="res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/materials/pointer.png"
dest_files=["res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.s3tc.ctex", "res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
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=0

View File

@ -0,0 +1,39 @@
extends Function
class_name Clickable
signal on_click(event: Dictionary)
signal on_press_down(event: Dictionary)
signal on_press_move(event: Dictionary)
signal on_press_up(event: Dictionary)
signal on_grab_down(event: Dictionary)
signal on_grab_move(event: Dictionary)
signal on_grab_up(event: Dictionary)
signal on_ray_enter(event: Dictionary)
signal on_ray_leave(event: Dictionary)
func _on_click(event: Dictionary):
on_click.emit(event)
func _on_press_down(event: Dictionary):
on_press_down.emit(event)
func _on_press_move(event: Dictionary):
on_press_move.emit(event)
func _on_press_up(event: Dictionary):
on_press_up.emit(event)
func _on_grab_down(event: Dictionary):
on_grab_down.emit(event)
func _on_grab_move(event: Dictionary):
on_grab_move.emit(event)
func _on_grab_up(event: Dictionary):
on_grab_up.emit(event)
func _on_ray_enter(event: Dictionary):
on_ray_enter.emit(event)
func _on_ray_leave(event: Dictionary):
on_ray_leave.emit(event)

View File

@ -1,9 +1,10 @@
[gd_scene load_steps=11 format=3 uid="uid://eecv28y6jxk4"]
[gd_scene load_steps=12 format=3 uid="uid://eecv28y6jxk4"]
[ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"]
[ext_resource type="Script" path="res://content/raycast.gd" id="1_tsqxc"]
[ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"]
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="3_1tbp3"]
[ext_resource type="Texture2D" uid="uid://bo55nohs0wsgf" path="res://assets/materials/pointer.png" id="4_wcfej"]
[ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="5_3qc8g"]
[ext_resource type="Material" uid="uid://bf5ina366dwm6" path="res://assets/materials/sky.material" id="5_wgwf8"]
@ -42,7 +43,7 @@ pose = &"aim"
mesh = SubResource("BoxMesh_ir3co")
[node name="Menu" parent="XROrigin3D/XRControllerLeft" instance=ExtResource("3_1tbp3")]
transform = Transform3D(-4.37114e-08, 0, -1, -0.707107, 0.707107, 3.09086e-08, 0.707107, 0.707107, -3.09086e-08, 0.183517, 0, -0.0534939)
transform = Transform3D(1, -0.000382732, -0.000120985, 8.65898e-05, 0.5, -0.866025, 0.000391948, 0.866025, 0.5, 0.0669508, 0.0876772, -0.101157)
[node name="XRControllerRight" type="XRController3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.488349, 0.559219, -0.2988)
@ -60,6 +61,11 @@ ray = NodePath("RayCast3D")
transform = Transform3D(-2.58078e-11, 4.3714e-08, 1, 1, -4.37117e-08, 9.27469e-12, 4.37112e-08, 1, -4.3714e-08, 0, 0, 0)
target_position = Vector3(0, -5, 0)
[node name="Decal" type="Decal" parent="XROrigin3D/XRControllerRight/Raycast"]
transform = Transform3D(0.999999, -0.000567105, -2.5179e-05, -2.51789e-05, 4.39886e-08, -0.999999, 0.000567105, 1, 2.97064e-08, -0.000775784, -1.09076e-05, -2.46767)
size = Vector3(0.01, 5, 0.01)
texture_albedo = ExtResource("4_wcfej")
[node name="StartXR" parent="." instance=ExtResource("1_i4c04")]
enable_passthrough = true

129
content/main_golf.tscn Normal file
View File

@ -0,0 +1,129 @@
[gd_scene load_steps=18 format=3 uid="uid://fap7m74qctpl"]
[ext_resource type="Script" path="res://content/main.gd" id="1_d7nko"]
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="2_1ns4p"]
[ext_resource type="Script" path="res://content/raycast.gd" id="3_raorn"]
[ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="4_6x466"]
[ext_resource type="Material" uid="uid://bf5ina366dwm6" path="res://assets/materials/sky.material" id="5_o7oeh"]
[ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="6_yj6uv"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"]
ao_enabled = true
[sub_resource type="BoxMesh" id="BoxMesh_ir3co"]
material = SubResource("StandardMaterial3D_m58yb")
size = Vector3(0.01, 0.01, 0.01)
[sub_resource type="Sky" id="Sky_vhymk"]
sky_material = ExtResource("5_o7oeh")
[sub_resource type="Environment" id="Environment_7ghp0"]
background_mode = 2
background_color = Color(0.466667, 0.47451, 0.462745, 0)
sky = SubResource("Sky_vhymk")
ambient_light_color = Color(1, 1, 1, 1)
ambient_light_sky_contribution = 0.72
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_5qi0p"]
rough = true
[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_i18hv"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_t7p2m"]
rough = true
[sub_resource type="SphereShape3D" id="SphereShape3D_wckr8"]
radius = 0.1
[sub_resource type="SphereMesh" id="SphereMesh_5b0e3"]
radius = 0.1
height = 0.2
[sub_resource type="BoxMesh" id="BoxMesh_4w3j6"]
size = Vector3(0.02, 1, 0.02)
[sub_resource type="BoxShape3D" id="BoxShape3D_huggw"]
size = Vector3(0.02, 1, 0.02)
[node name="Main" type="Node3D"]
transform = Transform3D(1, -0.000296142, 0.000270963, 0.000296143, 1, -4.61078e-06, -0.000270962, 4.67014e-06, 1, 0, 0, 0)
script = ExtResource("1_d7nko")
[node name="XROrigin3D" type="XROrigin3D" parent="."]
[node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.798091, 0.311748)
[node name="XRControllerLeft" type="XRController3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.469893, 0.597213, -0.251112)
tracker = &"left_hand"
pose = &"aim"
[node name="MeshInstance3D" type="MeshInstance3D" parent="XROrigin3D/XRControllerLeft"]
mesh = SubResource("BoxMesh_ir3co")
[node name="Menu" parent="XROrigin3D/XRControllerLeft" instance=ExtResource("2_1ns4p")]
transform = Transform3D(-4.37114e-08, 0, -1, -0.707107, 0.707107, 3.09086e-08, 0.707107, 0.707107, -3.09086e-08, 0.183517, 0, -0.0534939)
[node name="XRControllerRight" type="XRController3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.488349, 0.559219, -0.2988)
tracker = &"right_hand"
pose = &"aim"
[node name="MeshInstance3D" type="MeshInstance3D" parent="XROrigin3D/XRControllerRight"]
mesh = SubResource("BoxMesh_ir3co")
[node name="Raycast" type="Node3D" parent="XROrigin3D/XRControllerRight" node_paths=PackedStringArray("ray")]
script = ExtResource("3_raorn")
ray = NodePath("RayCast3D")
[node name="RayCast3D" type="RayCast3D" parent="XROrigin3D/XRControllerRight/Raycast"]
transform = Transform3D(-2.58078e-11, 4.3714e-08, 1, 1, -4.37117e-08, 9.27469e-12, 4.37112e-08, 1, -4.3714e-08, 0, 0, 0)
target_position = Vector3(0, -5, 0)
[node name="RemoteTransform3D" type="RemoteTransform3D" parent="XROrigin3D/XRControllerRight"]
remote_path = NodePath("../../../Club (AnimatableBody3D)")
[node name="StartXR" parent="." instance=ExtResource("4_6x466")]
enable_passthrough = true
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_7ghp0")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.834925, -0.386727, -0.39159, 0.550364, 0.586681, 0.594058, 0, -0.711511, 0.702675, 0, 7.21041, 2.06458)
shadow_enabled = true
[node name="XRSimulator" parent="." instance=ExtResource("6_yj6uv")]
xr_origin = NodePath("../XROrigin3D")
[node name="Ground (StaticBody3D)" type="StaticBody3D" parent="."]
transform = Transform3D(1, -1.39636e-11, 0, 9.47997e-12, 1, 0, 0, 0, 1, 0, 0, 0)
physics_material_override = SubResource("PhysicsMaterial_5qi0p")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground (StaticBody3D)"]
transform = Transform3D(0.999999, -1.39631e-11, 0, 9.48108e-12, 0.999999, -4.54747e-13, 0, -4.54747e-13, 0.999999, 0, 0, 0)
shape = SubResource("WorldBoundaryShape3D_i18hv")
[node name="Ball (RigidBody3D)" type="RigidBody3D" parent="."]
transform = Transform3D(0.999997, -1.39633e-11, 0, 9.48364e-12, 0.999998, -1.81899e-12, 0, 5.91172e-12, 0.999998, 0.487249, 1.15211, -0.679336)
physics_material_override = SubResource("PhysicsMaterial_t7p2m")
angular_damp = 4.0
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ball (RigidBody3D)"]
shape = SubResource("SphereShape3D_wckr8")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Ball (RigidBody3D)"]
transform = Transform3D(1, -1.39641e-11, 0, 9.47986e-12, 1, 0, 2.91038e-11, 0, 1, 0, 0, 0)
mesh = SubResource("SphereMesh_5b0e3")
[node name="Club (AnimatableBody3D)" type="AnimatableBody3D" parent="."]
transform = Transform3D(1, -1.39637e-11, 0, 9.47975e-12, 1, 0, 0, 0, 1, 0.488349, 0.559219, -0.2988)
[node name="MeshInstance3D" type="MeshInstance3D" parent="Club (AnimatableBody3D)"]
transform = Transform3D(1, -0.000567105, -2.51786e-05, -2.51789e-05, 4.39913e-08, -0.999999, 0.000567105, 1, 2.97096e-08, 0.000972658, -0.00257713, -0.524774)
mesh = SubResource("BoxMesh_4w3j6")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Club (AnimatableBody3D)"]
transform = Transform3D(1, -0.000567105, -2.51788e-05, -2.51788e-05, 4.39918e-08, -1, 0.000567105, 1, 2.97127e-08, 0.000972658, -0.00257713, -0.524774)
shape = SubResource("BoxShape3D_huggw")

View File

@ -18,12 +18,6 @@ func _physics_process(delta):
_handle_enter_leave()
_handle_move()
func _get_event_data():
return {
"controller": _controller,
"ray": ray,
}
func _handle_move():
if _is_pressed == false && _is_grabbed == false:
return
@ -86,11 +80,27 @@ func _on_button_released(button):
_is_grabbed = false
_moved = false
func _call_fn(collider: Object, fn_name: String):
if collider != null:
if collider.has_method(fn_name):
collider.call(fn_name, _get_event_data())
func _call_fn(collider: Object, fn_name: String, node: Node3D = null):
if collider == null:
return
for child in collider.get_children():
if child is Function:
_call_fn(child, fn_name)
if node == null:
node = collider
var event = {
"controller": _controller,
"ray": ray,
"target": collider,
}
for child in node.get_children():
if child is Function && child.has_method(fn_name):
child.call(fn_name, event)
if node.has_method(fn_name):
node.call(fn_name, event)
var parent = node.get_parent()
if parent != null && parent is Node3D:
_call_fn(collider, fn_name, parent)

View File

@ -0,0 +1,9 @@
extends StaticBody3D
@onready var animation_player: AnimationPlayer = $AnimationPlayer
func _on_press_down(_event):
animation_player.play("down")
func _on_press_up(_event):
animation_player.play("up")

View File

@ -0,0 +1,79 @@
[gd_scene load_steps=9 format=3 uid="uid://bsjqdvkt0u87c"]
[ext_resource type="Script" path="res://content/ui/button/button.gd" id="1_g5u54"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_peqek"]
albedo_color = Color(0.151534, 0.211909, 0.619523, 1)
[sub_resource type="BoxMesh" id="BoxMesh_jwpm5"]
material = SubResource("StandardMaterial3D_peqek")
size = Vector3(0.05, 0.02, 0.05)
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_o4j7g"]
points = PackedVector3Array(-0.025, -0.01, -0.025, -0.025, 0.01, -0.025, 0.025, -0.01, -0.025, -0.025, -0.01, 0.025, -0.025, 0.01, 0.025, 0.025, 0.01, -0.025, 0.025, -0.01, 0.025, 0.025, 0.01, 0.025)
[sub_resource type="Animation" id="Animation_04k6i"]
length = 0.001
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position:y")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(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.4
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position:y")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0, 0),
"points": PackedFloat32Array(0.01, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0, 0.4)
}
[sub_resource type="Animation" id="Animation_y7xum"]
resource_name = "up"
length = 0.4
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position: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),
"times": PackedFloat32Array(0, 0.4)
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_sbgno"]
_data = {
"RESET": SubResource("Animation_04k6i"),
"down": SubResource("Animation_iu2ed"),
"up": SubResource("Animation_y7xum")
}
[node name="Button" type="StaticBody3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.01, 0)
script = ExtResource("1_g5u54")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("BoxMesh_jwpm5")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("ConvexPolygonShape3D_o4j7g")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_sbgno")
}

View File

@ -1,13 +1,8 @@
extends StaticBody3D
extends Node3D
@onready var label: Label3D = $Label
@onready var label: Label3D = $Button/Label
@export var id: String = "0"
signal click(id: String)
func _on_click(event):
click.emit(id)
func set_device_name(text):
assert(label != null, "Device has to be added to the scene tree")
label.text = text

View File

@ -1,23 +1,19 @@
[gd_scene load_steps=4 format=3 uid="uid://dbe8slnyhro2n"]
[ext_resource type="Script" path="res://content/ui/device/device.gd" id="1_rbo86"]
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/button/button.tscn" id="2_go2es"]
[ext_resource type="Script" path="res://content/functions/clickable.gd" id="3_6wicx"]
[sub_resource type="BoxMesh" id="BoxMesh_aa3i4"]
size = Vector3(0.05, 0.01, 0.05)
[sub_resource type="BoxShape3D" id="BoxShape3D_28fjq"]
size = Vector3(0.05, 0.01, 0.05)
[node name="Device" type="StaticBody3D"]
[node name="Device" type="Node3D"]
script = ExtResource("1_rbo86")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("BoxMesh_aa3i4")
[node name="Button" parent="." instance=ExtResource("2_go2es")]
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_28fjq")
[node name="Label" type="Label3D" parent="."]
transform = Transform3D(-2.18557e-09, -0.05, -2.18557e-09, 0, -2.18557e-09, 0.05, -0.05, 2.18557e-09, 9.55343e-17, 0, 0.00918245, 0)
text = "Text"
[node name="Label" type="Label3D" parent="Button"]
transform = Transform3D(0.05, 0, 0, 0, -2.18557e-09, 0.05, 0, -0.05, -2.18557e-09, 0, 0.0142873, 0)
text = "Texttexttexttexttexttextext"
autowrap_mode = 3
width = 200.0
[node name="Clickable" type="Node" parent="."]
script = ExtResource("3_6wicx")

View File

@ -3,11 +3,6 @@ extends StaticBody3D
@onready var label: Label3D = $Label
@export var text = "Default"
signal click(name: String)
func _on_click(event):
click.emit(text)
func set_entity_name(text):
assert(label != null, "Entity has to be added to the scene tree")
label.text = text.replace(".", "\n")

View File

@ -1,6 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://xo0o5nrfjl23"]
[gd_scene load_steps=5 format=3 uid="uid://xo0o5nrfjl23"]
[ext_resource type="Script" path="res://content/ui/entity/entity.gd" id="1_825oj"]
[ext_resource type="Script" path="res://content/functions/clickable.gd" id="2_i054q"]
[sub_resource type="BoxMesh" id="BoxMesh_aa3i4"]
size = Vector3(0.05, 0.01, 0.05)
@ -18,6 +19,10 @@ mesh = SubResource("BoxMesh_aa3i4")
shape = SubResource("BoxShape3D_28fjq")
[node name="Label" type="Label3D" parent="."]
transform = Transform3D(-2.18557e-09, -0.05, -2.18557e-09, 0, -2.18557e-09, 0.05, -0.05, 2.18557e-09, 9.55343e-17, 0, 0.00918245, 0)
transform = Transform3D(0.05, 0, 0, 0, -2.18557e-09, 0.05, 0, -0.05, -2.18557e-09, 0, 0.00918245, 0)
text = "Text"
autowrap_mode = 3
width = 200.0
[node name="Clickable" type="Node" parent="."]
script = ExtResource("2_i054q")

View File

@ -0,0 +1,15 @@
extends Node3D
class_name Container3D
@export var size := Vector3(1.0, 1.0, 1.0) :
set(value):
size = value
_update_container()
@export var padding: Vector4 = Vector4(0, 0, 0, 0) :
set(value):
padding = value
_update_container()
func _update_container():
pass

42
content/ui/menu/grid.gd Normal file
View File

@ -0,0 +1,42 @@
@tool
extends Container3D
class_name GridContainer3D
@export var columns := 5 :
set(value):
columns = value
_update_container()
@export var rows := 1 :
set(value):
rows = value
_update_container()
@export var depth_gap := 1.0 :
set(value):
depth_gap = value
_update_container()
func _ready():
_update_container()
func get_gaps() -> Vector3:
return Vector3(
(float(size.x) / (columns - 1 )) if columns != 1 else 0.0,
(float(size.y) / (rows - 1)) if rows != 1 else 0.0,
depth_gap
)
func _update_container():
var i := 0
var gaps := get_gaps()
for child in get_children():
var x := (i % columns) * gaps.x
var y := ((i / columns) % rows) * gaps.y
var z := (i / (columns * rows)) * gaps.z
child.set_position(Vector3(x, -y, z))
i += 1

View File

@ -6,77 +6,123 @@ const Switch = preload("res://content/entities/switch/switch.tscn")
const Light = preload("res://content/entities/light/light.tscn")
const Sensor = preload("res://content/entities/sensor/sensor.tscn")
@onready var devices_node = $Devices
@onready var devices_node: GridContainer3D = $Devices
@onready var next_page_button = $NextPageButton
@onready var previous_page_button = $PreviousPageButton
@onready var page_number_label = $PageNumberLabel
var devices
var page = 0
var last_device_page = 0
var page_size = 20
var pages = 0
var selected_device = null
# Called when the node enters the scene tree for the first time.
func _ready():
devices = await HomeAdapters.adapter.get_devices()
render_devices()
next_page_button.get_node("Clickable").on_click.connect(func(_event):
print("next page")
next_page()
)
previous_page_button.get_node("Clickable").on_click.connect(func(_event):
previous_page()
)
render()
func update_pages():
if selected_device == null:
pages = ceil(float(devices.size()) / page_size)
else:
for device in devices:
if device.keys()[0] == selected_device:
pages = ceil(float(device.values()[0]["entities"].size()) / page_size)
func get_page():
if selected_device == null:
return devices.slice(page * page_size, page * page_size + page_size)
else:
for device in devices:
if device.keys()[0] == selected_device:
return device.values()[0]["entities"].slice(page * page_size, page * page_size + page_size)
func next_page():
if page >= pages - 1:
return
page += 1
render()
func previous_page():
if page <= 0:
return
page -= 1
render()
func render():
update_pages()
page_number_label.set_text(str(page + 1) + " / " + str(pages))
previous_page_button.visible = page > 0
next_page_button.visible = page < pages - 1
clear_menu()
if selected_device == null:
render_devices()
else:
render_entities()
func render_devices():
var x = 0
var y = 0
var page_devices = get_page()
for device in devices:
for device in page_devices:
var info = device.values()[0]
var device_instance = Device.instantiate()
device_instance.set_position(Vector3(y * 0.08, 0, -x * 0.08))
device_instance.click.connect(_on_device_click)
device_instance.id = device.keys()[0]
device_instance.get_node("Clickable").on_click.connect(func(_event):
_on_device_click(device_instance.id)
)
devices_node.add_child(device_instance)
device_instance.set_device_name(info["name"])
x += 1
if x % 5 == 0:
x = 0
y += 1
devices_node._update_container()
func render_entities():
var x = 0
var y = 0
var entities = get_page()
var info
for device in devices:
if device.keys()[0] == selected_device:
info = device.values()[0]
break
if info == null:
return
var entities = info["entities"]
var back_button = Entity.instantiate()
back_button.get_node("Clickable").on_click.connect(func(_event):
_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.set_position(Vector3(y * 0.08, 0, -x * 0.08))
entity_instance.click.connect(_on_entity_click)
entity_instance.get_node("Clickable").on_click.connect(func(_event):
_on_entity_click(entity)
)
devices_node.add_child(entity_instance)
entity_instance.set_entity_name(entity)
x += 1
if x % 5 == 0:
x = 0
y += 1
devices_node._update_container()
func _on_device_click(device_id):
selected_device = device_id
print(selected_device)
clear_menu()
render_entities()
last_device_page = page
page = 0
render()
func _on_entity_click(entity_name):
print(entity_name)
selected_device = null
clear_menu()
render_devices()
if entity_name == "#back":
selected_device = null
page = last_device_page
render()
return
var type = entity_name.split(".")[0]
print(type)

View File

@ -1,7 +1,11 @@
[gd_scene load_steps=4 format=3 uid="uid://c3kdssrmv84kv"]
[gd_scene load_steps=8 format=3 uid="uid://c3kdssrmv84kv"]
[ext_resource type="Script" path="res://content/ui/menu/menu.gd" id="1_ng4u3"]
[ext_resource type="Material" uid="uid://bertj8bp8b5l1" path="res://assets/materials/interface.tres" id="2_nsukb"]
[ext_resource type="Script" path="res://content/ui/menu/grid.gd" id="3_35a5r"]
[ext_resource type="Texture2D" uid="uid://tr8yrx470k03" path="res://assets/materials/arrow_right.png" id="4_7frvc"]
[ext_resource type="Script" path="res://content/functions/clickable.gd" id="4_f385t"]
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/button/button.tscn" id="5_w4i01"]
[sub_resource type="PlaneMesh" id="PlaneMesh_6t3dn"]
material = ExtResource("2_nsukb")
@ -11,7 +15,38 @@ size = Vector2(0.3, 0.3)
script = ExtResource("1_ng4u3")
[node name="Background" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0, 0.15)
mesh = SubResource("PlaneMesh_6t3dn")
[node name="Devices" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.149223, 0, 0.150667)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.03)
script = ExtResource("3_35a5r")
depth_gap = 0.06
size = Vector3(0.24, 0.1, 0.1)
[node name="NextPageButton" parent="." instance=ExtResource("5_w4i01")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.19, 0.01, 0.27)
[node name="Decal" type="Decal" parent="NextPageButton"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.02, 0)
size = Vector3(0.04, 0.04, 0.04)
texture_albedo = ExtResource("4_7frvc")
[node name="Clickable" type="Node" parent="NextPageButton"]
script = ExtResource("4_f385t")
[node name="PreviousPageButton" parent="." instance=ExtResource("5_w4i01")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.11, 0.01, 0.27)
[node name="Decal" type="Decal" parent="PreviousPageButton"]
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0.02, 0)
size = Vector3(0.04, 0.04, 0.04)
texture_albedo = ExtResource("4_7frvc")
[node name="Clickable" type="Node" parent="PreviousPageButton"]
script = ExtResource("4_f385t")
[node name="PageNumberLabel" type="Label3D" parent="."]
transform = Transform3D(0.1, 0, 0, 0, -4.37114e-09, 0.1, 0, -0.1, -4.37114e-09, 0.26, 0.01, 0.27)
text = "1 / 3"
font_size = 36