Explosion burst
A one_shot spark layer over a one_shot smoke layer, restarted together. Click to move the blast, or wait for the timer to fire it again.
The editor above is running this project. Change a line and it reloads.
Godot classes used
CPUParticles2DCanvasItemMaterialTimer
The code
scripts/main.gd
extends Node
const BURST_INTERVAL: float = 1.2
const SPARK_LIFETIME: float = 1.4
var spark: CPUParticles2D
var smoke: CPUParticles2D
func _ready() -> void:
_add_background()
var dot: GradientTexture2D = _make_dot()
smoke = CPUParticles2D.new()
smoke.texture = dot
smoke.local_coords = false
smoke.one_shot = true
smoke.explosiveness = 1.0
smoke.amount = 60
smoke.lifetime = 1.7
smoke.spread = 180.0
smoke.initial_velocity_min = 90.0
smoke.initial_velocity_max = 340.0
smoke.gravity = Vector2(0, -70)
smoke.damping_min = 90.0
smoke.damping_max = 190.0
smoke.scale_amount_min = 2.0
smoke.scale_amount_max = 4.2
smoke.color_ramp = _make_ramp(
PackedFloat32Array([0.0, 0.25, 1.0]),
PackedColorArray([Color(0.36, 0.38, 0.46, 0.0), Color(0.36, 0.38, 0.46, 0.22), Color(0.2, 0.21, 0.26, 0.0)])
)
add_child(smoke)
spark = CPUParticles2D.new()
spark.texture = dot
spark.local_coords = false
spark.one_shot = true
spark.explosiveness = 1.0
spark.amount = 280
spark.lifetime = SPARK_LIFETIME
spark.spread = 180.0
spark.initial_velocity_min = 260.0
spark.initial_velocity_max = 820.0
spark.gravity = Vector2(0, 620)
spark.damping_min = 90.0
spark.damping_max = 260.0
spark.scale_amount_min = 0.4
spark.scale_amount_max = 1.4
spark.color_ramp = _make_ramp(
PackedFloat32Array([0.0, 0.2, 0.6, 1.0]),
PackedColorArray([Color('#fff6d8'), Color('#f3d48d'), Color('#fc7f7f'), Color(0.7, 0.25, 0.25, 0.0)])
)
spark.material = _make_additive()
add_child(spark)
var timer: Timer = Timer.new()
timer.wait_time = BURST_INTERVAL
timer.timeout.connect(_blast_at_center)
add_child(timer)
timer.start()
_blast_at_center()
print('click anywhere to blow it up there, one goes off on its own every %.1f s' % BURST_INTERVAL)
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
_blast((event as InputEventMouseButton).position)
func _blast_at_center() -> void:
_blast(get_viewport().get_visible_rect().size * 0.5)
func _blast(at: Vector2) -> void:
spark.position = at
smoke.position = at
spark.restart()
smoke.restart()
func _make_additive() -> CanvasItemMaterial:
var material: CanvasItemMaterial = CanvasItemMaterial.new()
material.blend_mode = CanvasItemMaterial.BLEND_MODE_ADD
return material
func _make_ramp(offsets: PackedFloat32Array, colors: PackedColorArray) -> Gradient:
var ramp: Gradient = Gradient.new()
ramp.offsets = offsets
ramp.colors = colors
return ramp
func _make_dot() -> GradientTexture2D:
var gradient: Gradient = Gradient.new()
gradient.set_color(0, Color(1, 1, 1, 1))
gradient.set_color(1, Color(1, 1, 1, 0))
var dot: GradientTexture2D = GradientTexture2D.new()
dot.gradient = gradient
dot.fill = GradientTexture2D.FILL_RADIAL
dot.fill_from = Vector2(0.5, 0.5)
dot.fill_to = Vector2(1.0, 0.5)
dot.width = 32
dot.height = 32
return dot
func _add_background() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
# ColorRect defaults to MOUSE_FILTER_STOP and would eat the click before _unhandled_input
background.mouse_filter = Control.MOUSE_FILTER_IGNORE
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)