Polish dialog and intro transitions
This commit is contained in:
parent
3975959017
commit
d413d1da9f
7 changed files with 228 additions and 4 deletions
87
tests/test_dialog_releases_joysticks.gd
Normal file
87
tests/test_dialog_releases_joysticks.gd
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
# Forgejo #182: opening a dialog releases both touch joysticks before the
|
||||||
|
# world is paused. A finger-up event during the pause cannot reach their
|
||||||
|
# ordinary input path, so waiting for it would resume stale movement/fire.
|
||||||
|
|
||||||
|
var state: Node
|
||||||
|
var main: Node
|
||||||
|
var fleet: Node
|
||||||
|
var narration: Control
|
||||||
|
var movement: Control
|
||||||
|
var firing: Control
|
||||||
|
var stage: int = 0
|
||||||
|
var elapsed: float = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
state = root.get_node("GameState")
|
||||||
|
state.reset_new_game()
|
||||||
|
state.intro_active = false
|
||||||
|
state.reset_quests()
|
||||||
|
main = load("res://world/Main.tscn").instantiate()
|
||||||
|
root.add_child(main)
|
||||||
|
current_scene = main
|
||||||
|
fleet = main.get_node("Fleet")
|
||||||
|
narration = main.get_node("UI/NarrationBanner")
|
||||||
|
movement = main.get_node("UI/Joystick")
|
||||||
|
firing = main.get_node("UI/FireStick")
|
||||||
|
|
||||||
|
|
||||||
|
func _hold(stick: Control, index: int, direction: Vector2) -> void:
|
||||||
|
var centre: Vector2 = stick.global_position + stick.size * 0.5
|
||||||
|
var press := InputEventScreenTouch.new()
|
||||||
|
press.index = index
|
||||||
|
press.pressed = true
|
||||||
|
press.position = centre
|
||||||
|
stick.handle_touch(press)
|
||||||
|
var drag := InputEventScreenDrag.new()
|
||||||
|
drag.index = index
|
||||||
|
drag.position = centre + direction.normalized() * stick.max_radius
|
||||||
|
stick.handle_drag(drag)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> bool:
|
||||||
|
elapsed += delta
|
||||||
|
if stage != 0 or elapsed < 0.3:
|
||||||
|
return false
|
||||||
|
stage = 1
|
||||||
|
main.get_node("EnemySpawner").set_process(false)
|
||||||
|
main.get_node("AsteroidField").set_process(false)
|
||||||
|
_hold(movement, 21, Vector2.RIGHT)
|
||||||
|
_hold(firing, 22, Vector2.UP)
|
||||||
|
main._process(0.0)
|
||||||
|
main.get_node("FireStickController")._process(0.0)
|
||||||
|
if not movement.is_active() or not firing.is_active():
|
||||||
|
return _fail("the test could not hold both joysticks")
|
||||||
|
if movement.direction == Vector2.ZERO or firing.direction == Vector2.ZERO:
|
||||||
|
return _fail("a held joystick reported no direction")
|
||||||
|
if fleet.steer_direction == Vector2.ZERO:
|
||||||
|
return _fail("the movement joystick had not begun steering")
|
||||||
|
|
||||||
|
narration.say("Hands clear.", "TEST")
|
||||||
|
if not paused:
|
||||||
|
return _fail("the dialog did not pause the game")
|
||||||
|
for stick in [movement, firing]:
|
||||||
|
if stick.is_active() or stick.direction != Vector2.ZERO:
|
||||||
|
return _fail("%s remained held behind the dialog" % stick.name)
|
||||||
|
if stick.base_pos.distance_to(stick.home_pos()) > 0.01 \
|
||||||
|
or stick.knob_pos.distance_to(stick.home_pos()) > 0.01:
|
||||||
|
return _fail("%s did not visually recenter" % stick.name)
|
||||||
|
if fleet.steer_direction != Vector2.ZERO:
|
||||||
|
return _fail("releasing the movement joystick did not stop the fleet")
|
||||||
|
|
||||||
|
narration.clear()
|
||||||
|
main.get_node("FireStickController")._process(0.0)
|
||||||
|
if main.get_node("FireStickController").is_firing():
|
||||||
|
return _fail("fire resumed from stale joystick input after the dialog")
|
||||||
|
print("dialog released and recentered movement and fire joysticks before pausing")
|
||||||
|
print("TEST_DIALOG_RELEASES_JOYSTICKS: PASS")
|
||||||
|
quit(0)
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func _fail(message: String) -> bool:
|
||||||
|
print("TEST_DIALOG_RELEASES_JOYSTICKS: FAIL (%s)" % message)
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
1
tests/test_energy_propulser_dash.gd.uid
Normal file
1
tests/test_energy_propulser_dash.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bxn8xvfo3v7v0
|
||||||
|
|
@ -35,6 +35,8 @@ extends SceneTree
|
||||||
# R. #139 - no belt rock is laid down inside the visible screen
|
# R. #139 - no belt rock is laid down inside the visible screen
|
||||||
# S. #170 - the prologue opens on the PICTURE: the convoy is flying and the
|
# S. #170 - the prologue opens on the PICTURE: the convoy is flying and the
|
||||||
# game is running for a few seconds before the guide says anything
|
# game is running for a few seconds before the guide says anything
|
||||||
|
# T. #183 - absorption whites out the full screen, teleports only once the
|
||||||
|
# cover is opaque, then reveals the fleet at the normal spawn
|
||||||
|
|
||||||
var game_state: Node
|
var game_state: Node
|
||||||
var scene: Node
|
var scene: Node
|
||||||
|
|
@ -45,6 +47,7 @@ var stage: int = 0
|
||||||
var elapsed: float = 0.0
|
var elapsed: float = 0.0
|
||||||
var convoy_size: int = 0
|
var convoy_size: int = 0
|
||||||
var skipped_props: Array = []
|
var skipped_props: Array = []
|
||||||
|
var whiteout_mid_checked: bool = false
|
||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
|
|
@ -367,6 +370,14 @@ func _process(delta: float) -> bool:
|
||||||
|
|
||||||
# --- H. the vortex --------------------------------------
|
# --- H. the vortex --------------------------------------
|
||||||
director._begin(director.Beat.VORTEX)
|
director._begin(director.Beat.VORTEX)
|
||||||
|
var fade: ColorRect = scene.get_node("FadeOverlay/FadeRect")
|
||||||
|
var viewport_size: Vector2 = scene.get_viewport().get_visible_rect().size
|
||||||
|
if fade.size.distance_to(viewport_size) > 1.0:
|
||||||
|
return _fail("whiteout is %s, viewport is %s" % [fade.size, viewport_size])
|
||||||
|
if fade.color.r < 0.99 or fade.color.g < 0.99 or fade.color.b < 0.99:
|
||||||
|
return _fail("the vortex transition is not white")
|
||||||
|
if fade.color.a > 0.01:
|
||||||
|
return _fail("the whiteout began fully opaque instead of fading in")
|
||||||
elapsed = 0.0
|
elapsed = 0.0
|
||||||
stage = 3
|
stage = 3
|
||||||
return false
|
return false
|
||||||
|
|
@ -374,6 +385,15 @@ func _process(delta: float) -> bool:
|
||||||
# Left to the director's own clock rather than ticked by hand:
|
# Left to the director's own clock rather than ticked by hand:
|
||||||
# the vortex is a timed animation and driving it twice would not
|
# the vortex is a timed animation and driving it twice would not
|
||||||
# be the thing that ships.
|
# be the thing that ships.
|
||||||
|
if not whiteout_mid_checked and elapsed >= director.WHITEOUT_IN_SECONDS * 0.5:
|
||||||
|
whiteout_mid_checked = true
|
||||||
|
var mid_fade: ColorRect = scene.get_node("FadeOverlay/FadeRect")
|
||||||
|
if mid_fade.color.a <= 0.05 or mid_fade.color.a >= 0.95:
|
||||||
|
return _fail("whiteout did not gradually fade in (alpha %.2f)" % mid_fade.color.a)
|
||||||
|
if director.whiteout_teleported:
|
||||||
|
return _fail("fleet teleported before the screen was fully white")
|
||||||
|
if fleet.get_formation_origin().distance_to(director.DEFAULT_SPAWN) <= 1.0:
|
||||||
|
return _fail("fleet reached default spawn before full white")
|
||||||
if elapsed < 4.2:
|
if elapsed < 4.2:
|
||||||
return false
|
return false
|
||||||
var alive: int = 0
|
var alive: int = 0
|
||||||
|
|
@ -386,6 +406,15 @@ func _process(delta: float) -> bool:
|
||||||
return _fail("the survivor is a %s, not the default interceptor" \
|
return _fail("the survivor is a %s, not the default interceptor" \
|
||||||
% fleet.ships[0].vessel_type)
|
% fleet.ships[0].vessel_type)
|
||||||
print("the vortex took %d vessels and left one interceptor" % (convoy_size - 1))
|
print("the vortex took %d vessels and left one interceptor" % (convoy_size - 1))
|
||||||
|
if not director.whiteout_teleported:
|
||||||
|
return _fail("the screen reached white without teleporting the fleet")
|
||||||
|
if fleet.get_formation_origin().distance_to(director.DEFAULT_SPAWN) > 1.0:
|
||||||
|
return _fail("whiteout revealed the fleet at %s instead of default spawn %s" \
|
||||||
|
% [fleet.get_formation_origin(), director.DEFAULT_SPAWN])
|
||||||
|
var revealing: ColorRect = scene.get_node("FadeOverlay/FadeRect")
|
||||||
|
if revealing.color.a >= 0.99:
|
||||||
|
return _fail("screen stayed fully white after teleport")
|
||||||
|
print("whiteout hid the teleport to default spawn, then began revealing it")
|
||||||
|
|
||||||
# --- I. the handover ------------------------------------
|
# --- I. the handover ------------------------------------
|
||||||
director.finish()
|
director.finish()
|
||||||
|
|
@ -426,6 +455,9 @@ func _process(delta: float) -> bool:
|
||||||
return _fail("the breach lens is still over the screen after the handover")
|
return _fail("the breach lens is still over the screen after the handover")
|
||||||
if is_instance_valid(director) and director.breach != null:
|
if is_instance_valid(director) and director.breach != null:
|
||||||
return _fail("the black hole outlived the prologue")
|
return _fail("the black hole outlived the prologue")
|
||||||
|
var finished_fade: ColorRect = scene.get_node("FadeOverlay/FadeRect")
|
||||||
|
if finished_fade.color.a > 0.001 or finished_fade.color.r > 0.001:
|
||||||
|
return _fail("intro left the shared fade overlay tinted white")
|
||||||
print("handover: flags clear, 1 interceptor, waves and rocks running, buttons back")
|
print("handover: flags clear, 1 interceptor, waves and rocks running, buttons back")
|
||||||
_drop_scene()
|
_drop_scene()
|
||||||
elapsed = 0.0
|
elapsed = 0.0
|
||||||
|
|
|
||||||
|
|
@ -240,12 +240,26 @@ func _advance() -> void:
|
||||||
label.visible_characters = 0
|
label.visible_characters = 0
|
||||||
speaker_label.text = speaker
|
speaker_label.text = speaker
|
||||||
visible = true
|
visible = true
|
||||||
|
_release_touch_joysticks()
|
||||||
Sfx.play(get_tree(), Sfx.DIALOG)
|
Sfx.play(get_tree(), Sfx.DIALOG)
|
||||||
_layout()
|
_layout()
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
_sync_pause()
|
_sync_pause()
|
||||||
|
|
||||||
|
|
||||||
|
# A touch release delivered while the tree is paused never reaches an
|
||||||
|
# ordinary joystick. Neutralise every spring-loaded stick immediately before
|
||||||
|
# applying the pause, so neither movement nor firing resumes from stale input
|
||||||
|
# when the dialog closes (#182).
|
||||||
|
func _release_touch_joysticks() -> void:
|
||||||
|
var tree: SceneTree = get_tree()
|
||||||
|
if tree == null:
|
||||||
|
return
|
||||||
|
for joystick in tree.get_nodes_in_group("touch_joysticks"):
|
||||||
|
if is_instance_valid(joystick) and joystick.has_method("release_input"):
|
||||||
|
joystick.release_input()
|
||||||
|
|
||||||
|
|
||||||
func is_typing() -> bool:
|
func is_typing() -> bool:
|
||||||
return current != "" and revealed < float(current.length())
|
return current != "" and revealed < float(current.length())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ var knob_pos: Vector2 = Vector2.ZERO
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
# Dialogs release every spring-loaded stick through one compositional
|
||||||
|
# contract, without NarrationBanner knowing scene paths or joystick roles.
|
||||||
|
add_to_group("touch_joysticks")
|
||||||
resized.connect(_relayout)
|
resized.connect(_relayout)
|
||||||
_relayout()
|
_relayout()
|
||||||
|
|
||||||
|
|
@ -79,6 +82,15 @@ func handle_touch(event: InputEventScreenTouch) -> bool:
|
||||||
|
|
||||||
if event.index != active_touch_index:
|
if event.index != active_touch_index:
|
||||||
return false
|
return false
|
||||||
|
release_input()
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
# Returns this spring-loaded control to its neutral state. Public and
|
||||||
|
# idempotent so a dialog can safely release movement and fire sticks before
|
||||||
|
# pausing their controllers (#182), even when only one is currently held.
|
||||||
|
func release_input() -> void:
|
||||||
|
var was_active: bool = is_active() or direction != Vector2.ZERO
|
||||||
active_touch_index = -1
|
active_touch_index = -1
|
||||||
# Back to the middle of the rect, BASE included. This used to reset the
|
# Back to the middle of the rect, BASE included. This used to reset the
|
||||||
# knob onto base_pos and leave the base wherever the finger had landed, so
|
# knob onto base_pos and leave the base wherever the finger had landed, so
|
||||||
|
|
@ -88,9 +100,9 @@ func handle_touch(event: InputEventScreenTouch) -> bool:
|
||||||
knob_pos = base_pos
|
knob_pos = base_pos
|
||||||
direction = Vector2.ZERO
|
direction = Vector2.ZERO
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
direction_changed.emit(direction)
|
if was_active:
|
||||||
released.emit()
|
direction_changed.emit(direction)
|
||||||
return true
|
released.emit()
|
||||||
|
|
||||||
|
|
||||||
func handle_drag(event: InputEventScreenDrag) -> bool:
|
func handle_drag(event: InputEventScreenDrag) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,26 @@ func move_to(world_pos: Vector2) -> void:
|
||||||
_assign_slot_targets()
|
_assign_slot_targets()
|
||||||
|
|
||||||
|
|
||||||
|
# Moves the complete formation immediately while preserving every authored
|
||||||
|
# slot. Unlike move_to(), this is a scene transition hidden behind a full
|
||||||
|
# screen cover, not a travel order ships should visibly fly toward (#183).
|
||||||
|
func teleport_to(world_pos: Vector2) -> void:
|
||||||
|
var displacement: Vector2 = world_pos - get_formation_origin()
|
||||||
|
for ship in ships:
|
||||||
|
if not is_instance_valid(ship):
|
||||||
|
continue
|
||||||
|
ship.position += displacement
|
||||||
|
ship.move_target += displacement
|
||||||
|
ship.velocity = Vector2.ZERO
|
||||||
|
ship.fleet_velocity = Vector2.ZERO
|
||||||
|
steer_direction = Vector2.ZERO
|
||||||
|
dash_remaining = 0.0
|
||||||
|
dash_direction = Vector2.ZERO
|
||||||
|
fleet_target = world_pos
|
||||||
|
anchor = world_pos
|
||||||
|
GameState.fleet_position = get_centroid()
|
||||||
|
|
||||||
|
|
||||||
func move_in_direction(direction: Vector2) -> void:
|
func move_in_direction(direction: Vector2) -> void:
|
||||||
# Joystick steering. Sets the heading; _process advances the anchor.
|
# Joystick steering. Sets the heading; _process advances the anchor.
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,11 @@ const BELT_HALF_WIDTH: float = 2600.0
|
||||||
const BELT_DEPTH: float = 1400.0
|
const BELT_DEPTH: float = 1400.0
|
||||||
const BREACH_PULL: float = 620.0
|
const BREACH_PULL: float = 620.0
|
||||||
const SHAKE_MAX: float = 34.0
|
const SHAKE_MAX: float = 34.0
|
||||||
|
const DEFAULT_SPAWN: Vector2 = Vector2.ZERO
|
||||||
|
# The cover reaches white after the convoy has visibly collapsed to its
|
||||||
|
# survivor, then reveals the ordinary game location with time to breathe.
|
||||||
|
const WHITEOUT_IN_SECONDS: float = 3.2
|
||||||
|
const WHITEOUT_OUT_SECONDS: float = 2.0
|
||||||
# How far past the horizon the lens reaches. Generous: the bend is what
|
# How far past the horizon the lens reaches. Generous: the bend is what
|
||||||
# sells the hole, and it falls off to nothing on its own well before this.
|
# sells the hole, and it falls off to nothing on its own well before this.
|
||||||
const BREACH_LENS_SCALE: float = 7.0
|
const BREACH_LENS_SCALE: float = 7.0
|
||||||
|
|
@ -100,6 +105,7 @@ const VORTEX_COLORS: Array = [
|
||||||
@onready var narration: Control = get_node("../UI/NarrationBanner")
|
@onready var narration: Control = get_node("../UI/NarrationBanner")
|
||||||
@onready var asteroid_field: Node2D = get_node("../AsteroidField")
|
@onready var asteroid_field: Node2D = get_node("../AsteroidField")
|
||||||
@onready var enemy_spawner: Node2D = get_node("../EnemySpawner")
|
@onready var enemy_spawner: Node2D = get_node("../EnemySpawner")
|
||||||
|
@onready var fade_rect: ColorRect = get_node_or_null("../FadeOverlay/FadeRect")
|
||||||
|
|
||||||
var running: bool = false
|
var running: bool = false
|
||||||
var beat: int = Beat.BRIEF
|
var beat: int = Beat.BRIEF
|
||||||
|
|
@ -119,6 +125,8 @@ var _done: bool = false
|
||||||
# saying cannot surface in the middle of the next one.
|
# saying cannot surface in the middle of the next one.
|
||||||
var _pending_lines: Array = []
|
var _pending_lines: Array = []
|
||||||
var _pending_at: float = 0.0
|
var _pending_at: float = 0.0
|
||||||
|
var whiteout_teleported: bool = false
|
||||||
|
var _whiteout_tween: Tween = null
|
||||||
|
|
||||||
@onready var overlay: ColorRect = get_node_or_null("../UI/BreachOverlay")
|
@onready var overlay: ColorRect = get_node_or_null("../UI/BreachOverlay")
|
||||||
|
|
||||||
|
|
@ -209,6 +217,7 @@ func finish() -> void:
|
||||||
GameState.intro_locks_movement = false
|
GameState.intro_locks_movement = false
|
||||||
GameState.intro_fleet_size = 0
|
GameState.intro_fleet_size = 0
|
||||||
narration.clear()
|
narration.clear()
|
||||||
|
_reset_whiteout()
|
||||||
camera.offset = Vector2.ZERO
|
camera.offset = Vector2.ZERO
|
||||||
enemy_spawner.set_process(true)
|
enemy_spawner.set_process(true)
|
||||||
asteroid_field.set_process(true)
|
asteroid_field.set_process(true)
|
||||||
|
|
@ -354,6 +363,7 @@ func _begin(next: int) -> void:
|
||||||
vortex_time = 0.0
|
vortex_time = 0.0
|
||||||
_ensure_survivor_hull()
|
_ensure_survivor_hull()
|
||||||
narration.clear()
|
narration.clear()
|
||||||
|
_start_whiteout()
|
||||||
Beat.AFTERMATH:
|
Beat.AFTERMATH:
|
||||||
GameState.intro_locks_movement = false
|
GameState.intro_locks_movement = false
|
||||||
shake = 0.0
|
shake = 0.0
|
||||||
|
|
@ -434,7 +444,11 @@ func _tick(delta: float) -> void:
|
||||||
vortex_time += delta
|
vortex_time += delta
|
||||||
shake = maxf(shake - delta * SHAKE_MAX * 0.5, SHAKE_MAX * 0.35)
|
shake = maxf(shake - delta * SHAKE_MAX * 0.5, SHAKE_MAX * 0.35)
|
||||||
_drive_breach(1.0)
|
_drive_breach(1.0)
|
||||||
_whirl(delta)
|
# Once the opaque frame has moved the survivor to the real spawn,
|
||||||
|
# nothing from the old side may pull it back into the breach while the
|
||||||
|
# white cover clears.
|
||||||
|
if not whiteout_teleported:
|
||||||
|
_whirl(delta)
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
Beat.AFTERMATH:
|
Beat.AFTERMATH:
|
||||||
shake = maxf(shake - delta * SHAKE_MAX, 0.0)
|
shake = maxf(shake - delta * SHAKE_MAX, 0.0)
|
||||||
|
|
@ -445,6 +459,50 @@ func _tick(delta: float) -> void:
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
# The existing transition ColorRect already owns the topmost full-screen
|
||||||
|
# layer. Recolour it for this one transition, and sequence the teleport as a
|
||||||
|
# callback between fade-in and fade-out so no world-space jump can be seen.
|
||||||
|
func _start_whiteout() -> void:
|
||||||
|
whiteout_teleported = false
|
||||||
|
if fade_rect == null:
|
||||||
|
# Headless/minimal scenes may omit presentation, but the story still has
|
||||||
|
# to land at the same gameplay state.
|
||||||
|
_complete_whiteout()
|
||||||
|
return
|
||||||
|
if _whiteout_tween != null and _whiteout_tween.is_valid():
|
||||||
|
_whiteout_tween.kill()
|
||||||
|
fade_rect.color = Color(1.0, 1.0, 1.0, 0.0)
|
||||||
|
_whiteout_tween = create_tween()
|
||||||
|
_whiteout_tween.tween_property(fade_rect, "color:a", 1.0, WHITEOUT_IN_SECONDS)
|
||||||
|
_whiteout_tween.tween_callback(_complete_whiteout)
|
||||||
|
_whiteout_tween.tween_property(fade_rect, "color:a", 0.0, WHITEOUT_OUT_SECONDS)
|
||||||
|
_whiteout_tween.tween_callback(_finish_whiteout)
|
||||||
|
|
||||||
|
|
||||||
|
func _complete_whiteout() -> void:
|
||||||
|
if whiteout_teleported or not running:
|
||||||
|
return
|
||||||
|
whiteout_teleported = true
|
||||||
|
fleet.teleport_to(DEFAULT_SPAWN)
|
||||||
|
camera.global_position = fleet.get_centroid()
|
||||||
|
camera.offset = Vector2.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
func _finish_whiteout() -> void:
|
||||||
|
_whiteout_tween = null
|
||||||
|
if fade_rect != null:
|
||||||
|
# Restore the shared rect's normal transparent-black resting state so a
|
||||||
|
# later planet transition remains black rather than reusing intro white.
|
||||||
|
fade_rect.color = Color(0.0, 0.0, 0.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
func _reset_whiteout() -> void:
|
||||||
|
if _whiteout_tween != null and _whiteout_tween.is_valid():
|
||||||
|
_whiteout_tween.kill()
|
||||||
|
_whiteout_tween = null
|
||||||
|
_finish_whiteout()
|
||||||
|
|
||||||
|
|
||||||
func _apply_shake(delta: float) -> void:
|
func _apply_shake(delta: float) -> void:
|
||||||
if shake <= 0.01:
|
if shake <= 0.01:
|
||||||
if camera.offset != Vector2.ZERO:
|
if camera.offset != Vector2.ZERO:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue