Errance
Chaque agent vise un point qui ne glisse qu'un peu autour d'un cercle devant lui. C'est ce qui fait lire l'errance comme une intention plutôt qu'un bruit.
L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.
Classes Godot utilisées
Node2DLine2DRandomNumberGenerator
Le code
scripts/main.gd
extends Node
const COUNT: int = 18
func _ready() -> void:
_add_background()
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
rng.seed = 5507
var view: Vector2 = get_viewport().get_visible_rect().size
for i in COUNT:
var agent: Node2D = Node2D.new()
agent.set_script(Get.script('wanderer'))
agent.position = view * 0.5 if i == 0 else Vector2(rng.randf_range(140, view.x - 140), rng.randf_range(140, view.y - 140))
agent.velocity = Vector2.RIGHT.rotated(rng.randf_range(0, TAU)) * 160.0
agent.rng.seed = rng.randi()
agent.show_probe = i == 0
agent.tint = Color('#8eef97') if i == 0 else Color('#8da5f3')
add_child(agent)
var note: Label = Label.new()
note.text = 'the yellow square is what the green agent steers toward, it only slides a little around its circle each frame'
note.position = Vector2(60, view.y - 56)
note.add_theme_font_size_override('font_size', 19)
note.add_theme_color_override('font_color', Color('#f3d48d'))
add_child(note)
print('%d agents steering toward a point that drifts around a circle in front of them' % COUNT)
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)scripts/wanderer.gd
extends Node2D
const MAX_SPEED: float = 170.0
const MAX_FORCE: float = 240.0
const WANDER_DISTANCE: float = 90.0
const WANDER_RADIUS: float = 55.0
const JITTER: float = 6.0
const TRAIL_POINTS: int = 90
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
var velocity: Vector2 = Vector2(MAX_SPEED, 0)
var tint: Color = Color('#8da5f3')
var show_probe: bool = false
var wander_angle: float = 0.0
var hull: Polygon2D
var trail: Line2D
var ring: Line2D
var probe: Polygon2D
func _ready() -> void:
trail = Line2D.new()
trail.width = 3.0
trail.default_color = Color(tint.r, tint.g, tint.b, 0.65)
# top_level keeps the trail in world space instead of dragging its points along with the agent
trail.top_level = true
add_child(trail)
if show_probe:
ring = Line2D.new()
ring.width = 2.0
ring.default_color = Color('#f3d48d')
ring.closed = true
ring.top_level = true
for i in 24:
ring.add_point(Vector2(cos(TAU * i / 24.0), sin(TAU * i / 24.0)) * WANDER_RADIUS)
add_child(ring)
probe = Polygon2D.new()
probe.polygon = PackedVector2Array([Vector2(-6, -6), Vector2(6, -6), Vector2(6, 6), Vector2(-6, 6)])
probe.color = Color('#f3d48d')
probe.top_level = true
add_child(probe)
hull = Polygon2D.new()
hull.polygon = PackedVector2Array([Vector2(17, 0), Vector2(-12, 10), Vector2(-12, -10)])
hull.color = tint
add_child(hull)
func _process(delta: float) -> void:
wander_angle += rng.randf_range(-JITTER, JITTER) * delta
var heading: Vector2 = velocity.normalized() if velocity.length() > 1.0 else Vector2.RIGHT
var center: Vector2 = position + heading * WANDER_DISTANCE
var spot: Vector2 = center + Vector2(cos(wander_angle), sin(wander_angle)) * WANDER_RADIUS
var desired: Vector2 = (spot - position).normalized() * MAX_SPEED
velocity = (velocity + (desired - velocity).limit_length(MAX_FORCE) * delta).limit_length(MAX_SPEED)
position += velocity * delta
hull.rotation = velocity.angle()
_wrap()
trail.add_point(position)
while trail.get_point_count() > TRAIL_POINTS:
trail.remove_point(0)
if show_probe:
ring.position = center
probe.position = spot
func _wrap() -> void:
var view: Vector2 = get_viewport_rect().size
if position.x < 0.0 or position.x > view.x or position.y < 0.0 or position.y > view.y:
position = Vector2(fposmod(position.x, view.x), fposmod(position.y, view.y))
trail.clear_points()