Files
SirRoboGarage/common_libs/movements/oscillator.nim
T
SirStone 254c7dc997 feat(ModularBot): pluggable bot with 4 guns, phantom meteor movement, radar harness
- Gun harness: virtual bullet tracker, rolling fitness, auto-selector
- Guns: head-on, linear (extrapolation), circular (integrated formula), tsetlin machine (learning)
- Movement: phantom meteor gravity engine (danger histograms, phantom bullets, fire detection)
- Radar: harness + radar_lock adapter
- Color-coded modules: turret/bullet color per gun, body per movement, scan per radar
- Beats Target, SpinBot, Crazy, TrackFire in 10-round battles
2026-09-20 00:37:10 +02:00

51 lines
2.1 KiB
Nim

## Oscillator movement — perpendicular strafing relative to enemy bearing.
## Reverses direction every PERIOD ticks; wall proximity triggers one reversal
## then locks out further wall-reversals for WALL_LOCKOUT ticks to prevent
## sign-flip every tick (which would zero net movement and park the bot).
import std/math
import gun_harness/gun_interface
import movement_harness/movement_interface
const
MaxSpeed* = 8.0 ## Tank Royale max speed
Period* = 40 ## ticks between reversals; ponytail: fixed, tune if evasion feels predictable
WallMargin* = 80.0 ## px from wall to trigger early reversal
WallLockout* = 20 ## ticks to suppress further wall-reversals after one fires
type OscillatorModule* = object
sign: float ## +1 or -1, forward/backward relative to perp heading
elapsed: int ## ticks since last reversal
wallLockout: int ## remaining ticks where wall-reversal is suppressed
proc initOscillator*(): OscillatorModule =
OscillatorModule(sign: 1.0, elapsed: 0, wallLockout: 0)
proc computeMove*(m: var OscillatorModule, ws: WorldState): MoveCommand =
inc m.elapsed
if m.wallLockout > 0: dec m.wallLockout
# Perpendicular heading to enemy: enemy bearing + 90°
let enemyBearing = arctan2(ws.enemyY - ws.selfY, ws.enemyX - ws.selfX) * (180.0 / PI)
let perpHeading = (enemyBearing + 90.0) mod 360.0
let nearWall = ws.selfX < WallMargin or ws.selfX > ws.arenaWidth - WallMargin or
ws.selfY < WallMargin or ws.selfY > ws.arenaHeight - WallMargin
if m.elapsed >= Period or (nearWall and m.wallLockout == 0):
m.sign *= -1.0
m.elapsed = 0
if nearWall: m.wallLockout = WallLockout
# Turn rate = delta from current heading toward perpendicular
var delta = perpHeading - ws.selfHeading
while delta > 180.0: delta -= 360.0
while delta < -180.0: delta += 360.0
# When moving backward, flip the turn to keep perpendicular
var normDelta = if m.sign < 0: delta - 180.0 else: delta
while normDelta > 180.0: normDelta -= 360.0
while normDelta < -180.0: normDelta += 360.0
(speed: m.sign * MaxSpeed, turnRate: normDelta.clamp(-10.0, 10.0))