Flow field
Noise gives every point on the screen an angle. The arrows show the field and the particles follow it.
The editor above is running this project. Change a line and it reloads.
Godot classes used
FastNoiseLiteLine2D
The code
scripts/main.gd
extends Node
const CELL: float = 52.0
const ARROW: float = 15.0
const PARTICLES: int = 280
const TRAIL: int = 22
const SPEED: float = 130.0
const SEED: int = 20260814
var noise: FastNoiseLite = FastNoiseLite.new()
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
var trails: Array[Line2D] = []
var paths: Array[PackedVector2Array] = []
func _ready() -> void:
_add_background()
noise.seed = SEED
noise.noise_type = FastNoiseLite.TYPE_SIMPLEX
noise.frequency = 0.0022
rng.seed = SEED
var view: Vector2 = get_viewport().get_visible_rect().size
for x in int(view.x / CELL) + 1:
for y in int(view.y / CELL) + 1:
var at: Vector2 = Vector2(x, y) * CELL + Vector2(CELL, CELL) * 0.5
var direction: Vector2 = _flow(at)
var arrow: Line2D = Line2D.new()
arrow.points = PackedVector2Array([at - direction * ARROW, at + direction * ARROW])
arrow.width = 2.0
arrow.default_color = Color('#39415a')
add_child(arrow)
for i in PARTICLES:
var trail: Line2D = Line2D.new()
trail.width = 3.5
trail.default_color = Color('#8da5f3').lerp(Color('#f3d48d'), float(i) / PARTICLES)
add_child(trail)
trails.append(trail)
paths.append(PackedVector2Array([_random_point(view)]))
print('the noise gives every point an angle, change SEED for another field')
func _process(delta: float) -> void:
var view: Vector2 = get_viewport().get_visible_rect().size
for i in PARTICLES:
var path: PackedVector2Array = paths[i]
var head: Vector2 = path[path.size() - 1] + _flow(path[path.size() - 1]) * SPEED * delta
if head.x < 0.0 or head.x > view.x or head.y < 0.0 or head.y > view.y:
path = PackedVector2Array([_random_point(view)])
else:
path.append(head)
if path.size() > TRAIL:
path.remove_at(0)
paths[i] = path
trails[i].points = path
func _flow(at: Vector2) -> Vector2:
return Vector2.RIGHT.rotated(noise.get_noise_2dv(at) * TAU)
func _random_point(view: Vector2) -> Vector2:
return Vector2(rng.randf_range(0.0, view.x), rng.randf_range(0.0, view.y))
func _add_background() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)