The Physics of Starship Soccer

To write a team that is capable of pulling off those tricky ricochet long shots, it may be helpful to know about the physics used by Starship Soccer's engine to simulate the playing arena.

Universal Constants

Like any good universe, the universe of Starship Soccer has many useful universal constants.
Universal constants don't change during a game, but many of them can be configured to alter the nature of how Starship Soccer plays out.
It is a good idea to get your team to use universal constants instead of fudge factors wherever possible -- hopefully they will then know what to do when they get a supercharged thruster, or a very heavy ball.

Co-ordinate system conventions

Starship Soccer uses a standard cartesian co-ordinate system. Positive x is to the right, positive y is up.
(ssc_minX, ssc_minY) is the bottom-left corner of the arena.
(ssc_maxX, ssc_maxY) is the top-right corner of the arena.

Angles

All the Starship Soccer angles are specified in radians. The standard math library functions also use radians.
If you are unfamiliar with radians, there are 2*PI radians in 360 degrees. You can convert from one form to the other with:
        radians = degrees * PI/180
        degrees = radians * 180/PI;

A heading of 0 radians is to the right (positive X).
PI/2 radians (90 degrees) is up (positive Y).
PI radians (180 degrees) is left (negative X).
3*PI/2 radians (270 degrees) is down (negative Y).

Objects

Even though the ships are drawn as little vector objects, the game world treats them as circles. This is also true of the ball and goal. Bullets are treated as single points (or circles with a radius of 0), and the walls are lines.
Each object has a range of attributes maintained by the game engine available to the team AIs. These attributes include the object's current position, velocity, mass, radius and type.

The Game loop

The game calculates frames ssc_framesPerSecond.
The game may skip drawing some frames if the machine cannot keep up; internally the frame rate is always the same.
Several steps are performed each frame to simulate the physics of Starship Soccer.
The following steps are documented in the order the game engine simulates them:
  1. Motion under friction
  2. Collisions, Momentum and explosions
  3. AI Processing
  4. Firing
  5. Turning
  6. Thrusting

Step 1 - Motion under friction

A smooth, dense, streamlined object that slips easily through a gas is subject to a resistive force directly proportional to its velocity - a linear resistive force.
All objects in Starship Soccer are subject to this type of resistive force.
The force is can be expressed in the form:
        FR = -kmv

The friction constant, k is available in the universal constants as ssc_friction.
From F = ma, we can calculate that the acceleration due to friction is equal to:
        ar = -kv

The velocity of an object at any time t can be calculated given its initial velocity v0:
        v( t ) =  v0 * e-kt

The convenience values ssc_frictionPerSecond and ssc_frictionPerFrame have been provided, such that:
        v( constant( ssc_secondsPerFrame) ) =  v0 * ( 1 - constant( ssc_frictionPerFrame ) )
        v( 1.0 ) = v0 * ( 1 - constant( ssc_frictionPerSecond ) )

The distance travelled by an object between time t0 and t1 can be calculated by integrating the previous function:
        d(t) =  v0 * ( e-k*t0 ) / k - v0 * ( e-k*t1 ) / k

The game engine moves objects at constant velocity during each frame.
It applies friction by using the following formula to compute the velocity of the object for the end of the frame:
        vx,vy specify the object's velocity at the start of the frame.
        vx' = vx * (1.0 - constant( ssc_frictionPerFrame ) )
        vy' = vy * (1.0 - constant( ssc_frictionPerFrame ) )

