254c7dc997
- 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
51 lines
2.1 KiB
Nim
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))
|