update interaction system
This commit is contained in:
parent
9ff35349a1
commit
c240efa56f
31
README.md
31
README.md
|
@ -65,30 +65,29 @@ func watch_state(entity: String, callback: Callable[entity: Entity]) -> Callable
|
||||||
|
|
||||||
### Interaction Events
|
### Interaction Events
|
||||||
|
|
||||||
Each time a button is pressed on the primary controller, a raycast is done to be able to interact with devices or the UI.
|
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.
|
||||||
|
|
||||||
**InteractionEvent**
|
```python
|
||||||
```js
|
InteractionEvent {
|
||||||
{
|
"controller": XRController3D, # The controller that triggered the event
|
||||||
position: Vector3,
|
"ray": RayCast3D, # The ray-cast that triggered the event
|
||||||
rotation: Vector3
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
| Function called | Args | Description |
|
| Function called | Args | Description |
|
||||||
| -- | -- | -- |
|
| -- | -- | -- |
|
||||||
| `_click` | `[event: InteractionEvent]` | The back trigger button has been pressed and released |
|
| `_on_click` | `[event: InteractionEvent]` | The back trigger button has been pressed and released |
|
||||||
| `_dbl_click` | `[event: InteractionEvent]` | The back trigger button has been pressed and released twice in a row |
|
| `_on_press_down` | `[event: InteractionEvent]` | The back trigger button has been pressed down |
|
||||||
| `_long_click` | `[event: InteractionEvent]` | The back trigger button has been pressed, then hold still for a short period, then released |
|
| `_on_press_move` | `[event: InteractionEvent]` | The back trigger button has been moved while pressed down |
|
||||||
| `_press_down` | `[event: InteractionEvent]` | The back trigger button has been pressed down |
|
| `_on_press_up` | `[event: InteractionEvent]` | The back trigger button has been released |
|
||||||
| `_press_move` | `[event: InteractionEvent]` | The back trigger button has been moved while pressed down |
|
| `_on_grab_down` | `[event: InteractionEvent]` | The side grab button been pressed down |
|
||||||
| `_press_up` | `[event: InteractionEvent]` | The back trigger button has been released |
|
| `_on_grab_move` | `[event: InteractionEvent]` | The side grab button been pressed down |
|
||||||
| `_grab_down` | `[event: InteractionEvent]` | The side grap button been pressed down |
|
| `_on_grab_up` | `[event: InteractionEvent]` | The side grab button been released |
|
||||||
| `_grab_move` | `[event: InteractionEvent]` | The side grap button been pressed down |
|
| `_on_ray_enter` | `[event: InteractionEvent]` | The ray-cast enters the the collision body |
|
||||||
| `_grab_up` | `[event: InteractionEvent]` | The side grap button been released |
|
| `_on_ray_leave` | `[event: InteractionEvent]` | The ray-cast leaves the the collision body |
|
||||||
|
|
||||||
### Testing without a VR Headset
|
### 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.
|
In order to test without a headset, press the run project (F5) button in Godot and ignore the prompt that OpenXR failed to start.
|
||||||
To simulate the headset and controller movement, we're using the [XR Input Simulator](https://godotengine.org/asset-library/asset/1775) asset.
|
To simulate the headset and controller movement, we're using the [XR Input Simulator](https://godotengine.org/asset-library/asset/1775) asset.
|
||||||
Click at the link to get a list of the supported controlls.
|
Click at the link to get a list of the supported controls.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=12 format=3 uid="uid://eecv28y6jxk4"]
|
[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="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"]
|
||||||
[ext_resource type="Script" path="res://src/raycast.gd" id="1_tsqxc"]
|
[ext_resource type="Script" path="res://src/raycast.gd" id="1_tsqxc"]
|
||||||
|
@ -7,6 +7,7 @@
|
||||||
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://scenes/menu.tscn" id="3_1tbp3"]
|
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://scenes/menu.tscn" id="3_1tbp3"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="5_3qc8g"]
|
[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="Material" uid="uid://bf5ina366dwm6" path="res://assets/materials/sky.material" id="5_wgwf8"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cscl5k7lhopj5" path="res://scenes/entities/switch.tscn" id="8_uxmrb"]
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"]
|
||||||
ao_enabled = true
|
ao_enabled = true
|
||||||
|
@ -76,3 +77,7 @@ shadow_enabled = true
|
||||||
|
|
||||||
[node name="XRSimulator" parent="." instance=ExtResource("5_3qc8g")]
|
[node name="XRSimulator" parent="." instance=ExtResource("5_3qc8g")]
|
||||||
xr_origin = NodePath("../XROrigin3D")
|
xr_origin = NodePath("../XROrigin3D")
|
||||||
|
|
||||||
|
[node name="Switch" parent="." instance=ExtResource("8_uxmrb")]
|
||||||
|
transform = Transform3D(0.999999, -1.39635e-11, 0, 9.48031e-12, 1, 0, 0, 0, 1, 0.564168, 0.725642, -1.56163)
|
||||||
|
entity_id = "switch.plug_printer_2_fale"
|
||||||
|
|
|
@ -6,6 +6,9 @@ extends StaticBody3D
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
var stateInfo = await HomeAdapters.adapter_ws.get_state(entity_id)
|
var stateInfo = await HomeAdapters.adapter_ws.get_state(entity_id)
|
||||||
|
if stateInfo == null:
|
||||||
|
return
|
||||||
|
|
||||||
if stateInfo["state"] == "on":
|
if stateInfo["state"] == "on":
|
||||||
sprite.set_frame(0)
|
sprite.set_frame(0)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -10,6 +10,7 @@ var token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzZjQ0ZGM2N2Y3YzY0M
|
||||||
var LOG_MESSAGES := false
|
var LOG_MESSAGES := false
|
||||||
|
|
||||||
var authenticated := false
|
var authenticated := false
|
||||||
|
var loading := true
|
||||||
var id := 1
|
var id := 1
|
||||||
var entities: Dictionary = {}
|
var entities: Dictionary = {}
|
||||||
|
|
||||||
|
@ -100,6 +101,7 @@ func start_subscriptions():
|
||||||
"attributes": packet.event.a[entity]["a"]
|
"attributes": packet.event.a[entity]["a"]
|
||||||
}
|
}
|
||||||
entitiy_callbacks.call_key(entity, [entities[entity]])
|
entitiy_callbacks.call_key(entity, [entities[entity]])
|
||||||
|
loading = false
|
||||||
on_connect.emit()
|
on_connect.emit()
|
||||||
|
|
||||||
if packet.event.has("c"):
|
if packet.event.has("c"):
|
||||||
|
@ -171,13 +173,13 @@ func encode_packet(packet: Dictionary):
|
||||||
return JSON.stringify(packet)
|
return JSON.stringify(packet)
|
||||||
|
|
||||||
func load_devices():
|
func load_devices():
|
||||||
if !authenticated:
|
if loading:
|
||||||
await on_connect
|
await on_connect
|
||||||
|
|
||||||
return entities
|
return entities
|
||||||
|
|
||||||
func get_state(entity: String):
|
func get_state(entity: String):
|
||||||
if !authenticated:
|
if loading:
|
||||||
await on_connect
|
await on_connect
|
||||||
|
|
||||||
if entities.has(entity):
|
if entities.has(entity):
|
||||||
|
@ -186,14 +188,14 @@ func get_state(entity: String):
|
||||||
|
|
||||||
|
|
||||||
func watch_state(entity: String, callback: Callable):
|
func watch_state(entity: String, callback: Callable):
|
||||||
if !authenticated:
|
if loading:
|
||||||
await on_connect
|
await on_connect
|
||||||
|
|
||||||
entitiy_callbacks.add(entity, callback)
|
entitiy_callbacks.add(entity, callback)
|
||||||
|
|
||||||
|
|
||||||
func set_state(entity: String, state: String, attributes: Dictionary = {}):
|
func set_state(entity: String, state: String, attributes: Dictionary = {}):
|
||||||
assert(authenticated, "Not authenticated")
|
assert(!loading, "Still loading")
|
||||||
|
|
||||||
var domain = entity.split(".")[0]
|
var domain = entity.split(".")[0]
|
||||||
var service: String
|
var service: String
|
||||||
|
|
|
@ -5,23 +5,92 @@ extends Node3D
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
_controller.button_pressed.connect(self._on_button_pressed)
|
_controller.button_pressed.connect(_on_button_pressed)
|
||||||
|
_controller.button_released.connect(_on_button_released)
|
||||||
|
|
||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
var _last_collided: Object = null
|
||||||
func _process(delta):
|
var _is_pressed := false
|
||||||
pass
|
var _is_grabbed := false
|
||||||
|
var _moved := false
|
||||||
|
var _click_point := Vector3.ZERO
|
||||||
|
|
||||||
func _on_button_pressed(button):
|
func _physics_process(delta):
|
||||||
print(button)
|
_handle_enter_leave()
|
||||||
if button != "trigger_click":
|
_handle_move()
|
||||||
|
|
||||||
|
func _get_event_data():
|
||||||
|
return {
|
||||||
|
"controller": _controller,
|
||||||
|
"ray": ray,
|
||||||
|
}
|
||||||
|
|
||||||
|
func _handle_move():
|
||||||
|
var distance = ray.get_collision_point().distance_to(_click_point)
|
||||||
|
|
||||||
|
if distance > 0.01:
|
||||||
|
if _is_pressed:
|
||||||
|
_call_fn("_on_press_move")
|
||||||
|
_moved = true
|
||||||
|
if _is_grabbed:
|
||||||
|
_call_fn("_on_grab_move")
|
||||||
|
_moved = true
|
||||||
|
|
||||||
|
func _handle_enter_leave():
|
||||||
|
var collider = ray.get_collider()
|
||||||
|
|
||||||
|
if collider == _last_collided:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if _last_collided != null && _last_collided.has_method("_on_ray_enter"):
|
||||||
|
_last_collided._on_ray_enter(_get_event_data())
|
||||||
|
|
||||||
|
if collider != null && collider.has_method("_on_ray_leave"):
|
||||||
|
collider._on_ray_leave(_get_event_data())
|
||||||
|
|
||||||
|
_last_collided = collider
|
||||||
|
|
||||||
|
func _on_button_pressed(button):
|
||||||
var collider = ray.get_collider()
|
var collider = ray.get_collider()
|
||||||
|
|
||||||
if collider == null:
|
if collider == null:
|
||||||
return
|
return
|
||||||
|
|
||||||
print(collider)
|
match button:
|
||||||
|
"trigger_click":
|
||||||
|
_is_pressed = true
|
||||||
|
_click_point = ray.get_collision_point()
|
||||||
|
_call_fn("_on_press_down")
|
||||||
|
"grip_click":
|
||||||
|
_is_grabbed = true
|
||||||
|
_click_point = ray.get_collision_point()
|
||||||
|
_call_fn("_on_grab_down")
|
||||||
|
|
||||||
if collider.has_method("_on_toggle"):
|
func _on_button_released(button):
|
||||||
collider._on_toggle()
|
var collider = ray.get_collider()
|
||||||
|
|
||||||
|
if collider == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
match button:
|
||||||
|
"trigger_click":
|
||||||
|
if _is_pressed:
|
||||||
|
if _moved == false:
|
||||||
|
_call_fn("_on_click")
|
||||||
|
_call_fn("_on_press_up")
|
||||||
|
_is_pressed = false
|
||||||
|
_moved = false
|
||||||
|
"grip_click":
|
||||||
|
if _is_grabbed:
|
||||||
|
_call_fn("_on_grab_up")
|
||||||
|
_is_grabbed = false
|
||||||
|
_moved = false
|
||||||
|
|
||||||
|
func _call_fn(fn_name: String):
|
||||||
|
print("call_fn", fn_name)
|
||||||
|
var collider = ray.get_collider()
|
||||||
|
|
||||||
|
if collider == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if collider.has_method(fn_name):
|
||||||
|
collider.call(fn_name, _get_event_data())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user