OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / bots / roam.gd

63 lines · gd ref:
extends RefCounted
## ROAM — wander around home: the creatures' old behaviour, as a brain (creatures → bots,
## #114 phase 2; user 2026-10-13: the default for a placed creature).
##
## A creature body used to pick its own wander target on EVERY peer, from its own RNG,
## so two peers drew the same creature walking two different ways; a bot with no brain
## was therefore told to stand still. Here the room authority alone picks the next spot
## and publishes it (BotRegistry.move → world:bots:pos:), and every peer's body walks to
## that same spot with its own gait. No navmesh: it heads straight for a point within
## `radius` of home, as the creatures did.

## Injected by BotRegistry before _bot_init.
var bot_id: String = ""

const PARAMS := [
	{"id": "radius", "label": "Roam radius", "kind": "float", "default": 12.0, "min": 1.0, "max": 128.0, "step": 1.0, "unit": "m"},
	{"id": "pause", "label": "Seconds per stop", "kind": "float", "default": 5.0, "min": 0.5, "max": 60.0, "step": 0.5},
]

var radius: float = 12.0
var pause: float = 5.0

## The longest step to the next spot. A body TELEPORTS to a target further than its
## snap distance (GroundCrawler.SNAP_DISTANCE, 8 m — the spawn / late-joiner path), so
## a roam that jumped across its whole radius teleported instead of walking.
const STEP := 6.0

var home := Vector3.ZERO
var _from := Vector3.ZERO           # the last spot published: where the body is headed
var _left := 0.0
var _rng := RandomNumberGenerator.new()


func _bot_init() -> void:
	home = BotRegistry.start_position(bot_id) if BotRegistry != null else Vector3.ZERO
	_from = home
	_rng.randomize()
	_next()


func _bot_tick(delta: float) -> void:
	_left -= delta
	if _left <= 0.0:
		_next()


## The next spot — a walkable step (<= STEP) from the last, inside `radius` of home —
## and how long until the one after: pause .. 2 × pause, so a group placed together
## does not move in step.
func _next() -> void:
	var a := _rng.randf() * TAU
	var d := _rng.randf_range(0.3, 1.0) * minf(STEP, radius)
	var p := _from + Vector3(cos(a) * d, 0.0, sin(a) * d)
	if Vector2(p.x - home.x, p.z - home.z).length() > radius:
		# Off the edge of its ground: step back toward home instead (never past it).
		var back := Vector3(home.x - _from.x, 0.0, home.z - _from.z)
		p = _from + back.limit_length(d)
	p.y = home.y
	_from = p
	_left = _rng.randf_range(pause, pause * 2.0)
	if BotRegistry != null and bot_id != "":
		BotRegistry.move(bot_id, p)