tojam20-elevator/scenes/virtua_hand.gd

81 lines
3.1 KiB
GDScript

extends Sprite3D
const SLIDE_DURATION := 0.25
const UP_DURATION := 0.1
const HOLD_DURATION := 0.05
const DOWN_DURATION := 0.18
const ENTRY_OFFSET := 0.5
const ENTRY_DURATION := 0.5
var _open_button: Node3D
var _close_button: Node3D
var _target_button: Node3D
var _close_rest_x: float
var _open_rest_x: float
var _rest_y: float
var _slide_tween: Tween
var _press_tween: Tween
func _ready() -> void:
if not get_parent().is_node_ready():
await get_parent().ready
await get_tree().process_frame
_open_button = get_parent().get_node("DoorOpen")
_close_button = get_parent().get_node("DoorClose")
_close_rest_x = _project_to_hand_plane(_close_button)
_open_rest_x = _project_to_hand_plane(_open_button)
_rest_y = position.y
_target_button = _close_button
position = Vector3(_close_rest_x, _rest_y, position.z)
visible = false
print("[VirtuaHand] close_x=", _close_rest_x, " open_x=", _open_rest_x, " hand_pos=", position)
EventBus.button_pressed.connect(_animate_press)
EventBus.active_button_changed.connect(_on_active_button_changed)
EventBus.intro_finished.connect(_on_intro_finished)
func _on_intro_finished() -> void:
var sprite_height := texture.get_height() * pixel_size * scale.y
position.y = _rest_y - sprite_height - ENTRY_OFFSET
visible = true
var entry_tween := create_tween()
entry_tween.tween_property(self, "position:y", _rest_y, ENTRY_DURATION).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
func _project_to_hand_plane(button: Node3D) -> float:
var cam := get_viewport().get_camera_3d()
if not cam:
return button.position.x
var screen_pos := cam.unproject_position(button.global_position)
var ray_origin := cam.project_ray_origin(screen_pos)
var ray_dir := cam.project_ray_normal(screen_pos)
if absf(ray_dir.z) < 0.0001:
return button.position.x
var t := (global_position.z - ray_origin.z) / ray_dir.z
var hit := ray_origin + ray_dir * t
return get_parent().to_local(hit).x
func _on_active_button_changed(target: String) -> void:
var new_button: Node3D = _open_button if target == "open" else _close_button
if new_button == _target_button:
return
_target_button = new_button
var target_x: float = _open_rest_x if target == "open" else _close_rest_x
print("[VirtuaHand] slide target=", target, " target_x=", target_x, " current_pos=", position)
if _press_tween and _press_tween.is_valid():
_press_tween.kill()
if _slide_tween and _slide_tween.is_valid():
_slide_tween.kill()
_slide_tween = create_tween()
_slide_tween.tween_property(self, "position:x", target_x, SLIDE_DURATION).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
func _animate_press() -> void:
if not is_instance_valid(_target_button):
return
if _press_tween and _press_tween.is_valid():
_press_tween.kill()
var fingertip_offset := texture.get_height() * 0.5 * pixel_size * scale.y
var press_y := _target_button.position.y - fingertip_offset
_press_tween = create_tween()
_press_tween.tween_property(self, "position:y", press_y, UP_DURATION).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
_press_tween.tween_interval(HOLD_DURATION)
_press_tween.tween_property(self, "position:y", _rest_y, DOWN_DURATION).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)