Poprawiony efekt eksplozji
This commit is contained in:
parent
bcde93eca9
commit
6f9bd71298
@ -31,7 +31,8 @@ func configure(sprite: Sprite2D, drift: Vector2, camera: Camera2D) -> void:
|
|||||||
global_position = sprite.global_position
|
global_position = sprite.global_position
|
||||||
global_rotation = sprite.global_rotation
|
global_rotation = sprite.global_rotation
|
||||||
_ship_scale = sprite.global_scale
|
_ship_scale = sprite.global_scale
|
||||||
_drift = drift.rotated(-global_rotation) * 0.12
|
# The whole effect inherits world velocity; fragment velocities are relative.
|
||||||
|
_drift = drift
|
||||||
_camera = camera
|
_camera = camera
|
||||||
if is_instance_valid(_camera):
|
if is_instance_valid(_camera):
|
||||||
_camera_offset = _camera.offset
|
_camera_offset = _camera.offset
|
||||||
@ -39,6 +40,9 @@ func configure(sprite: Sprite2D, drift: Vector2, camera: Camera2D) -> void:
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
z_index = 45
|
z_index = 45
|
||||||
light_mask = 4
|
light_mask = 4
|
||||||
|
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||||
|
# Animation advances in render frames, so don't interpolate its transform again.
|
||||||
|
physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_OFF
|
||||||
_rng.randomize()
|
_rng.randomize()
|
||||||
_build_fragments()
|
_build_fragments()
|
||||||
_prepare_smoke_texture()
|
_prepare_smoke_texture()
|
||||||
@ -81,14 +85,15 @@ func _build_fragments() -> void:
|
|||||||
uv.append(vertex / dimensions)
|
uv.append(vertex / dimensions)
|
||||||
var wreck := origin.length() < 12.0
|
var wreck := origin.length() < 12.0
|
||||||
var radial := origin.normalized() if origin.length_squared() > 0.1 else Vector2.RIGHT.rotated(_rng.randf_range(0, TAU))
|
var radial := origin.normalized() if origin.length_squared() > 0.1 else Vector2.RIGHT.rotated(_rng.randf_range(0, TAU))
|
||||||
_fragments.append({"points": points, "uv": uv, "position": origin, "velocity": radial.rotated(_rng.randf_range(-0.45, 0.45)) * _rng.randf_range(65, 155) + _drift if not wreck else radial * 5.0, "angle": 0.0, "spin": _rng.randf_range(-5, 5) if not wreck else _rng.randf_range(-0.3, 0.3), "wreck": wreck})
|
_fragments.append({"points": points, "uv": uv, "position": origin, "velocity": radial.rotated(_rng.randf_range(-0.45, 0.45)) * _rng.randf_range(65, 155) if not wreck else radial * 5.0, "angle": 0.0, "spin": _rng.randf_range(-5, 5) if not wreck else _rng.randf_range(-0.3, 0.3), "wreck": wreck})
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
|
global_position += _drift * delta
|
||||||
if _done and _elapsed >= DURATION + 1.8:
|
if _done and _elapsed >= DURATION + 1.8:
|
||||||
_smoke.clear()
|
if not _smoke.is_empty() or not _sparks.is_empty():
|
||||||
_sparks.clear()
|
_smoke.clear()
|
||||||
set_process(false)
|
_sparks.clear()
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
return
|
return
|
||||||
_elapsed += delta
|
_elapsed += delta
|
||||||
if not _detonated and _elapsed < CHARGE_TIME:
|
if not _detonated and _elapsed < CHARGE_TIME:
|
||||||
@ -191,13 +196,14 @@ func _emit_smoke() -> void:
|
|||||||
position = _burns[_rng.randi_range(0, _burns.size() - 1)]["position"] if not _burns.is_empty() else _hull_burn_position()
|
position = _burns[_rng.randi_range(0, _burns.size() - 1)]["position"] if not _burns.is_empty() else _hull_burn_position()
|
||||||
elif not _fragments.is_empty() and _rng.randf() < 0.7:
|
elif not _fragments.is_empty() and _rng.randf() < 0.7:
|
||||||
position = _fragments[_rng.randi_range(0, _fragments.size() - 1)]["position"]
|
position = _fragments[_rng.randi_range(0, _fragments.size() - 1)]["position"]
|
||||||
_smoke.append({"position": position, "velocity": Vector2(_rng.randf_range(-12, 12), _rng.randf_range(-22, 8)), "age": 0.0, "life": _rng.randf_range(0.9, 1.7), "radius": _rng.randf_range(5, 12)})
|
_smoke.append({"position": position, "velocity": Vector2(_rng.randf_range(-12, 12), _rng.randf_range(-22, 8)) - _drift.rotated(-global_rotation) * 0.25, "age": 0.0, "life": _rng.randf_range(0.9, 1.7), "radius": _rng.randf_range(5, 12)})
|
||||||
|
|
||||||
func _update_camera() -> void:
|
func _update_camera() -> void:
|
||||||
if not is_instance_valid(_camera):
|
if not is_instance_valid(_camera):
|
||||||
return
|
return
|
||||||
var time := _elapsed - CHARGE_TIME
|
var time := _elapsed - CHARGE_TIME
|
||||||
var strength := 0.8 if time < 0.0 else 7.0 * exp(-5.0 * time)
|
var strength := 0.8 if time < 0.0 else 7.0 * exp(-5.0 * time)
|
||||||
|
_camera.global_position = global_position
|
||||||
_camera.offset = _camera_offset + Vector2(sin(_elapsed * 83), cos(_elapsed * 67)) * strength
|
_camera.offset = _camera_offset + Vector2(sin(_elapsed * 83), cos(_elapsed * 67)) * strength
|
||||||
|
|
||||||
func _restore_camera() -> void:
|
func _restore_camera() -> void:
|
||||||
@ -238,10 +244,6 @@ func _draw() -> void:
|
|||||||
for layer in 3:
|
for layer in 3:
|
||||||
draw_arc(Vector2.ZERO, 18 + time * 230 + layer * 2, 0, TAU, 96, Color(0.85, 0.75, 0.6, fade * 0.08), 2, true)
|
draw_arc(Vector2.ZERO, 18 + time * 230 + layer * 2, 0, TAU, 96, Color(0.85, 0.75, 0.6, fade * 0.08), 2, true)
|
||||||
_draw_sparks()
|
_draw_sparks()
|
||||||
if time > 0.8:
|
|
||||||
for index in 4:
|
|
||||||
var flicker := maxf(0, sin(_elapsed * 17 + index * 8)) * clampf((3.3 - time) / 2, 0, 1)
|
|
||||||
draw_circle(Vector2.RIGHT.rotated(index * 2.3) * (4 + index * 2), 2 + flicker * 2, Color(1, 0.28, 0.04, flicker * 0.75))
|
|
||||||
|
|
||||||
func _draw_sparks() -> void:
|
func _draw_sparks() -> void:
|
||||||
for spark in _sparks:
|
for spark in _sparks:
|
||||||
|
|||||||
@ -22,8 +22,11 @@ func _ready() -> void:
|
|||||||
assert(effect.get("_fragments").size() >= 4)
|
assert(effect.get("_fragments").size() >= 4)
|
||||||
assert(not game.has_node("DefeatOverlay"))
|
assert(not game.has_node("DefeatOverlay"))
|
||||||
assert(not effect.has_node("ExplosionAudio"))
|
assert(not effect.has_node("ExplosionAudio"))
|
||||||
|
var start_position: Vector2 = effect.global_position
|
||||||
|
assert(effect.get("_drift") == Vector2(100, -40))
|
||||||
effect.finished.connect(func() -> void: _finished_count += 1)
|
effect.finished.connect(func() -> void: _finished_count += 1)
|
||||||
effect._process(0.2)
|
effect._process(0.2)
|
||||||
|
assert(effect.global_position.is_equal_approx(start_position + Vector2(20, -8)))
|
||||||
assert(not effect.get("_detonated") and camera.offset != Vector2(3, 5))
|
assert(not effect.get("_detonated") and camera.offset != Vector2(3, 5))
|
||||||
for step in 18:
|
for step in 18:
|
||||||
effect._process(0.1)
|
effect._process(0.1)
|
||||||
@ -39,6 +42,7 @@ func _ready() -> void:
|
|||||||
effect._process(0.3)
|
effect._process(0.3)
|
||||||
assert(game.has_node("DefeatOverlay") and _finished_count == 1)
|
assert(game.has_node("DefeatOverlay") and _finished_count == 1)
|
||||||
assert(camera.offset == Vector2(3, 5))
|
assert(camera.offset == Vector2(3, 5))
|
||||||
|
assert(effect.global_position.is_equal_approx(start_position + Vector2(100, -40) * 5.35))
|
||||||
effect._process(0.1)
|
effect._process(0.1)
|
||||||
ship.call("_destroy_ship")
|
ship.call("_destroy_ship")
|
||||||
assert(_finished_count == 1)
|
assert(_finished_count == 1)
|
||||||
@ -47,6 +51,11 @@ func _ready() -> void:
|
|||||||
if child.name == "PlayerDestructionEffect":
|
if child.name == "PlayerDestructionEffect":
|
||||||
deaths += 1
|
deaths += 1
|
||||||
assert(deaths == 1)
|
assert(deaths == 1)
|
||||||
|
# A drifting wreck must retain its velocity even after the visual cleanup.
|
||||||
|
effect._process(2.0)
|
||||||
|
var coasting_position: Vector2 = effect.global_position
|
||||||
|
effect._process(0.5)
|
||||||
|
assert(effect.global_position.is_equal_approx(coasting_position + Vector2(50, -20)))
|
||||||
for chassis in preload("res://scripts/game/ship_catalog.gd").SHIPS:
|
for chassis in preload("res://scripts/game/ship_catalog.gd").SHIPS:
|
||||||
var source := Sprite2D.new()
|
var source := Sprite2D.new()
|
||||||
source.texture = load(preload("res://scripts/game/ship_catalog.gd").texture_path(chassis))
|
source.texture = load(preload("res://scripts/game/ship_catalog.gd").texture_path(chassis))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user