This commit is contained in:
Henry 2026-05-11 15:48:09 +01:00
commit b6812cf8d0
12 changed files with 84 additions and 71 deletions

View file

@ -7,7 +7,7 @@ var _active_walkers: Array[Node] = []
var _batch_generation: int = 0 var _batch_generation: int = 0
@onready var survivor = preload("res://scenes/survivor.tscn") @onready var survivor = preload("res://scenes/survivor.tscn")
@onready var survivor_spawn = get_node("/root/Game/World/SuvivorSpawn") @onready var survivor_spawn = get_node("/root/Game/World/SurvivorSpawn")
@onready var start_pos: Vector3 = survivor_spawn.global_position @onready var start_pos: Vector3 = survivor_spawn.global_position
func _enter_tree() -> void: func _enter_tree() -> void:
@ -38,6 +38,6 @@ func _run_batch(count: int, generation: int) -> void:
func _spawn_one() -> void: func _spawn_one() -> void:
var s = survivor.instantiate() var s = survivor.instantiate()
var offset := Vector3(randf_range(-lateral_variance, lateral_variance), 0, 0) var offset := Vector3(randf_range(-lateral_variance, lateral_variance), 0, 0)
get_tree().root.add_child.call_deferred(s) add_child.call_deferred(s)
s.position = start_pos + offset s.position = start_pos + offset
_active_walkers.append(s) _active_walkers.append(s)

View file

@ -11,23 +11,32 @@ var _tween: Tween = null
func _ready(): func _ready():
$ElevatorDoorRight.position = Vector3(DOOR_CLOSED_X, 0, 0) $ElevatorDoorRight.position = Vector3(DOOR_CLOSED_X, 0, 0)
$ElevatorDoorLeft.position = Vector3(-DOOR_CLOSED_X, 0, 0) $ElevatorDoorLeft.position = Vector3(-DOOR_CLOSED_X, 0, 0)
_set_door_collision(true)
EventBus.doors_opened.connect(_on_doors_opened) EventBus.doors_opened.connect(_on_doors_opened)
EventBus.doors_closed.connect(_on_doors_closed) EventBus.doors_closed.connect(_on_doors_closed)
EventBus.pulse_started.connect(_on_pulse_started) EventBus.pulse_started.connect(_on_pulse_started)
EventBus.pulse_blocked.connect(_on_pulse_blocked) EventBus.pulse_blocked.connect(_on_pulse_blocked)
func _on_doors_opened(): func _on_doors_opened():
_set_door_collision(false)
_tween_doors(DOOR_OPEN_X, DOOR_DEFAULT_TIME) _tween_doors(DOOR_OPEN_X, DOOR_DEFAULT_TIME)
func _on_doors_closed(fast: bool): func _on_doors_closed(fast: bool):
_set_door_collision(true)
_tween_doors(DOOR_CLOSED_X, DOOR_FAST_CLOSE_TIME if fast else DOOR_DEFAULT_TIME) _tween_doors(DOOR_CLOSED_X, DOOR_FAST_CLOSE_TIME if fast else DOOR_DEFAULT_TIME)
func _on_pulse_started(duration: float): func _on_pulse_started(duration: float):
_set_door_collision(true)
_tween_doors(DOOR_CLOSED_X, duration) _tween_doors(DOOR_CLOSED_X, duration)
func _on_pulse_blocked(): func _on_pulse_blocked():
_set_door_collision(false)
_tween_doors(DOOR_OPEN_X, DOOR_REOPEN_TIME) _tween_doors(DOOR_OPEN_X, DOOR_REOPEN_TIME)
func _set_door_collision(enabled: bool):
$ElevatorDoorRight/CollisionShape3D.disabled = not enabled
$ElevatorDoorLeft/CollisionShape3D.disabled = not enabled
func _tween_doors(target_x: float, duration: float): func _tween_doors(target_x: float, duration: float):
if _tween: if _tween:
_tween.kill() _tween.kill()

