Add virtua hand lighting up floor buttons!
- hand sweeps down the button panel at game start - button panel now spawns its floor buttons procedurally via button_panel.gd - elevator_panel waits for the new intro_finished signal before starting floor 1 - removes the stray ShaftStrip from hud.tscn - cleaned up timing but henry will probably want to tune further
This commit is contained in:
parent
046ae6f8a0
commit
fae69c4816
13 changed files with 201 additions and 82 deletions
114
scenes/left_hand.gd
Normal file
114
scenes/left_hand.gd
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
extends Sprite3D
|
||||
|
||||
const INTRO_DURATION := 1.5
|
||||
const ENTRY_OFFSET := 0.5
|
||||
const EXIT_OFFSET := 0.5
|
||||
const FORWARD_OFFSET := 0.05
|
||||
const FINGER_OFFSET_X := 0.0
|
||||
|
||||
@onready var _button_panel: Node3D = get_parent().get_node("ButtonPanel")
|
||||
|
||||
var _buttons: Array = []
|
||||
var _intro_playing := false
|
||||
var _sprite_half_h := 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
visible = false
|
||||
_sprite_half_h = texture.get_height() * pixel_size * global_transform.basis.get_scale().y * 0.5
|
||||
|
||||
EventBus.game_started.connect(_play_intro)
|
||||
EventBus.floor_changed.connect(_on_floor_changed)
|
||||
|
||||
func _ensure_buttons() -> void:
|
||||
if not _buttons.is_empty():
|
||||
return
|
||||
_buttons = _collect_buttons()
|
||||
if not _buttons.is_empty():
|
||||
_set_all_lit(false)
|
||||
|
||||
func _collect_buttons() -> Array:
|
||||
var arr: Array = []
|
||||
var container = _button_panel.get_node_or_null("FloorButtons")
|
||||
if container == null or container.get_child_count() == 0:
|
||||
container = _button_panel
|
||||
for i in range(10):
|
||||
var button_name := "%02d" % i
|
||||
var btn = container.get_node_or_null(button_name)
|
||||
if btn != null:
|
||||
arr.append(btn)
|
||||
return arr
|
||||
|
||||
func _play_intro() -> void:
|
||||
if _intro_playing:
|
||||
return
|
||||
_intro_playing = true
|
||||
|
||||
_ensure_buttons()
|
||||
if _buttons.size() < 10:
|
||||
_intro_playing = false
|
||||
EventBus.intro_finished.emit()
|
||||
return
|
||||
|
||||
_set_all_lit(false)
|
||||
|
||||
# animate the hand's global_position.y from start to end over a set duration
|
||||
# each button gets a sibling callback scheduled in *parallel*!
|
||||
# what fraction of the way from start to end is this button's Y?
|
||||
# to figure out when to fire callback on set_delay() to stagge.3.r
|
||||
# this way it is easy to change the duration if we want
|
||||
|
||||
var top_button: Node3D = _buttons[9]
|
||||
var bottom_button: Node3D = _buttons[0]
|
||||
var camera = get_viewport().get_camera_3d()
|
||||
var camera_pos = camera.global_position if camera else Vector3.ZERO
|
||||
var button_z = top_button.global_position.z
|
||||
var hand_z = button_z - FORWARD_OFFSET
|
||||
var z_ratio = (hand_z - camera_pos.z) / (button_z - camera_pos.z)
|
||||
|
||||
var hand_x = camera_pos.x + (top_button.global_position.x - camera_pos.x) * z_ratio + FINGER_OFFSET_X
|
||||
|
||||
var finger_start_y_world = top_button.global_position.y + ENTRY_OFFSET
|
||||
var finger_end_y_world = bottom_button.global_position.y - EXIT_OFFSET
|
||||
var finger_start_y = camera_pos.y + (finger_start_y_world - camera_pos.y) * z_ratio
|
||||
var finger_end_y = camera_pos.y + (finger_end_y_world - camera_pos.y) * z_ratio
|
||||
|
||||
var sprite_start_y = finger_start_y - _sprite_half_h
|
||||
var sprite_end_y = finger_end_y - _sprite_half_h
|
||||
|
||||
global_position = Vector3(hand_x, sprite_start_y, hand_z)
|
||||
visible = true
|
||||
|
||||
var tween := create_tween().set_parallel(true)
|
||||
tween.tween_property(self, "global_position:y", sprite_end_y, INTRO_DURATION)
|
||||
|
||||
for i in range(_buttons.size()):
|
||||
var button_y_world = _buttons[i].global_position.y
|
||||
# weird thing: button_y is projected onto the hand's Z-plane to account for perspective
|
||||
# to keep the fingertip visually aligned with each button at the exact right moment
|
||||
var button_y_proj = camera_pos.y + (button_y_world - camera_pos.y) * z_ratio
|
||||
var t_fraction = (finger_start_y - button_y_proj) / (finger_start_y - finger_end_y)
|
||||
t_fraction = clamp(t_fraction, 0.0, 1.0)
|
||||
tween.tween_callback(_light_button.bind(i)).set_delay(t_fraction * INTRO_DURATION)
|
||||
|
||||
await tween.finished
|
||||
visible = false
|
||||
_intro_playing = false
|
||||
EventBus.intro_finished.emit()
|
||||
|
||||
func _light_button(index: int) -> void:
|
||||
var sprite: Sprite3D = _buttons[index].get_node("ButtonSprite")
|
||||
sprite.frame = index + 10
|
||||
|
||||
func _set_all_lit(lit: bool) -> void:
|
||||
for i in range(_buttons.size()):
|
||||
var sprite: Sprite3D = _buttons[i].get_node("ButtonSprite")
|
||||
sprite.frame = i + (10 if lit else 0)
|
||||
|
||||
func _on_floor_changed(floor_num: int) -> void:
|
||||
if floor_num >= EventBus.STARTING_FLOOR:
|
||||
return
|
||||
_ensure_buttons()
|
||||
if floor_num < 0 or floor_num >= _buttons.size():
|
||||
return
|
||||
var sprite: Sprite3D = _buttons[floor_num].get_node("ButtonSprite")
|
||||
sprite.frame = floor_num
|
||||
Loading…
Add table
Add a link
Reference in a new issue