Merge pull request #17 from Nitwel/testing
Add buttons and improve interface
This commit is contained in:
commit
1e7288caab
16
README.md
16
README.md
|
@ -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.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:034fb07ad84872c283141a5f2ae34989b349cdf77328cab5458a9263f58e4967
|
||||
size 2984138
|
||||
oid sha256:d9423ef5121871fe9f60a673f76728265d2618f318a14e73affb4257cb42f73d
|
||||
size 3906893
|
||||
|
|
3
assets/materials/arrow_right.png
Normal file
3
assets/materials/arrow_right.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a00d470585d14a17ca080c46003908207238e9595ea99adc4c40e759d9c13c58
|
||||
size 10494
|
36
assets/materials/arrow_right.png.import
Normal file
36
assets/materials/arrow_right.png.import
Normal 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
|
3
assets/materials/pointer.png
Normal file
3
assets/materials/pointer.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7d62537d8aa4fee28ed5484c8c7ba96c2c9a7fa7bc0740e79420f01105602ca5
|
||||
size 43035
|
36
assets/materials/pointer.png.import
Normal file
36
assets/materials/pointer.png.import
Normal 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
|
39
content/functions/clickable.gd
Normal file
39
content/functions/clickable.gd
Normal 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)
|
|
@ -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
129
content/main_golf.tscn
Normal 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")
|
|
@ -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)
|
||||
|
|
9
content/ui/button/button.gd
Normal file
9
content/ui/button/button.gd
Normal 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")
|
79
content/ui/button/button.tscn
Normal file
79
content/ui/button/button.tscn
Normal 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")
|
||||
}
|
|
@ -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
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
15
content/ui/menu/container3d.gd
Normal file
15
content/ui/menu/container3d.gd
Normal 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
42
content/ui/menu/grid.gd
Normal 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
|
|
@ -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()
|
||||
|
||||
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)
|
||||
if entity_name == "#back":
|
||||
selected_device = null
|
||||
clear_menu()
|
||||
render_devices()
|
||||
page = last_device_page
|
||||
render()
|
||||
return
|
||||
|
||||
var type = entity_name.split(".")[0]
|
||||
print(type)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user