View file

@ -1,6 +1,9 @@
extends PanelContainer extends PanelContainer
var current_floor := 10 @onready var _screen = $PanelMargin/PanelColumn/Screen
@onready var _close_button: Button = $PanelMargin/PanelColumn/CloseButton
var current_floor: int = EventBus.STARTING_FLOOR
var saved_count := 0 var saved_count := 0
var doors_closing_flag := false var doors_closing_flag := false
var _onboarded := false var _onboarded := false
@ -30,15 +33,13 @@ const PERFECT_STUN_DURATION := 0.25
const PRE_PULSE_DELAY := 3.5 const PRE_PULSE_DELAY := 3.5
func _ready(): func _ready():
var button = $PanelMargin/PanelColumn/CloseButton _close_button.text = "CLOSE"
button.text = "CLOSE" _close_button.pressed.connect(_on_block_pressed)
button.pressed.connect(_on_block_pressed)
var screen = $PanelMargin/PanelColumn/Screen _screen.pulse_started.connect(_on_pulse_started)
screen.pulse_started.connect(_on_pulse_started) _screen.pulse_blocked.connect(_on_pulse_blocked)
screen.pulse_blocked.connect(_on_pulse_blocked) _screen.pulse_blocked_perfect.connect(_on_pulse_blocked_perfect)
screen.pulse_blocked_perfect.connect(_on_pulse_blocked_perfect) _screen.doors_closing.connect(func(): _on_doors_closing(true))
screen.doors_closing.connect(func(): _on_doors_closing(true))
EventBus.game_started.connect(_start_floor) EventBus.game_started.connect(_start_floor)
@ -54,7 +55,7 @@ func _start_floor():
$SfxBell.play() $SfxBell.play()
doors_closing_flag = false doors_closing_flag = false
people_in_elevator = 0 people_in_elevator = 0
$PanelMargin/PanelColumn/CloseButton.text = "CLOSE" _close_button.text = "CLOSE"
EventBus.doors_opened.emit() EventBus.doors_opened.emit()
var floors_remaining = current_floor - 1 var floors_remaining = current_floor - 1
@ -64,27 +65,26 @@ func _start_floor():
EventBus.floor_changed.emit(current_floor) EventBus.floor_changed.emit(current_floor)
EventBus.floor_started.emit(survivors_remaining) EventBus.floor_started.emit(survivors_remaining)
var floors_descended = 10 - current_floor var floors_descended = EventBus.STARTING_FLOOR - current_floor
var robot_speed = robot_speed_top + floors_descended * robot_speed_per_floor var robot_speed = robot_speed_top + floors_descended * robot_speed_per_floor
var robot_delay = max(robot_delay_min, robot_delay_top - floors_descended * robot_delay_per_floor) var robot_delay = max(robot_delay_min, robot_delay_top - floors_descended * robot_delay_per_floor)
EventBus.robot_floor_started.emit(robot_delay, robot_speed) EventBus.robot_floor_started.emit(robot_delay, robot_speed)
var screen = $PanelMargin/PanelColumn/Screen _screen.start(current_floor)
screen.start(current_floor)
if current_floor <= MOVING_ZONE_START_FLOOR: if current_floor <= MOVING_ZONE_START_FLOOR:
var floors_below = MOVING_ZONE_START_FLOOR - current_floor var floors_below = MOVING_ZONE_START_FLOOR - current_floor
screen.set_block_zone_movement(MOVING_ZONE_BASE_SPEED + floors_below * MOVING_ZONE_SPEED_PER_FLOOR) _screen.set_block_zone_movement(MOVING_ZONE_BASE_SPEED + floors_below * MOVING_ZONE_SPEED_PER_FLOOR)
if not _onboarded: if not _onboarded:
_onboarded = true _onboarded = true
screen.show_onboarding("BLOCK\nIN GREEN ZONE") _screen.show_onboarding("BLOCK\nIN GREEN ZONE")
get_tree().create_timer(3.0).timeout.connect( get_tree().create_timer(3.0).timeout.connect(
func(): func():
if not is_instance_valid(screen): if not is_instance_valid(_screen):
return return
screen.end_onboarding() _screen.end_onboarding()
screen.launch_pulse(), _screen.launch_pulse(),
CONNECT_ONE_SHOT CONNECT_ONE_SHOT
) )
else: else:
@ -92,28 +92,27 @@ func _start_floor():
func(): func():
if not is_instance_valid(self) or doors_closing_flag: if not is_instance_valid(self) or doors_closing_flag:
return return
screen.launch_pulse(), _screen.launch_pulse(),
CONNECT_ONE_SHOT CONNECT_ONE_SHOT
) )
func _on_block_pressed(): func _on_block_pressed():
if doors_closing_flag: if doors_closing_flag:
return return
var screen = $PanelMargin/PanelColumn/Screen if _screen.pulse_active:
if screen.pulse_active: _screen.attempt_block()
screen.attempt_block()
else: else:
_on_doors_closing(false) _on_doors_closing(false)
func _on_pulse_started(duration: float): func _on_pulse_started(duration: float):
$PanelMargin/PanelColumn/CloseButton.text = "BLOCK" _close_button.text = "BLOCK"
EventBus.pulse_started.emit(duration) EventBus.pulse_started.emit(duration)
func _on_pulse_blocked_perfect(): func _on_pulse_blocked_perfect():
EventBus.robot_stun_requested.emit(PERFECT_STUN_DURATION) EventBus.robot_stun_requested.emit(PERFECT_STUN_DURATION)
func _on_pulse_blocked(): func _on_pulse_blocked():
$PanelMargin/PanelColumn/CloseButton.text = "CLOSE" _close_button.text = "CLOSE"
EventBus.pulse_blocked.emit() EventBus.pulse_blocked.emit()
survivors_remaining -= 1 survivors_remaining -= 1
people_in_elevator += 1 people_in_elevator += 1
@ -124,12 +123,11 @@ func _on_pulse_blocked():
get_tree().create_timer(0.25).timeout.connect(_on_doors_closing, CONNECT_ONE_SHOT) get_tree().create_timer(0.25).timeout.connect(_on_doors_closing, CONNECT_ONE_SHOT)
return return
var screen = $PanelMargin/PanelColumn/Screen var gap = _screen.get_pulse_gap()
var gap = screen.get_pulse_gap()
get_tree().create_timer(gap).timeout.connect( get_tree().create_timer(gap).timeout.connect(
func(): func():
if not doors_closing_flag: if not doors_closing_flag:
screen.launch_pulse(), _screen.launch_pulse(),
CONNECT_ONE_SHOT CONNECT_ONE_SHOT
) )
@ -139,10 +137,8 @@ func _on_doors_closing(fast: bool = false):
doors_closing_flag = true doors_closing_flag = true
EventBus.doors_closed.emit(fast) EventBus.doors_closed.emit(fast)
var screen = $PanelMargin/PanelColumn/Screen
if people_in_elevator < threshold: if people_in_elevator < threshold:
screen.show_loss("TOO FEW") _screen.show_loss("TOO FEW")
EventBus.game_lost.emit("TOO FEW") EventBus.game_lost.emit("TOO FEW")
return return
@ -157,14 +153,14 @@ func _on_doors_closing(fast: bool = false):
current_floor -= 1 current_floor -= 1
if current_floor <= 1: if current_floor <= 1:
screen.show_win() _screen.show_win()
EventBus.floor_changed.emit(current_floor) EventBus.floor_changed.emit(current_floor)
EventBus.game_won.emit() EventBus.game_won.emit()
return return
$SfxClose.play() $SfxClose.play()
screen.show_countdown() _screen.show_countdown()
screen.shrink_block_zone() _screen.shrink_block_zone()
var tween = create_tween() var tween = create_tween()
tween.tween_interval(3.0) tween.tween_interval(3.0)

View file

@ -11,12 +11,15 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
[node name="ElevatorPanel" type="PanelContainer" unique_id=574176994] [node name="ElevatorPanel" type="PanelContainer" unique_id=574176994]
custom_minimum_size = Vector2(250, 0) anchors_preset = 6
anchors_preset = 11
anchor_left = 1.0 anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 0.5
offset_left = -8.0 offset_left = -200.0
offset_top = -140.0
offset_right = -10.0
offset_bottom = 140.0
grow_horizontal = 0 grow_horizontal = 0
grow_vertical = 2 grow_vertical = 2
script = ExtResource("1_1gr6t") script = ExtResource("1_1gr6t")
@ -32,7 +35,7 @@ theme_override_constants/margin_bottom = 15
layout_mode = 2 layout_mode = 2
[node name="Screen" type="Panel" parent="PanelMargin/PanelColumn" unique_id=1395085208] [node name="Screen" type="Panel" parent="PanelMargin/PanelColumn" unique_id=1395085208]
custom_minimum_size = Vector2(200, 200) custom_minimum_size = Vector2(160, 160)
layout_mode = 2 layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_n2snw") theme_override_styles/panel = SubResource("StyleBoxFlat_n2snw")
script = ExtResource("1_3gei6") script = ExtResource("1_3gei6")

