Research aimTo() mechanics — gun turn limits and API #149

Closed
opened 2026-09-12 11:37:10 +02:00 by SirStone · 1 comment
Owner

Question

How does gun turning work in Tank Royale? What is the max gun turn rate per tick? Is it affected by body turn? What API call sets the gun turn? Does an aimTo()-like helper already exist in the bot API or in any existing bot, or must we write one? This determines the aimTo() function contract.

Parent map: #147

## Question How does gun turning work in Tank Royale? What is the max gun turn rate per tick? Is it affected by body turn? What API call sets the gun turn? Does an `aimTo()`-like helper already exist in the bot API or in any existing bot, or must we write one? This determines the aimTo() function contract. Parent map: #147
Author
Owner

Research Findings: Gun Turn Mechanics

Max Gun Turn Rate

20.0 degrees/tick (MAX_GUN_TURN_RATE constant in tankroyale_botapi/constants.nim)

API Call to Set Gun Turn

proc setGunTurnRate*(rate: float)
  • Parameter: rate in degrees/tick, automatically clamped to ±20.0
  • Example: setGunTurnRate(desiredDelta.clamp(-20.0, 20.0))

Gun Turn Independence vs Body Turn

Gun turn is affected by body turn via an opt-in adjustment flag.

Two separate control mechanisms:

  1. Raw gun turn: Independent of body rotation

    • Set via setGunTurnRate(rate)
    • Gun rotates at specified rate, regardless of body motion
  2. Adjusted gun turn (opt-in): Affects relative behavior

    • Enable via setAdjustGunForBodyTurn(true) in onRoundStarted()
    • When enabled, body turns "carry" the gun turret along
    • Actual gun angle changes = body rotation + gun turn rate

In classic Robocode terms: Tank Royale separates these concerns. You set the gun turn rate independently, then optionally enable adjustment that makes body turns affect absolute gun direction. OscillatorBot and QBot both use this.

Existing aimTo() Helper

Yes, one exists. In PPO_Bot_garage/src/PPO_Bot/controllers.nim:

proc aimToTick*(targetX, targetY, botX, botY, gunDirection: float): float =
  ## Returns gunTurnRate (clamped to ±MAX_GUN_TURN_RATE) to rotate gun toward target.
  let bearing = normalizeRelativeAngle(directionTo(botX, botY, targetX, targetY) - gunDirection)
  bearing.clamp(-MAX_GUN_TURN_RATE, MAX_GUN_TURN_RATE)

Contracts to match:

  • Takes current position, target position, gun direction
  • Returns turn rate (degrees/tick) in [-20, 20]
  • Normalizes angles to relative bearing
  • Pure function, no side effects

Existing Usage Examples

  • OscillatorBot: Directly computes gunDelta and clamps
    let bearing = directionTo(getX(), getY(), e.x, e.y)
    let gunDelta = normalizeRelativeAngle(bearing - getGunDirection())
    setGunTurnRate(gunDelta.clamp(-MAX_GUN_TURN_RATE, MAX_GUN_TURN_RATE))
    
  • QBot: Identical pattern with offset aim
    let desiredDelta = normalizeRelativeAngle(bearingToEnemy + aimOffset - gunDir)
    setGunTurnRate(desiredDelta.clamp(-20.0, 20.0))
    

Conclusion for aimTo()

The aimToTick() helper already exists in PPO_Bot. Reuse it rather than rewrite. All three existing patterns (OscillatorBot direct, QBot with offset, PPO's aimToTick) converge on the same math: (targetBearing - gunDirection).clamp(±20). No surprises; the API is simple and uniform.

## Research Findings: Gun Turn Mechanics ### Max Gun Turn Rate **20.0 degrees/tick** (`MAX_GUN_TURN_RATE` constant in `tankroyale_botapi/constants.nim`) ### API Call to Set Gun Turn ```nim proc setGunTurnRate*(rate: float) ``` - Parameter: rate in degrees/tick, automatically clamped to ±20.0 - Example: `setGunTurnRate(desiredDelta.clamp(-20.0, 20.0))` ### Gun Turn Independence vs Body Turn Gun turn is **affected by body turn via an opt-in adjustment flag**. Two separate control mechanisms: 1. **Raw gun turn**: Independent of body rotation - Set via `setGunTurnRate(rate)` - Gun rotates at specified rate, regardless of body motion 2. **Adjusted gun turn** (opt-in): Affects relative behavior - Enable via `setAdjustGunForBodyTurn(true)` in `onRoundStarted()` - When enabled, body turns "carry" the gun turret along - Actual gun angle changes = body rotation + gun turn rate In classic Robocode terms: Tank Royale separates these concerns. You set the gun turn rate independently, then *optionally* enable adjustment that makes body turns affect absolute gun direction. OscillatorBot and QBot both use this. ### Existing aimTo() Helper **Yes, one exists.** In `PPO_Bot_garage/src/PPO_Bot/controllers.nim`: ```nim proc aimToTick*(targetX, targetY, botX, botY, gunDirection: float): float = ## Returns gunTurnRate (clamped to ±MAX_GUN_TURN_RATE) to rotate gun toward target. let bearing = normalizeRelativeAngle(directionTo(botX, botY, targetX, targetY) - gunDirection) bearing.clamp(-MAX_GUN_TURN_RATE, MAX_GUN_TURN_RATE) ``` **Contracts to match:** - Takes current position, target position, gun direction - Returns turn rate (degrees/tick) in [-20, 20] - Normalizes angles to relative bearing - Pure function, no side effects ### Existing Usage Examples - **OscillatorBot**: Directly computes gunDelta and clamps ```nim let bearing = directionTo(getX(), getY(), e.x, e.y) let gunDelta = normalizeRelativeAngle(bearing - getGunDirection()) setGunTurnRate(gunDelta.clamp(-MAX_GUN_TURN_RATE, MAX_GUN_TURN_RATE)) ``` - **QBot**: Identical pattern with offset aim ```nim let desiredDelta = normalizeRelativeAngle(bearingToEnemy + aimOffset - gunDir) setGunTurnRate(desiredDelta.clamp(-20.0, 20.0)) ``` ### Conclusion for aimTo() The `aimToTick()` helper already exists in PPO_Bot. Reuse it rather than rewrite. All three existing patterns (OscillatorBot direct, QBot with offset, PPO's aimToTick) converge on the same math: `(targetBearing - gunDirection).clamp(±20)`. No surprises; the API is simple and uniform.
SirStone added the wayfinder:research label 2026-09-12 12:22:07 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SirStone/SirRoboGarage#149