Files
SirRoboGarage/common_libs/movements/oscillator.nim
SirStone 2cc2a3bd87 fix(ModularBot): ram loop prevention, dead-target guards, cleaner logging
- 30-tick cooldown after ghost-stuck/timeout ram exit prevents re-entry loop
- enemy_tracker.update() skips dead bots to prevent same-tick scan resurrection
- TFIL graphics cleared when ramming is active movement
- [config] logs: white base with green-highlighted changes only
- [ram:enter] logs trigger reason and key values on false→true transition
- [death] and [target-invalid] logs retained for diagnostics
2026-09-20 20:44:45 +02:00

52 lines
2.2 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
debugGraphics*: bool
proc initOscillator*(): OscillatorModule =
OscillatorModule(sign: 1.0, elapsed: 0, wallLockout: 0, debugGraphics: false)
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))