Difference between revisions of "Robocode/Game Physics"

From Robowiki
Jump to navigation Jump to search
m (grammar correction)
m (fix coordinates gif)
 
(6 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
This page describes the game physics of [[Robocode]].
 
This page describes the game physics of [[Robocode]].
  
== Coordinates and Direction Conventions ==
+
== Coordinates and directions ==
{|border="0" style="text-align:left"
+
[[File:RobocodeCoordinates.gif]]
! Coordinates System:
+
<br />
| [[Robocode]] is using the [http://en.wikipedia.org/wiki/Cartesian_coordinate_system Cartesian Coordinate System], which means that that the (0, 0) coordinate is located in the bottom left of the battle field.
 
|-
 
! Clockwise Direction:
 
| [[Robocode]] is using a clockwise direction convention where 0 / 360 deg is towards "North", 90 deg towards "East", 180 deg towards "South", and 270 deg towards "West".
 
|}
 
<br/>
 
Figure 1:
 
http://www.ibm.com/developerworks/java/library/j-robocode2/fig2.gif
 
  
== Time and distance measurements in Robocode ==
+
;Coordinates system
{|border="0" style="text-align:left"
+
:Robocode uses the [[wikipedia:Cartesian coordinate system|Cartesian coordinate system]], which means that that the (0, 0) coordinate is located at the bottom-left corner of the battlefield.
! Time (t):
 
| Robocode time is measured in "ticks". Each robot gets one turn per tick. 1 tick = 1 turn.
 
|-
 
! Distance Measurement:
 
| Robocode's units are basically measured in pixels, with two exceptions. First, all distances are measured with ''double'' precision, so you can actually move a fraction of a pixel. Second, Robocode automatically scales down battles to fit on the screen. In this case, the unit of distance is actually smaller than a pixel.
 
|}
 
  
== Robot Movement Physics ==
+
;Rotational direction system
{|border="0" style="text-align:left"
+
: Robocode uses a clockwise direction convention where 0° & 360° is north, 90° is east, 180° is south, and 270° is west.
! Acceleration (a):
+
: In radians it's 0 & 2𝜋 ~= 6.28 is north, 𝜋/2 ~= 1.57 is east, 𝜋 ~= 3.14 is south, and 3𝜋/2 ~= 4.71 is west.
| Robots accelerate at the rate of 1 pixel/turn/turn. Robots decelerate at the rate of 2 pixels/turn/turn. Robocode determines acceleration for you, based on the distance you are trying to move.
 
|-
 
! Velocity Equation(v):
 
| v = at. Velocity can never exceed 8 pixels/turn. Note that technically, velocity is a vector, but in Robocode we simply assume the direction of the vector to be the robot's heading.
 
|-
 
! Distance Equation (d):
 
| d = vt. That is, distance = velocity * time
 
|}
 
  
== Robot, Gun, and Radar rotation ==
+
== Time and distance ==
{|border="0" style="text-align:left"
+
;Time measurement
! Max rate of rotation of robot:
+
:Robocode time is measured in "ticks". Each robot gets one turn per tick. 1 tick = 1 turn.
| (10 - 0.75 * abs(velocity)) deg / turn. The faster you're moving, the slower you turn.
 
|-
 
! Max rate of rotation of gun:
 
| 20 deg / turn. This is added to the current rate of rotation of the robot.
 
|-
 
! Max rate of rotation of radar:
 
| 45 deg / turn. This is added to the current rate of rotation of the gun.
 
|}
 
  
== Bullets ==
+
;Distance measurement
{|border="0" style="text-align:left"
+
:Robocode's distance units are measured with double precision, so you can move a fraction of a unit. Generally, 1 Robocode distance unit = 1 pixel, except when Robocode automatically scales down battles to fit on the screen.
! Damage:
 
| 4 * firepower. If firepower > 1, it does an additional damage = 2 * (power - 1).
 
|-
 
! Velocity:
 
| 20 - 3 * firepower.
 
|-
 
! GunHeat generated:
 
| 1 + firepower / 5. You cannot fire if gunHeat > 0. All guns are hot at the start of each round.
 
|-
 
! Power returned on hit:
 
| 3 * firepower.
 
|}
 
  
== Collisions ==
+
== Movement physics ==
{|border="0" style="text-align:left"
+
;Acceleration (a)
! With Another Robot:
+
:Robots accelerate at the rate of 1 pixel/turn every turn. Robots decelerate at the rate of 2 pixels/turn every turn. Robocode determines acceleration for you, based on the distance you are trying to move.
| Each robot takes 0.6 damage. If a robot is moving away from the collision, it will not be stopped.
 
|-
 
! With a Wall:
 
| [[AdvancedRobot]]s take abs(velocity) * 0.5 - 1; (Never < 0).
 
|}
 
  
== Robocode Processing Loop ==
+
;Velocity (v)
The order that Robocode runs is as follows:
+
:The velocity equation is: v = at. Velocity can never exceed 8 pixels/turn. Note that technically, velocity is a vector, but in Robocode we simply assume the direction of the vector to be the robot's heading.
  
# Battle view is (re)painted.
+
;Distance (d)
# All robots execute their code until they take action (and then paused).
+
:The distance formula is: d = vt. That is, distance = velocity * time
# Time is updated (time = time + 1).
 
# All bullets move and check for collisions. This includes firing bullets.
 
# All robots move (gun, radar, heading, acceleration, velocity, distance, in that order).
 
# All robots perform scans (and collect team messages).
 
# All robots are resumed to take new action.
 
# Each robot processes its event queue.
 
  
Most of this can be gleamed by following the method calls from BaseBattle.runRound() and Battle.runTurn() in the robocode.battle module.
+
== Rotation ==
 +
;Robot base rotation
 +
:The maximum rate of rotation is: (10 - 0.75 * abs(velocity)) deg/turn. The faster you're moving, the slower you turn.
  
Event dispatch happens from within commands that take a turn. So the call stack when an event is delivered usually looks like this:
+
;Gun rotation
 +
:The maximum rate of rotation is: 20 deg/turn. This is added to the current rate of rotation of the robot.
  
<blockquote>Robocode internals → Robot's run method → Robocode internals → Event handler</blockquote>
+
;Radar rotation
 +
:The maximum rate of rotation is: 45 deg/turn. This is added to the current rate of rotation of the gun.
  
However, event handlers can themselves make calls that take turns. If one of these happens to generate an event, we might see a call stack like
+
== Bullets ==
 +
;Bullet damage
 +
:4 * firepower. If firepower > 1, it does an additional damage = 2 * (power - 1).
  
<blockquote>Robocode internals → Robot's run method → Robocode internals → First event handler → Robocode internals → Second event handler</blockquote>
+
;Bullet velocity
 +
:20 - 3 * firepower.
  
But this kind of nesting could lead to a stack overflow. Or—more commonly—cases where the first handler finishes up its actions long after the response-provoking situation has passed. Thus, Robocode takes special steps for events generated within event handlers; these measures are implemented in EventManager.processEvents().  In particular, the call stack will get as far as
+
;Gun heat generated on firing
 +
:1 + firepower / 5. You cannot fire if gunHeat > 0. All guns are hot at the start of each round.
  
<blockquote>Robocode internals → Robot's run method → Robocode internals (including processEvents) → First event handler → Robocode internals (including processEvents)</blockquote>
+
;Energy returned on hit
 +
:3 * firepower.
  
but then the inner processEvents will detect the impending nesting and throw an EventInterruptedException, which unwinds the stack to the catch block in the outer processEvents:
+
== Collisions ==
 +
;Collision with another robot
 +
:Each robot takes 0.6 damage. If a robot is moving away from the collision, it will not be stopped.
  
<blockquote>Robocode internals → Robot's run method → Robocode internals (including processEvents)</blockquote>
+
;Collision with a wall
 +
:AdvancedRobots take damage = abs(velocity) * 0.5 - 1 (never < 0).
  
effectively canceling whatever the running event handler was up to.  Next, the event-delivering loop in the outer processEvents resumes delivering events, letting the second event handler execute unnested:
+
== Robocode processing loop ==
 +
The order that Robocode runs is as follows:  
  
<blockquote>Robocode internals → Robot's run method → Robocode internals → Second event handler</blockquote>
+
# Battle view is (re)painted.
 +
# All robots execute their code until they take action (and are then paused).
 +
# Time is updated (time++).
 +
# All bullets move (including the bullet fired in the last tick) and are checked for collisions.
 +
# All robots move (gun, radar, heading, acceleration, velocity, distance, in that order. gun heat is also decreased in this step).
 +
# All robots perform scans (and collect team messages).
 +
# All robots are resumed to take new action.
 +
# Each robot processes its event queue.
  
It is possible, though not usually useful, to catch and respond to EventInterruptedExceptions in the first handler instead.
+
Most of this can be gleaned by following the method calls from [https://github.com/robo-code/robocode/blob/0eb93ba532bc6731b7ff8dd02da1308d92ccb2fd/robocode.battle/src/main/java/net/sf/robocode/battle/BaseBattle.java#L251 <code>BaseBattle.runRound()</code>] and [https://github.com/robo-code/robocode/blob/0eb93ba532bc6731b7ff8dd02da1308d92ccb2fd/robocode.battle/src/main/java/net/sf/robocode/battle/Battle.java#L411 <code>Battle.runTurn()</code>] in the <code>robocode.battle</code> module.
  
=== Firing Pitfall ===
+
=== Firing pitfall ===
Because bullets are fired before the gun is moved, calling setFire() will cause the bullet to leave at the current gun heading. This may seem counter-intuitive if you are used to thinking in terms of pointing a gun, then shooting. It is also inconvenient because you can't call <code>setTurnGun(...)</code> and <code>setFire(...)</code> right after each other (not if you need perfect accuracy, anyway). Most of the time, the error will be so small you won't notice it, but if you're testing a pattern matcher against <code>sample.Walls</code>, you will occasionally spot the bug.
+
Because bullets are fired before the gun is moved, calling setFire() will cause the bullet to leave at the current gun heading. This may seem counter-intuitive if you are used to thinking in terms of pointing a gun, then shooting. It is also inconvenient because you can't call <code>setTurnGun(...)</code> and <code>setFire(...)</code> right after each other (not if you need perfect accuracy, anyway). Most of the time, the error will be so small you won't notice it, but if you're testing a pattern matcher against sample.Walls, you will occasionally spot the bug.
  
 
To get the bullet to leave after turning the gun, you will need to use code like this:
 
To get the bullet to leave after turning the gun, you will need to use code like this:
Line 129: Line 96:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== See also ==
+
== Event handling ==
 +
 
 +
Event dispatch happens from within commands that take a turn.  So the call stack when an event is delivered usually looks like this:
 +
 
 +
<blockquote>Robocode internals → Robot's run method → Robocode internals → Event handler</blockquote>
 +
 
 +
However, event handlers can themselves make calls that take turns.  If one of these happens to generate an event, we might see a call stack like
 +
 
 +
<blockquote>Robocode internals → Robot's run method → Robocode internals → First event handler → Robocode internals → Second event handler</blockquote>
 +
 
 +
But this kind of nesting could lead to a stack overflow.  Or—more commonly—cases where the first handler finishes up its actions long after the response-provoking situation has passed.  Thus, Robocode takes special steps for events generated within event handlers; these measures are implemented in EventManager.processEvents().  In particular, the call stack will get as far as
 +
 
 +
<blockquote>Robocode internals → Robot's run method → Robocode internals (including processEvents) → First event handler → Robocode internals (including processEvents)</blockquote>
 +
 
 +
but then the inner processEvents will detect the impending nesting and throw an EventInterruptedException, which unwinds the stack to the catch block in the outer processEvents:
 +
 
 +
<blockquote>Robocode internals → Robot's run method → Robocode internals (including processEvents)</blockquote>
 +
 
 +
effectively canceling whatever the running event handler was up to.  Next, the event-delivering loop in the outer processEvents resumes delivering events, letting the second event handler execute unnested:
  
=== Robot API ===
+
<blockquote>Robocode internals → Robot's run method → Robocode internals → Second event handler</blockquote>
* [http://robocode.sourceforge.net/docs/robocode/ Robot API]
 
  
=== Tutorials ===
+
It is possible, though not usually useful, to catch and respond to EventInterruptedExceptions in the first handler instead.
* [[Robocode/System Requirements|System Requirements for Robocode]]
 
* [[Robocode/Download|How to download and install Robocode]]
 
* [[Robocode/Robot Anatomy|The anatomy of a robot]]
 
* [[Robocode/Getting Started|Getting started with Robocode]]
 
* [[Robocode/My First Robot|My First Robot Tutorial]]
 
* [[Robocode/Scoring|Scoring in Robocode]]
 
* [[Robocode/Robot Console|Using the robot console]]
 
* [[Robocode/Downloading_Robots|Downloading other robots]]
 
* [[Robocode/Learning from Robots|Learning from other robots]]
 
* [[Robocode/Package Robot|Package your robot]]
 
* [[Robocode/FAQ|Frequently Asked Questions (FAQ)]]
 
* [[Robocode/Articles|Articles about Robocode]]
 
* [[Robocode/Console Usage|Starting Robocode from the command line]]
 
* [[Robocode/Graphical_Debugging|Graphical debugging]]
 
* [[Robocode/Eclipse|Using Eclipse as IDE]]
 
* [[Robocode/Eclipse/Create_a_Project|Creating a project for your robots]]
 
* [[Robocode/Eclipse/Create_a_Robot|Creating a robot in Eclipse]]
 
* [[Robocode/Running from Eclipse|Running your robot from Eclipse]]
 
* [[Robocode/Eclipse/Debugging Robot|Debugging your robot with Eclipse]]
 
  
=== News and Releases ===
+
== See also ==
* [http://sourceforge.net/export/rss2_project.php?group_id=37202 RSS Feeds for the Robocode project]
 
* [http://sourceforge.net/project/showfiles.php?group_id=37202&package_id=29609 Robocode file releases]
 
  
=== Home pages ===
+
{{RobocodeDocsList}}
* [http://robocode.sourceforge.net/ Classic homepage]
 
* [http://sourceforge.net/projects/robocode Robocode project at SourceForge]
 
* [http://robocoderepository.com/ Robocode Repository]
 
* [[wikipedia:Robocode|Wikipediaentry for Robocode]]
 
  
 
[[Category:Robocode Documentation]]
 
[[Category:Robocode Documentation]]
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]

Latest revision as of 05:06, 16 September 2021

This page describes the game physics of Robocode.

Coordinates and directions

RobocodeCoordinates.gif

Coordinates system
Robocode uses the Cartesian coordinate system, which means that that the (0, 0) coordinate is located at the bottom-left corner of the battlefield.
Rotational direction system
Robocode uses a clockwise direction convention where 0° & 360° is north, 90° is east, 180° is south, and 270° is west.
In radians it's 0 & 2𝜋 ~= 6.28 is north, 𝜋/2 ~= 1.57 is east, 𝜋 ~= 3.14 is south, and 3𝜋/2 ~= 4.71 is west.

Time and distance

Time measurement
Robocode time is measured in "ticks". Each robot gets one turn per tick. 1 tick = 1 turn.
Distance measurement
Robocode's distance units are measured with double precision, so you can move a fraction of a unit. Generally, 1 Robocode distance unit = 1 pixel, except when Robocode automatically scales down battles to fit on the screen.

Movement physics

Acceleration (a)
Robots accelerate at the rate of 1 pixel/turn every turn. Robots decelerate at the rate of 2 pixels/turn every turn. Robocode determines acceleration for you, based on the distance you are trying to move.
Velocity (v)
The velocity equation is: v = at. Velocity can never exceed 8 pixels/turn. Note that technically, velocity is a vector, but in Robocode we simply assume the direction of the vector to be the robot's heading.
Distance (d)
The distance formula is: d = vt. That is, distance = velocity * time

Rotation

Robot base rotation
The maximum rate of rotation is: (10 - 0.75 * abs(velocity)) deg/turn. The faster you're moving, the slower you turn.
Gun rotation
The maximum rate of rotation is: 20 deg/turn. This is added to the current rate of rotation of the robot.
Radar rotation
The maximum rate of rotation is: 45 deg/turn. This is added to the current rate of rotation of the gun.

Bullets

Bullet damage
4 * firepower. If firepower > 1, it does an additional damage = 2 * (power - 1).
Bullet velocity
20 - 3 * firepower.
Gun heat generated on firing
1 + firepower / 5. You cannot fire if gunHeat > 0. All guns are hot at the start of each round.
Energy returned on hit
3 * firepower.

Collisions

Collision with another robot
Each robot takes 0.6 damage. If a robot is moving away from the collision, it will not be stopped.
Collision with a wall
AdvancedRobots take damage = abs(velocity) * 0.5 - 1 (never < 0).

Robocode processing loop

The order that Robocode runs is as follows:

  1. Battle view is (re)painted.
  2. All robots execute their code until they take action (and are then paused).
  3. Time is updated (time++).
  4. All bullets move (including the bullet fired in the last tick) and are checked for collisions.
  5. All robots move (gun, radar, heading, acceleration, velocity, distance, in that order. gun heat is also decreased in this step).
  6. All robots perform scans (and collect team messages).
  7. All robots are resumed to take new action.
  8. Each robot processes its event queue.

Most of this can be gleaned by following the method calls from BaseBattle.runRound() and Battle.runTurn() in the robocode.battle module.

Firing pitfall

Because bullets are fired before the gun is moved, calling setFire() will cause the bullet to leave at the current gun heading. This may seem counter-intuitive if you are used to thinking in terms of pointing a gun, then shooting. It is also inconvenient because you can't call setTurnGun(...) and setFire(...) right after each other (not if you need perfect accuracy, anyway). Most of the time, the error will be so small you won't notice it, but if you're testing a pattern matcher against sample.Walls, you will occasionally spot the bug.

To get the bullet to leave after turning the gun, you will need to use code like this:

long fireTime = 0;
void doGun() {
    if (fireTime == getTime() && getGunTurnRemaining() == 0) {
        setFire(2);
    }

    // ... aiming code ...

    setTurnGunRight(...);
    // Don't need to check whether gun turn will complete in single turn because
    // we check that gun is finished turning before calling setFire(...).
    // This is simpler since the precise angle your gun can move in one tick
    // depends on where your robot is turning.
    fireTime = getTime() + 1;
}

Event handling

Event dispatch happens from within commands that take a turn. So the call stack when an event is delivered usually looks like this:

Robocode internals → Robot's run method → Robocode internals → Event handler

However, event handlers can themselves make calls that take turns. If one of these happens to generate an event, we might see a call stack like

Robocode internals → Robot's run method → Robocode internals → First event handler → Robocode internals → Second event handler

But this kind of nesting could lead to a stack overflow. Or—more commonly—cases where the first handler finishes up its actions long after the response-provoking situation has passed. Thus, Robocode takes special steps for events generated within event handlers; these measures are implemented in EventManager.processEvents(). In particular, the call stack will get as far as

Robocode internals → Robot's run method → Robocode internals (including processEvents) → First event handler → Robocode internals (including processEvents)

but then the inner processEvents will detect the impending nesting and throw an EventInterruptedException, which unwinds the stack to the catch block in the outer processEvents:

Robocode internals → Robot's run method → Robocode internals (including processEvents)

effectively canceling whatever the running event handler was up to. Next, the event-delivering loop in the outer processEvents resumes delivering events, letting the second event handler execute unnested:

Robocode internals → Robot's run method → Robocode internals → Second event handler

It is possible, though not usually useful, to catch and respond to EventInterruptedExceptions in the first handler instead.

See also

Robocode API

Beginner Guides

External Editors

.NET Robots

Links