diff --git a/README.md b/README.md index 3f0158d..c4be6d2 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,10 @@ InteractionEvent { "ray": RayCast3D, # The ray-cast that triggered the event "target": Node3D, # The node that was hit by the ray-cast } + +KeyEvent { + "key": String, # The key that was pressed +} ``` | Function called | Args | Description | @@ -114,6 +118,12 @@ InteractionEvent { | `_on_grab_up` | `[event: InteractionEvent]` | The side grab button been released | | `_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 | +| `_on_key_down` | `[event: KeyEvent]` | The ray-cast leaves the the collision body | +| `_on_key_up` | `[event: KeyEvent]` | The ray-cast leaves the the collision body | + +After considering using the build in godot event system, I've decided that it would be better to use a custom event system. +The reason being that we would have to check each tick if the event matches the desired one which seems very inefficient compared to using signals like the browser does. +Thus I've decided to use a custom event system that is similar to the one used in the browser. ### Functions diff --git a/content/functions/clickable.gd b/content/functions/clickable.gd index bbf1366..01dcab5 100644 --- a/content/functions/clickable.gd +++ b/content/functions/clickable.gd @@ -1,39 +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) +signal on_click(event: EventRay) +signal on_press_down(event: EventRay) +signal on_press_move(event: EventRay) +signal on_press_up(event: EventRay) +signal on_grab_down(event: EventRay) +signal on_grab_move(event: EventRay) +signal on_grab_up(event: EventRay) +signal on_ray_enter(event: EventRay) +signal on_ray_leave(event: EventRay) -func _on_click(event: Dictionary): +func _on_click(event: EventRay): on_click.emit(event) -func _on_press_down(event: Dictionary): +func _on_press_down(event: EventRay): on_press_down.emit(event) -func _on_press_move(event: Dictionary): +func _on_press_move(event: EventRay): on_press_move.emit(event) -func _on_press_up(event: Dictionary): +func _on_press_up(event: EventRay): on_press_up.emit(event) -func _on_grab_down(event: Dictionary): +func _on_grab_down(event: EventRay): on_grab_down.emit(event) -func _on_grab_move(event: Dictionary): +func _on_grab_move(event: EventRay): on_grab_move.emit(event) -func _on_grab_up(event: Dictionary): +func _on_grab_up(event: EventRay): on_grab_up.emit(event) -func _on_ray_enter(event: Dictionary): +func _on_ray_enter(event: EventRay): on_ray_enter.emit(event) -func _on_ray_leave(event: Dictionary): +func _on_ray_leave(event: EventRay): on_ray_leave.emit(event) \ No newline at end of file diff --git a/content/functions/movable.gd b/content/functions/movable.gd index e0b1cad..07f3bad 100644 --- a/content/functions/movable.gd +++ b/content/functions/movable.gd @@ -4,14 +4,14 @@ class_name Movable var hit_node := Node3D.new() -func _on_grab_down(event): +func _on_grab_down(event: EventRay): event.controller.add_child(hit_node) hit_node.global_transform = get_parent().global_transform -func _on_grab_move(event): +func _on_grab_move(_event: EventRay): get_parent().global_transform = hit_node.global_transform -func _on_grab_up(event): +func _on_grab_up(event: EventRay): event.controller.remove_child(hit_node) func _get_configuration_warnings() -> PackedStringArray: diff --git a/content/main.tscn b/content/main.tscn index 7609b70..381fae9 100644 --- a/content/main.tscn +++ b/content/main.tscn @@ -1,13 +1,13 @@ [gd_scene load_steps=13 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://b30w6tywfj4fp" path="res://content/controller_left.tscn" id="2_2lraw"] -[ext_resource type="Texture2D" uid="uid://bo55nohs0wsgf" path="res://assets/materials/pointer.png" id="4_wcfej"] +[ext_resource type="PackedScene" uid="uid://b30w6tywfj4fp" path="res://content/system/controller_left/controller_left.tscn" id="2_2lraw"] +[ext_resource type="PackedScene" uid="uid://d3f8glx1xgm5w" path="res://content/system/raycast/raycast.tscn" id="3_67lii"] [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"] [ext_resource type="PackedScene" uid="uid://83lb5p4e0qk0" path="res://content/scenes/house.tscn" id="8_qkrg7"] +[ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/ui/keyboard/keyboard.tscn" id="9_e5n3p"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] ao_enabled = true @@ -46,20 +46,7 @@ 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("1_tsqxc") -ray = NodePath("RayCast3D") - -[node name="RayCast3D" type="RayCast3D" parent="XROrigin3D/XRControllerRight/Raycast"] -transform = Transform3D(-4.62364e-10, 4.3714e-08, 0.999998, 0.999999, -4.37194e-08, 9.2768e-12, 4.37103e-08, 0.999999, -4.3714e-08, -0.000467122, 0.00228411, -0.0016689) -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.02, 4.91995, 0.02) -texture_albedo = ExtResource("4_wcfej") -upper_fade = 0.000985425 -lower_fade = 0.000919435 +[node name="Raycast" parent="XROrigin3D/XRControllerRight" instance=ExtResource("3_67lii")] [node name="StartXR" parent="." instance=ExtResource("1_i4c04")] enable_passthrough = true @@ -77,3 +64,6 @@ xr_origin = NodePath("../XROrigin3D") [node name="House" parent="." instance=ExtResource("8_qkrg7")] transform = Transform3D(0.404247, 0.000180645, 0.914648, 0.00017221, 0.999999, -0.000273614, -0.914648, 0.00026812, 0.404247, -0.343479, 0.000110551, 1.91547) visible = false + +[node name="Keyboard" parent="." instance=ExtResource("9_e5n3p")] +transform = Transform3D(0.5, -6.98186e-12, 0, 4.73988e-12, 0.5, 0, 0, 0, 0.5, -0.00874073, 0.253873, -0.357135) diff --git a/content/raycast.gd b/content/raycast.gd deleted file mode 100644 index 530e703..0000000 --- a/content/raycast.gd +++ /dev/null @@ -1,121 +0,0 @@ -extends Node3D - -@onready var _controller := XRHelpers.get_xr_controller(self) -@export var ray: RayCast3D -@export var timespan_click = 200.0 - -# Called when the node enters the scene tree for the first time. -func _ready(): - _controller.button_pressed.connect(_on_button_pressed) - _controller.button_released.connect(_on_button_released) - -var _last_collided: Object = null -var _is_pressed := false -var _is_grabbed := false -var _time_pressed := 0.0 -var _moved := false -var _click_point := Vector3.ZERO - -func _physics_process(delta): - _handle_enter_leave() - _handle_move() - -func _handle_move(): - var time_passed = Time.get_ticks_msec() - _time_pressed - if time_passed <= timespan_click || (_is_pressed == false && _is_grabbed == false): - return - - _moved = true - - if _is_pressed: - _call_fn(_last_collided, "_on_press_move") - - if _is_grabbed: - _call_fn(_last_collided, "_on_grab_move") - -func _handle_enter_leave(): - var collider = ray.get_collider() - - if collider == _last_collided || _is_grabbed || _is_pressed: - return - - _call_fn(collider, "_on_ray_enter") - _call_fn(_last_collided, "_on_ray_leave") - - _last_collided = collider - -func _on_button_pressed(button): - var collider = ray.get_collider() - - if collider == null: - return - - match button: - "trigger_click": - _is_pressed = true - _time_pressed = Time.get_ticks_msec() - _click_point = ray.get_collision_point() - _call_fn(collider, "_on_press_down") - "grip_click": - _is_grabbed = true - _click_point = ray.get_collision_point() - _call_fn(collider, "_on_grab_down") - -func _on_button_released(button): - if _last_collided == null: - return - - match button: - "trigger_click": - if _is_pressed: - if _moved == false: - _call_fn(_last_collided, "_on_click") - _call_fn(_last_collided, "_on_press_up") - _is_pressed = false - _last_collided = null - _moved = false - "grip_click": - if _is_grabbed: - _call_fn(_last_collided, "_on_grab_up") - _is_grabbed = false - _last_collided = null - _moved = false - -func _call_fn(collider: Variant, fn_name: String, node: Node3D = null, event = null): - if collider == null: - return - - if node == null: - node = collider - event = { - "controller": _controller, - "ray": ray, - "target": collider, - } - - if node.has_method(fn_name): - var result = node.call(fn_name, event) - - if result != null && result is Dictionary: - result.merge(event, true) - event = result - - if result != null && result is bool && result == false: - # Stop the event from bubbling up - return - - for child in node.get_children(): - if child is Function && child.has_method(fn_name): - child.call(fn_name, event) - - - var parent = node.get_parent() - - if parent != null && parent is Node3D: - _call_fn(collider, fn_name, parent, event) - else: - # in case the top has been reached - _call_global_fn(fn_name, event) - -func _call_global_fn(fn_name: String, event = null): - Events.get(fn_name.substr(1)).emit(event) diff --git a/content/controller_left.gd b/content/system/controller_left/controller_left.gd similarity index 88% rename from content/controller_left.gd rename to content/system/controller_left/controller_left.gd index 355bc3b..a8fa9d0 100644 --- a/content/controller_left.gd +++ b/content/system/controller_left/controller_left.gd @@ -34,11 +34,11 @@ var trash_bin_large: bool = false: func _ready(): trash_bin_visible = false - Events.on_grab_down.connect(func(event): + EventSystem.on_grab_down.connect(func(event: EventRay): trash_bin_visible = event.target.is_in_group("entity") ) - Events.on_grab_move.connect(func(event): + EventSystem.on_grab_move.connect(func(event): if !trash_bin_visible: return @@ -53,7 +53,7 @@ func _ready(): ) - Events.on_grab_up.connect(func(event): + EventSystem.on_grab_up.connect(func(_event: EventRay): if !trash_bin_visible: return diff --git a/content/controller_left.tscn b/content/system/controller_left/controller_left.tscn similarity index 91% rename from content/controller_left.tscn rename to content/system/controller_left/controller_left.tscn index de6a854..fb8344e 100644 --- a/content/controller_left.tscn +++ b/content/system/controller_left/controller_left.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=10 format=3 uid="uid://b30w6tywfj4fp"] +[gd_scene load_steps=11 format=3 uid="uid://b30w6tywfj4fp"] -[ext_resource type="Script" path="res://content/controller_left.gd" id="1_2j3qs"] +[ext_resource type="Script" path="res://content/system/controller_left/controller_left.gd" id="1_2j3qs"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="1_ccbr3"] [ext_resource type="PackedScene" uid="uid://cj42our8uhfq6" path="res://assets/models/trash_bin/trash_bin.gltf" id="3_m33ce"] +[ext_resource type="PackedScene" uid="uid://d3f8glx1xgm5w" path="res://content/system/raycast/raycast.tscn" id="4_n7lao"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] ao_enabled = true @@ -119,3 +120,5 @@ shape = SubResource("CylinderShape3D_x2eyr") libraries = { "": SubResource("AnimationLibrary_hkli8") } + +[node name="Raycast" parent="." instance=ExtResource("4_n7lao")] diff --git a/content/system/raycast/raycast.gd b/content/system/raycast/raycast.gd new file mode 100644 index 0000000..3b9d6ce --- /dev/null +++ b/content/system/raycast/raycast.gd @@ -0,0 +1,94 @@ +extends RayCast3D + +@export var is_right: bool = true + +var controller: XRController3D +var timespan_click = 200.0 + +var last_collided: Object = null +var is_pressed := false +var is_grabbed := false +var time_pressed := 0.0 +var moved := false +var click_point := Vector3.ZERO + +func _ready(): + controller = get_parent() + assert(controller is XRController3D, "XRController3D is not found in parent") + + controller.button_pressed.connect(_on_button_pressed) + controller.button_released.connect(_on_button_released) + +func _physics_process(_delta): + _handle_enter_leave() + _handle_move() + +func _handle_move(): + var time_passed = Time.get_ticks_msec() - time_pressed + if time_passed <= timespan_click || (is_pressed == false && is_grabbed == false): + return + + moved = true + + if is_pressed: + _emit_event("press_move", last_collided ) + + if is_grabbed: + _emit_event("grab_move", last_collided ) + +func _handle_enter_leave(): + var collider = get_collider() + + if collider == last_collided || is_grabbed || is_pressed: + return + + _emit_event("ray_enter", collider ) + _emit_event("ray_leave", last_collided ) + + last_collided = collider + +func _on_button_pressed(button: String): + var collider = get_collider() + + if collider == null: + return + + match button: + "trigger_click": + is_pressed = true + time_pressed = Time.get_ticks_msec() + click_point = get_collision_point() + _emit_event("press_down", collider ) + "grip_click": + is_grabbed = true + click_point = get_collision_point() + _emit_event("grab_down", collider ) + +func _on_button_released(button: String): + if last_collided == null: + return + + match button: + "trigger_click": + if is_pressed: + if moved == false: + _emit_event("click", last_collided ) + _emit_event("press_up", last_collided ) + is_pressed = false + last_collided = null + moved = false + "grip_click": + if is_grabbed: + _emit_event("grab_up", last_collided ) + is_grabbed = false + last_collided = null + moved = false + +func _emit_event(type: String, target: Object): + var event = EventRay.new() + event.controller = controller + event.target = target + event.ray = self + event.is_right_controller = is_right + + EventSystem.emit(type, event) \ No newline at end of file diff --git a/content/system/raycast/raycast.tscn b/content/system/raycast/raycast.tscn new file mode 100644 index 0000000..1d448b3 --- /dev/null +++ b/content/system/raycast/raycast.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=3 format=3 uid="uid://d3f8glx1xgm5w"] + +[ext_resource type="Texture2D" uid="uid://bo55nohs0wsgf" path="res://assets/materials/pointer.png" id="1_2f2iv"] +[ext_resource type="Script" path="res://content/system/raycast/raycast.gd" id="1_gp8nv"] + +[node name="Raycast" type="RayCast3D"] +transform = Transform3D(0.999999, -1.39624e-11, 0, 9.48108e-12, 0.999999, 0, 0, 4.54747e-13, 0.999998, -0.000467122, 0.00228411, -0.0016689) +target_position = Vector3(0, 0, -5) +script = ExtResource("1_gp8nv") + +[node name="Decal" type="Decal" parent="."] +transform = Transform3D(1, -0.000567106, -2.5179e-05, -2.5179e-05, 4.39886e-08, -1, 0.000567106, 1, 2.97068e-08, -0.000308663, -0.00229502, -2.46601) +size = Vector3(0.02, 4.91995, 0.02) +texture_albedo = ExtResource("1_2f2iv") +upper_fade = 0.000985425 +lower_fade = 0.000919435 diff --git a/content/ui/components/button/button.gd b/content/ui/components/button/button.gd index 960eef3..dbcdc4d 100644 --- a/content/ui/components/button/button.gd +++ b/content/ui/components/button/button.gd @@ -1,12 +1,14 @@ extends StaticBody3D class_name Button3D +signal on_button_down() +signal on_button_up() + @export var toggleable: bool = false @export var disabled: bool = false @export var initial_active: bool = false var active: bool = false : set(value): - print("set active", value) animation_player.stop() if value == active: return @@ -17,8 +19,6 @@ var active: bool = false : animation_player.play("down") else: animation_player.play_backwards("down") - get: - return active @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var click_sound: AudioStreamPlayer = $ClickSound @@ -27,35 +27,31 @@ func _ready(): if initial_active: active = true -func _on_click(_event): +func _on_press_down(event): if disabled: - return false - - if !toggleable: + event.bubbling = false return - active = !active - AudioPlayer.play_effect("click") - - return { - "active": active - } - -func _on_press_down(_event): - if disabled: - return false - if toggleable: return + + active = true + on_button_down.emit() AudioPlayer.play_effect("click") - animation_player.play("down") + -func _on_press_up(_event): +func _on_press_up(event): if disabled: - return false - - if toggleable: + event.bubbling = false return - animation_player.play_backwards("down") + if toggleable: + active = !active + if active: + on_button_down.emit() + else: + on_button_up.emit() + else: + active = false + on_button_up.emit() diff --git a/content/ui/keyboard/keyboard.gd b/content/ui/keyboard/keyboard.gd index ca9b60e..f511f6f 100644 --- a/content/ui/keyboard/keyboard.gd +++ b/content/ui/keyboard/keyboard.gd @@ -1,51 +1,84 @@ -extends Node3D +@tool +extends StaticBody3D const button_scene = preload("res://content/ui/components/button/button.tscn") @onready var keys = $Keys @onready var caps_button = $Caps +@onready var backspace_button = $Backspace var key_list = [ - ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "~"], - ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "/"], - ["A", "S", "D", "F", "G", "H", "J", "K", "L", ":", "\\"], - ["Z", "X", "C", "V", "B", "N", "M", ",", ".", "-"] + [KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_ASCIITILDE], + [KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_SLASH], + [KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_COLON, KEY_BACKSLASH], + [KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA , KEY_PERIOD, KEY_MINUS] ] -var caps = false +var caps = false : + set(value): + caps = value + update_labels() func _ready(): for row in key_list: for key in row: - print(key) var button = create_key(key) keys.add_child(button) + button.on_button_down.connect(func(): + _emit_event("key_down", key) + ) + button.on_button_up.connect(func(): + _emit_event("key_up", key) + ) keys.columns = key_list[0].size() -func _on_click(event): - if event.target == caps_button: - caps = event.active - return + backspace_button.on_button_down.connect(func(): + _emit_event("key_down", KEY_BACKSPACE) + ) - var code = event.target.get_children()[event.target.get_child_count() - 1].text + backspace_button.on_button_up.connect(func(): + _emit_event("key_up", KEY_BACKSPACE) + ) - if caps: - code = code.to_upper() - else: - code = code.to_lower() + caps_button.on_button_down.connect(func(): + caps = true + _emit_event("key_down", KEY_CAPSLOCK) + ) - Events.typed.emit(code) - print(code) + caps_button.on_button_up.connect(func(): + caps = false + _emit_event("key_up", KEY_CAPSLOCK) + ) -func create_key(key: String): +func create_key(key: Key): var button = button_scene.instantiate() var label = Label3D.new() - label.text = key + label.text = EventKey.key_to_string(key, caps) label.pixel_size = 0.001 label.position = Vector3(0, 0.012, 0) label.rotate_x(deg_to_rad(-90)) + label.add_to_group("button_label") + + button.set_meta("key", key) button.add_child(label) return button + +func update_labels(): + for key_button in keys.get_children(): + var label = key_button.get_children()[key_button.get_children().size() - 1] + if caps: + label.text = label.text.to_upper() + else: + label.text = label.text.to_lower() + +func _emit_event(type: String, key: Key): + var event = EventKey.new() + event.key = key + event.shift_pressed = caps + + EventSystem.emit(type, event) + print("Emitting event: " + type + " " + EventKey.key_to_string(key, caps)) + diff --git a/content/ui/keyboard/keyboard.tscn b/content/ui/keyboard/keyboard.tscn index 721e0bd..0e7e822 100644 --- a/content/ui/keyboard/keyboard.tscn +++ b/content/ui/keyboard/keyboard.tscn @@ -1,14 +1,28 @@ -[gd_scene load_steps=4 format=3 uid="uid://lrehk38exd5n"] +[gd_scene load_steps=6 format=3 uid="uid://lrehk38exd5n"] [ext_resource type="Script" path="res://content/ui/keyboard/keyboard.gd" id="1_maojw"] [ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="1_xdpwr"] [ext_resource type="Script" path="res://content/ui/menu/grid.gd" id="3_mx544"] +[ext_resource type="Script" path="res://content/functions/movable.gd" id="4_86fct"] -[node name="Keyboard" type="Node3D"] +[sub_resource type="BoxShape3D" id="BoxShape3D_k5ib7"] +size = Vector3(0.744504, 0.0402036, 0.296009) + +[node name="Keyboard" type="StaticBody3D"] +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="." instance=ExtResource("1_xdpwr")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.66, 0, 0.02) +metadata/key = 4194308 + +[node name="Label3D" type="Label3D" parent="Backspace"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.012, 0) +pixel_size = 0.001 +text = "back" + [node name="Caps" parent="." instance=ExtResource("1_xdpwr")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0668889, 0, 0.03) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.06, 0, 0.15) toggleable = true [node name="Label3D" type="Label3D" parent="Caps"] @@ -18,6 +32,13 @@ text = "caps" [node name="Keys" type="Node3D" parent="."] script = ExtResource("3_mx544") -columns = 1 +columns = 11 depth_gap = 0.06 size = Vector3(0.6, 1, 1) + +[node name="Movable" type="Node" parent="."] +script = ExtResource("4_86fct") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.276719, -0.025645, 0.0928761) +shape = SubResource("BoxShape3D_k5ib7") diff --git a/lib/events/event.gd b/lib/events/event.gd new file mode 100644 index 0000000..33779f8 --- /dev/null +++ b/lib/events/event.gd @@ -0,0 +1,9 @@ +extends Resource +class_name Event + +func merge(event: Event): + assert(self.is_class(event.get_class()), "Can only merge events of the same type.") + + for prop in event.get_property_list(): + if prop.name in self: + self.set(prop.name, event.get(prop.name)) diff --git a/lib/events/event_bubble.gd b/lib/events/event_bubble.gd new file mode 100644 index 0000000..a72ca89 --- /dev/null +++ b/lib/events/event_bubble.gd @@ -0,0 +1,5 @@ +extends Event +class_name EventBubble + +var bubbling := true +var target: Node \ No newline at end of file diff --git a/lib/events/event_key.gd b/lib/events/event_key.gd new file mode 100644 index 0000000..a7fe112 --- /dev/null +++ b/lib/events/event_key.gd @@ -0,0 +1,16 @@ +extends EventWithModifiers +class_name EventKey + +var key: Key +var echo: bool + +static func key_to_string(key: Key, caps: bool = false) -> String: + match key: + KEY_ASCIITILDE: return "~" + KEY_SLASH: return "/" + KEY_BACKSLASH: return "\\" + KEY_COLON: return ";" + KEY_COMMA: return "," + KEY_PERIOD: return "." + KEY_MINUS: return "-" + _: return OS.get_keycode_string(key).to_upper() if caps else OS.get_keycode_string(key).to_lower() \ No newline at end of file diff --git a/lib/events/event_ray.gd b/lib/events/event_ray.gd new file mode 100644 index 0000000..aa2765d --- /dev/null +++ b/lib/events/event_ray.gd @@ -0,0 +1,6 @@ +extends EventBubble +class_name EventRay + +var controller: XRController3D +var is_right_controller: bool +var ray: RayCast3D \ No newline at end of file diff --git a/lib/events/event_with_modifiers.gd b/lib/events/event_with_modifiers.gd new file mode 100644 index 0000000..14a7389 --- /dev/null +++ b/lib/events/event_with_modifiers.gd @@ -0,0 +1,7 @@ +extends Event +class_name EventWithModifiers + +var alt_pressed := false +var shift_pressed := false +var control_pressed := false +var meta_pressed := false \ No newline at end of file diff --git a/lib/globals/event_system.gd b/lib/globals/event_system.gd new file mode 100644 index 0000000..8e3d9e6 --- /dev/null +++ b/lib/globals/event_system.gd @@ -0,0 +1,55 @@ +extends Node + +const FN_PREFIX = "_on_" +const SIGNAL_PREFIX = "on_" + +# Interaction Events +signal on_click(event: EventRay) +signal on_press_down(event: EventRay) +signal on_press_move(event: EventRay) +signal on_press_up(event: EventRay) +signal on_grab_down(event: EventRay) +signal on_grab_move(event: EventRay) +signal on_grab_up(event: EventRay) +signal on_ray_enter(event: EventRay) +signal on_ray_leave(event: EventRay) + +signal on_key_down(event: EventKey) +signal on_key_up(event: EventKey) + +func emit(type: String, event: Event): + if event is EventBubble: + _bubble_call(type, event.target, event) + else: + _root_call(type, event) + + +func _bubble_call(type: String, target: Variant, event: EventBubble): + if target == null: + return + + if target.has_method(FN_PREFIX + type): + var updated_event = target.call(FN_PREFIX + type, event) + + if updated_event is EventBubble: + updated_event.merge(event) + event = updated_event + + if event.bubbling == false: + return + + for child in target.get_children(): + if child is Function && child.has_method(FN_PREFIX + type): + child.call(FN_PREFIX + type, event) + + var parent = target.get_parent() + + if parent != null && parent is Node: + _bubble_call(type, parent, event) + else: + # in case the top has been reached + _root_call(type, event) + + +func _root_call(type: String, event: Event): + get(SIGNAL_PREFIX + type).emit(event) diff --git a/lib/globals/events.gd b/lib/globals/events.gd deleted file mode 100644 index 6fa7e02..0000000 --- a/lib/globals/events.gd +++ /dev/null @@ -1,15 +0,0 @@ -# Global event bus -extends Node - -# Interaction Events -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) - -signal typed(key: String) \ No newline at end of file diff --git a/lib/home_adapters/hass_ws/hass.gd b/lib/home_adapters/hass_ws/hass.gd index 7479829..0a413b3 100644 --- a/lib/home_adapters/hass_ws/hass.gd +++ b/lib/home_adapters/hass_ws/hass.gd @@ -16,6 +16,7 @@ var authenticated := false var loading := true var id := 1 var entities: Dictionary = {} +var retries := 5 var entitiy_callbacks := CallbackMap.new() var packet_callbacks := CallbackMap.new() @@ -31,6 +32,11 @@ func _init(url := self.url, token := self.token): connect_ws() func connect_ws(): + retries -= 1 + if retries < 0: + print("Failed to connect to %s" % self.url) + return + print("Connecting to %s" % self.url) socket.connect_to_url(self.url) set_process(true) diff --git a/project.godot b/project.godot index 73ec25b..5bcc1f1 100644 --- a/project.godot +++ b/project.godot @@ -21,7 +21,7 @@ XRToolsUserSettings="*res://addons/godot-xr-tools/user_settings/user_settings.gd Request="*res://lib/globals/request.gd" HomeAdapters="*res://lib/globals/home_adapters.gd" AudioPlayer="*res://lib/globals/audio_player.gd" -Events="*res://lib/globals/events.gd" +EventSystem="*res://lib/globals/event_system.gd" [editor_plugins]