流场

噪声为屏幕上每个点给出一个角度。箭头显示这个场,粒子跟着它走。

上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。

用到的 Godot 类

FastNoiseLiteLine2D

代码

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)

更多程序化生成示例