The object is moved at the average of these two values.
To compute the average velocity for the frame:
        vx,vy specify the object's velocity at the start of the frame.
        vx',vy' specify the object's velocity at the end of the frame.
        avx = ( vx' + vx ) / 2
        avy = ( vy' + vy ) / 2

To calculate the object's initial co-ordinates for next frame:
        x,y specify the object's initial co-ordinates for this frame
        x' = x + avx * constant( ssc_secondsPerFrame )
        y' = y + avy * constant( ssc_secondsPerFrame )

Step 2 - Collisions, Momentum and Explosions

After the objects have been moved, their trajectories for the frame are checked for collisions with other moving game objects, and the walls.
Collisions will usually happen during the frame, rather than at the start or at the end. The game engine solves these cases algebraically - it does not simply examine snapshots for overlaps.

Objects bounce off the walls with perfect reflection. Remember to take into account the radius of the object if you're trying to compute how an object is going to reflect!

Collisions between moving objects are modelled by reducing them to a one dimensional elastic collision.
The two colliding objects are considered to be moving along the line running between both centres at the moment of impact. The velocity components running along this line are extracted and used for the momentum transfer. Because collisions between moving objects are elastic both momentum and kinetic energy are conserved.

m1, m2 = masses
u1, u2 = pre-collision velocity component
v1, v2 = post-collision velocity component

Momentum before = Momentum after
(1) m1*u1 + m2*u2 = m1*v1 + m2*v2

K.E. before = K.E. after
(2) 1/2*m1*u1*u1 + 1/2*m2*u2*u2  = 1/2 *m1*v1*v1 + 1/2*m2*v2*v2
If you wish to solve for the post-collision velocities, v1 and v2, re-arrange (1) to:
(4) v2 = ( m1*u1 + m2*u2 - m1*v1 )  / m2;
The equation for v2 can then be situated into (2), and solved using the quadratic formula.

Collisions with a bullet also trigger an explosion.
The explosion happens just after the collision and momentum transfer with the bullet.
Any object that is within ssc_bulletExplosionRadius metres at the instant of the explosion is affected.
Each object receives ssc_bulletExplosionEnergy Joules, in the form of Kinetic Energy directed away from the centre of the explosion.

KE = 0.5 * mass * v * v = constant( ssc_bulletExplosionEnergy )
ev = sqrt( 2 * constant( ssc_bulletExplosionEnergy ) / mass )
alpha = heading from explosion to object
vx' = vx + ev * cos( alpha )
vy' = vy + ev * sin( alpha )

Step 3 - AI Processing

Once the objects have been moved, and the resulting collisions resolved, the game world is now ready for the AI routines to decide what to do.
The engine builds the sensor arrays, and calls the team DLLs.
The DLL calls the team process function, and the Starship process function for each surviving ship.
This proceeds until all teams have been processed. Note that each team is presented with the same moment in game-time to make its decisions from.
Eventually the teams return with a set of Starship controls, and the engine moves to act on them.

Step 4 - Firing

The Starships are equipped with a single forward firing energy weapon.
The weapon has an infinite supply of ammunition, and firing does not alter the mass of your ship.

The first AI command acted upon is Firing. The ship will fire during the exact moment presented to the AI for evaluation.
You can calculate the initial position and velocity of a new bullet with:
        bulletX = shipX + constant( ssc_starshipRadius ) * cos( shipHeading )
        bulletY = shipY + constant( ssc_starshipRadius ) * sin( shipHeading )
        bulletVY = shipVX + constant( ssc_bulletLaunchSpeed ) * cos( shipHeading );
        bulletVY = shipVY + constant( ssc_bulletLaunchSpeed ) * sin( shipHeading );

Bullets last for ssc_bulletLifespan, which means that their range is limited by their launch velocity relative to the target!
Bullets, like their targets, are subject to friction.

Step 5 - Turning

The starships can turn left or right at a constant speed. ssc_starshipTurnRadiansPerSecond defines how far a starship can turn in 1 second; ssc_starshipTurnRadiansPerFrame defines the smallest amount a starship can turn. It is a good idea to write your team so that they will accept being mis-aligned by ssc_starshipTurnRadiansPerFrame, so they won't be continually trying to get to an angle that they just can't reach exactly.

If you are turning your starship, you can calculate what your heading will be next frame with:
        heading' = heading +/- constant( ssc_starshipTurnRadiansPerFrame )

Step 6 - Thrusting

The starships are equipped with a single rear firing thruster that can be in one of two states -- on, or off.
Thrusting does not reduce the mass of your ship. The thruster is powered by the ship's infinity generator.
When the thruster is on, the starship accelerates in the direction it is facing at ssc_starshipThrustAcceleration m/s/s.
The thrusters act instantly, in single bursts.
After your starship shot has been fired, and your starship turned, the acceleration from your thrusters is applied to your velocity.
This can be calculated using the convenience value ssc_starshipThrustAccelerationPerFrame, which is simply ssc_starshipThrustAcceleration * ssc_secondsPerFrame:
        vx' = vx + constant( ssc_starshipThrustAccelerationPerFrame ) * cos( heading )
        vy' = vy + constant( ssc_starshipThrustAccelerationPerFrame ) * sin( heading )

The engine then returns back to step 1, moving the objects under friction.