62 lines
2.1 KiB
GDScript
62 lines
2.1 KiB
GDScript
extends Node3D
|
|
## Original Half-Life fireball, 15 frames at 15 FPS, additive camera-facing quad.
|
|
## A PNG atlas avoids the native GoldSrc importer in Web exports.
|
|
const ATLAS = preload("res://assets/effects/explosion/zerogxplode_atlas.png")
|
|
const FRAME_COUNT := 15
|
|
const FPS := 15.0
|
|
const DURATION := FRAME_COUNT / FPS
|
|
const SIZE := 3.2
|
|
var elapsed := 0.0
|
|
var frame_index := 0
|
|
var fireball: MeshInstance3D
|
|
var material: StandardMaterial3D
|
|
|
|
func _ready() -> void:
|
|
name = "GrenadeExplosion"
|
|
material = StandardMaterial3D.new()
|
|
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
|
material.blend_mode = BaseMaterial3D.BLEND_MODE_ADD
|
|
material.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED
|
|
material.cull_mode = BaseMaterial3D.CULL_DISABLED
|
|
material.albedo_texture = ATLAS
|
|
material.texture_filter = BaseMaterial3D.TEXTURE_FILTER_LINEAR
|
|
material.texture_repeat = false
|
|
# Two-pixel black gutters prevent adjacent frames bleeding under filtering.
|
|
material.uv1_scale = Vector3(64.0 / 340.0, 64.0 / 204.0, 1)
|
|
fireball = MeshInstance3D.new()
|
|
fireball.name = "Fireball"
|
|
fireball.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
|
var quad := QuadMesh.new()
|
|
quad.size = Vector2(SIZE, SIZE)
|
|
quad.material = material
|
|
fireball.mesh = quad
|
|
# Raise the fireball, but leave the damage origin at the physical impact.
|
|
fireball.position.y = 0.8
|
|
add_child(fireball)
|
|
_set_frame(0)
|
|
var light := OmniLight3D.new()
|
|
light.name = "Flash"
|
|
light.light_color = Color(1, 0.45, 0.08)
|
|
light.light_energy = 8
|
|
light.omni_range = 10
|
|
light.shadow_enabled = false
|
|
add_child(light)
|
|
create_tween().tween_property(light, "light_energy", 0.0, 0.3)
|
|
# Keep the node alive for the original explosion sound to finish.
|
|
get_tree().create_timer(4).timeout.connect(queue_free)
|
|
|
|
func _process(delta: float) -> void:
|
|
elapsed += delta
|
|
if elapsed >= DURATION:
|
|
fireball.hide()
|
|
set_process(false)
|
|
return
|
|
_set_frame(mini(int(elapsed * FPS), FRAME_COUNT - 1))
|
|
|
|
func _set_frame(index: int) -> void:
|
|
frame_index = index
|
|
material.uv1_offset = Vector3(
|
|
(float(index % 5) * 68 + 2) / 340.0,
|
|
(float(index / 5) * 68 + 2) / 204.0, 0)
|