View file

@ -23,14 +23,7 @@ func update_floor(floor_num: int):
_displayed_floor = floor_num _displayed_floor = floor_num
return return
_displayed_floor = floor_num _displayed_floor = floor_num
label.pivot_offset = Vector2(0, label.size.y) UIUtils.flip_label_text(label, new_text)
var tween = create_tween()
tween.tween_property(label, "scale:y", 0.0, 0.15).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN)
tween.tween_callback(func():
label.text = new_text
label.pivot_offset = Vector2.ZERO
)
tween.tween_property(label, "scale:y", 1.0, 0.15).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT)
func update_saved(count: int): func update_saved(count: int):
$StatsColumn/SavedLabel.text = "SAVED: " + str(count) $StatsColumn/SavedLabel.text = "SAVED: " + str(count)

View file

@ -4,10 +4,9 @@ var _enabled := false
func _ready(): func _ready():
visible = false visible = false
EventBus.game_started.connect(_on_game_started) EventBus.game_started.connect(func(): _enabled = true)
EventBus.game_won.connect(func(): _enabled = false)
func _on_game_started(): EventBus.game_lost.connect(func(_reason: String): _enabled = false)
_enabled = true
func _unhandled_input(event): func _unhandled_input(event):
if not _enabled: if not _enabled:

View file

