Feu et fumée

Deux émetteurs empilés avec des rampes de couleur différentes, une flamme additive et un panache de fumée au-dessus. Cliquez pour souffler une brise à travers les deux.

L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.

Classes Godot utilisées

CPUParticles2DGradientCanvasItemMaterial

Le code

scripts/main.gd
extends Node

const FIRE_RISE: float = -110.0
const SMOKE_RISE: float = -40.0
const BREEZE: float = 120.0

var fire: CPUParticles2D
var smoke: CPUParticles2D
var windy: bool = false


func _ready() -> void:
	_add_background()

	var view: Vector2 = get_viewport().get_visible_rect().size
	var base: Vector2 = Vector2(view.x * 0.5, view.y * 0.78)
	var dot: GradientTexture2D = _make_dot()

	_add_brazier(base)

	smoke = CPUParticles2D.new()
	smoke.position = base - Vector2(0, 150)
	smoke.texture = dot
	smoke.amount = 80
	smoke.lifetime = 2.8
	smoke.preprocess = 2.8
	smoke.emission_shape = CPUParticles2D.EMISSION_SHAPE_RECTANGLE
	smoke.emission_rect_extents = Vector2(24, 6)
	smoke.direction = Vector2(0, -1)
	smoke.spread = 14.0
	smoke.initial_velocity_min = 40.0
	smoke.initial_velocity_max = 95.0
	smoke.gravity = Vector2(0, SMOKE_RISE)
	smoke.angular_velocity_min = -35.0
	smoke.angular_velocity_max = 35.0
	smoke.scale_amount_min = 1.8
	smoke.scale_amount_max = 4.0
	smoke.scale_amount_curve = _make_growth_curve()
	smoke.color_ramp = _make_ramp(
		PackedFloat32Array([0.0, 0.3, 1.0]),
		PackedColorArray([Color(0.44, 0.46, 0.54, 0.0), Color(0.44, 0.46, 0.54, 0.45), Color(0.3, 0.31, 0.38, 0.0)])
	)
	add_child(smoke)

	fire = CPUParticles2D.new()
	fire.position = base
	fire.texture = dot
	fire.amount = 160
	fire.lifetime = 1.3
	fire.preprocess = 1.3
	fire.emission_shape = CPUParticles2D.EMISSION_SHAPE_RECTANGLE
	fire.emission_rect_extents = Vector2(32, 5)
	fire.direction = Vector2(0, -1)
	fire.spread = 16.0
	fire.initial_velocity_min = 105.0
	fire.initial_velocity_max = 210.0
	fire.gravity = Vector2(0, FIRE_RISE)
	fire.damping_min = 10.0
	fire.damping_max = 45.0
	fire.scale_amount_min = 1.0
	fire.scale_amount_max = 2.1
	fire.scale_amount_curve = _make_shrink_curve()
	fire.color_ramp = _make_ramp(
		PackedFloat32Array([0.0, 0.3, 0.7, 1.0]),
		PackedColorArray([Color(1.0, 0.9, 0.6, 0.34), Color(0.95, 0.8, 0.45, 0.32), Color(0.99, 0.45, 0.42, 0.26), Color(0.55, 0.18, 0.18, 0.0)])
	)
	fire.material = _make_additive()
	add_child(fire)

	print('click to switch the breeze on and off, the smoke leans further than the flame')


func _unhandled_input(event: InputEvent) -> void:
	if not (event is InputEventMouseButton and event.pressed):
		return

	windy = not windy

	var push: float = BREEZE if windy else 0.0
	fire.gravity = Vector2(push, FIRE_RISE)
	smoke.gravity = Vector2(push * 1.6, SMOKE_RISE)


func _add_brazier(base: Vector2) -> void:
	var size: Vector2 = Vector2(170, 28)

	var brazier: Polygon2D = Polygon2D.new()
	brazier.polygon = PackedVector2Array([-size * 0.5, Vector2(size.x, -size.y) * 0.5, size * 0.5, Vector2(-size.x, size.y) * 0.5])
	brazier.color = Color('#2a2f3d')
	brazier.position = base + Vector2(0, 14)
	add_child(brazier)


func _make_growth_curve() -> Curve:
	var curve: Curve = Curve.new()
	curve.add_point(Vector2(0.0, 0.25))
	curve.add_point(Vector2(1.0, 1.0))

	return curve


func _make_shrink_curve() -> Curve:
	var curve: Curve = Curve.new()
	curve.add_point(Vector2(0.0, 1.0))
	curve.add_point(Vector2(1.0, 0.15))

	return curve


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)

Plus d'exemples de Particules