@ -40,6 +40,7 @@ var _glow: ColorRect
var _perfect_zone: ColorRect var _perfect_zone: ColorRect
var _face_scale_tween: Tween var _face_scale_tween: Tween
var _face_shake_tween: Tween var _face_shake_tween: Tween
var _flash_tween: Tween
var _floor_label: Label var _floor_label: Label
signal pulse_started(duration: float) signal pulse_started(duration: float)
@ -99,10 +100,10 @@ func _ready():
add_child(_floor_label) add_child(_floor_label)
EventBus.floor_changed.connect(_update_floor_label) EventBus.floor_changed.connect(_update_floor_label)
func start(floor_num: int = 10): func start(floor_num: int = EventBus.STARTING_FLOOR):
active = true active = true
pulses_blocked = 0 pulses_blocked = 0
var floors_descended = 10 - floor_num var floors_descended = EventBus.STARTING_FLOOR - floor_num
pulse_speed = pulse_speed_initial + floors_descended * pulse_speed_per_floor pulse_speed = pulse_speed_initial + floors_descended * pulse_speed_per_floor
pulse_gap = 1.0 pulse_gap = 1.0
$AIFace.text = ">:)" $AIFace.text = ">:)"
@ -148,14 +149,7 @@ func _update_floor_label(floor_num: int):
_displayed_floor = floor_num _displayed_floor = floor_num
return return
_displayed_floor = floor_num _displayed_floor = floor_num
_floor_label.pivot_offset = Vector2(0, _floor_label.size.y) UIUtils.flip_label_text(_floor_label, new_text)
var tween = create_tween()
tween.tween_property(_floor_label, "scale:y", 0.0, 0.15).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN)
tween.tween_callback(func():
_floor_label.text = new_text
_floor_label.pivot_offset = Vector2.ZERO
)
tween.tween_property(_floor_label, "scale:y", 1.0, 0.15).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT)
func _update_perfect_zone(): func _update_perfect_zone():
var bz = $TargetZone var bz = $TargetZone
@ -252,9 +246,11 @@ func flash(color: Color):
var style = get_theme_stylebox("panel") as StyleBoxFlat var style = get_theme_stylebox("panel") as StyleBoxFlat
if not style: if not style:
return return
if _flash_tween:
_flash_tween.kill()
style.bg_color = color style.bg_color = color
var tween = create_tween() _flash_tween = create_tween()
tween.tween_property(style, "bg_color", base_color, 0.3) _flash_tween.tween_property(style, "bg_color", base_color, 0.3)
func show_countdown(): func show_countdown():
stop() stop()

View file

@ -9,6 +9,7 @@ static var _last_chase: AudioStream = null
var speed: int = 3 var speed: int = 3
var clumsiness: int = 0 var clumsiness: int = 0
var _saved: bool = false
@onready var safety_zone = get_node("/root/Game/World/ElevatorSafeZone") @onready var safety_zone = get_node("/root/Game/World/ElevatorSafeZone")
@ -28,12 +29,14 @@ func _ready():
CONNECT_ONE_SHOT CONNECT_ONE_SHOT
) )
func _physics_process(delta): func _physics_process(_delta):
velocity.z -= speed * delta velocity.z = -speed
move_and_slide() move_and_slide()
func _on_area_3d_area_entered(area: Area3D) -> void: func _on_area_3d_area_entered(area: Area3D) -> void:
var safety = safety_zone if area == safety_zone and not _saved:
if area == safety: _saved = true
print("Safe!") get_tree().create_timer(0.5).timeout.connect(
queue_free() func(): queue_free(),
CONNECT_ONE_SHOT
)

View file

@ -43,7 +43,7 @@ transform = Transform3D(4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 3, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.8164063, -0.30373383) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.8164063, -0.30373383)
shape = SubResource("BoxShape3D_k0juu") shape = SubResource("BoxShape3D_k0juu")
[node name="SuvivorSpawn" type="Marker3D" parent="." unique_id=1095768768] [node name="SurvivorSpawn" type="Marker3D" parent="." unique_id=1095768768]
unique_name_in_owner = true unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.9181392, 13.711893) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.9181392, 13.711893)
gizmo_extents = 1.46 gizmo_extents = 1.46

View file

@ -1,5 +1,7 @@
extends Node extends Node
const STARTING_FLOOR := 10
@warning_ignore_start("unused_signal") @warning_ignore_start("unused_signal")
signal floor_changed(floor_num: int) signal floor_changed(floor_num: int)

11
scripts/ui_utils.gd Normal file
View file

@ -0,0 +1,11 @@
class_name UIUtils
static func flip_label_text(label: Label, new_text: String, duration: float = 0.15) -> void:
label.pivot_offset = Vector2(0, label.size.y)
var tween = label.create_tween()
tween.tween_property(label, "scale:y", 0.0, duration).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN)
tween.tween_callback(func():
label.text = new_text
label.pivot_offset = Vector2.ZERO
)
tween.tween_property(label, "scale:y", 1.0, duration).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT)

1
scripts/ui_utils.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bp4uktnrbpag8