Fitting the galaxy in a computer screen

Having a realistic solar system with its planets orbiting around in their elliptic orbits and axis tilt is cool, even for an arcade game. But as is the trend with all space games: the bigger the better (and there is a certain citizen that took this to a whole new level).

So, the prototype we published earlier this month proved a success because ... well, we played it and we liked it. And we decided to continue developing a full game around it. Isn't that the dream of the kid we all have inside?

Escaping Earth prototype

 

Where to start?

Normally, as all serious studios do, we will assemble all of our man (and woman) power, set a tight schedule and start pre-production. With Escaping Earth though we decided to walk the prototype way. There are many gameplay ideas we want very much to try and given our limited resources there isn't time to think ahead. So we have already started development.

We are lucky to be developing and deploying in PlayCanvas, which allows us to prototype rapidly. We have some rough requirements of the world we would like our game to take place in which allow us to develop the basic game engine to support gameplay.

Some features which seem are already decided:

  • Large number of stars (300+) and planet systems to freely travel and explore.
  • Positions, orbits and sizes of known objects taken from scientific data and scaled accordingly to support gameplay.
  • Planet approach and landing.
  • Story mode.
  • Multiplayer mode on certain mini-games.
  • HTML5 all the way.
Distances in the solar system

 

Accuracy in large worlds

Building large simulated worlds always brings up the issue of big numbers and precision. As the numbers used in computing aren't infinite but have a certain precision (number of digits) this leads to rounding errors and some surprising results. Especially when physics are involved this can lead to unexpected behaviour in worlds larger than a limit. It is well known in the Unity engine that if you build a world larger than 100.000 units physics will start to fall apart when walking further. Even the Unity editor shows up a warning.

What is precision in computer science?

In computer science, the precision of a numerical quantity is a measure of the detail in which the quantity is expressed. This is usually measured in bits, but sometimes in decimal digits. It is related to precision in mathematics, which describes the number of digits that are used to express a value. Precision is often the source of rounding errors in computation. The number of bits used to store a number will often cause some loss of accuracy. An example would be to store "sin(0.1)" in IEEE single precision floating point standard. The error is then often magnified as subsequent computations are made using the data (although it can also be reduced).

Of course 100.000 units (if we assume they are meters), or even 1.000.000 units are nothing compared to the vast volume of space. Think that the distance of earth to the sun is 149.600.000km, which means 149.600.000.000 meters! So simulating space in a 1:1 scale is impossible with today's computers.

So we need to scale down everything to fit in the relatively small space we have available inside our render scene. But what's the scale ratio?

To calculate that we need to take account the gameplay that we are designing for:

  • Will the player orbit around a planet collecting small objects?
  • Is the player going to rotate around watching a planet orbit the sun?
  • Will he be able to zoom out and see a sun among its neighbour stars?
  • Will a galaxy view be provided?

Finding the perfect scale to handle all possible camera views will be a challenge. More on this in future posts.

Galactic Coordinate system
Wkipedia: Galactic coordinate system

 

Galactic coordinate system

When we think of space, planets and stars we tend to think that everything is in a certain place, position. We think, even though they move and circle (orbit) around, more or less they can be found at a certain point of ... space. Like the sun rising from the east each morning.

Well the truth is that everything in space is in constant motion and in crazy big velocities. Like the water in a river it moves in a new position each instant. Many systems have been created to arrange the night sky with its visible objects in stellar maps so we can navigate our view around (and hopefully our digital and, why not physical spaceships at some point).

Constellation OrionOne of the difficulties in mapping the stars is that we have few points of reference. To draft a map, which is a system of coordinates that each object can be found using a set of numbers, you need some points of reference to create the axises of that system.

From ancient times those points of reference in the night sky where the constellations.

What is a constellation?

A constellation is a group of stars that are considered to form imaginary outlines or meaningful patterns on the celestial sphere, typically representing animals, mythological people or gods, mythological creatures, or manufactured devices. The 88 modern constellations are formally defined regions of the sky together covering the entire celestial sphere.

Constellations are good to navigate around from a stationary point but to be able to take off your planet and navigate around other star systems means that you need some real points of reference inside your galaxy and not on the night sky.

This is where the Galactic coordinate system comes in. Scientists have estimated the direction and distance where the centre of our galaxy, the Milky Way, can be found based on the position of our sun. This creates a nice system of coordinates on which our known/visible stars can be mapped to.

This system uses two numbers as coordinates:

  • Galactic longitude, l
  • Galactic latitude, b

And by doing a matrix rotation using the Right Ascension/Declination and the distance from our sun we can get regular cartesian X,Y,Z coordinates with our sun at 0,0,0. Which are perfect for inputting them in a game engine.

Here is a nice online database with decent queries to get info for your favourite stars: The internet Stellar Database

And here is list that assembles everything in a nicely formatted JSON.

 

Developing the stars engine

The specifications for the star systems when inserted in the game engine are the following:

  • Ability to load an arbitrary number of stars and their corresponding system of planets, if available.
  • Ability to navigate and approach a star system in real time without pauses/loading times.
  • Stars will be able to have planets and other objects orbiting around.
  • The system will be able to load in less than 1-2 seconds and run on desktop and mobile devices.

To properly handle the loading and update times of all created objects we created our own update loops. This means that we won't be using the PlayCanvas default update method:

// update code called every frame
Billboard.prototype.update = function(dt) {
    
    if( Solar.Cameras.activeCamera ){

        this.entity.lookAt(Solar.Cameras.activeCamera.getPosition() );
        this.entity.rotateLocal(-90, 0, 0);
    }
};

But we are now using a custom array that holds instances of all methods that need to be updated every now and then:

// --- update
Solar.Update.queueAsync.push({
    accumulator: 0.0,
    threshold: 0.2,
    pausable: true,
    postUpdate: false,
    loop: 1,
    debugName: 'L17-billboard.js, update()',
    debugEntityName: this.entity.name,
    debugDescription: 'Handle billboard rotation to camera',
    debugLog: false,
    instance: this,
    callback: function(dt, physicsDt){

        if( Solar.Cameras.activeCamera ){

            this.entity.lookAt(Solar.Cameras.activeCamera.getPosition() );
            if( this.entity.model ){
                this.entity.rotateLocal(-90, 0, 0);   
            }
        }

    }.bind(this) 
});

Sounds complicated? Yes it is, but also this low level access to the render/update loop proves essential for millisecond management. It adds an overall small overhead to the application but we take this back with the performance gains that we squeeze by micro-managing everything. To achieve a 60fps we need to be able to have all of our frames rendered in less than 16-17ms.

Also using this system we can off-load some of the heavy methods that are calculated on load time and have them run async in the background. Effectively reducing the initial load time. On the build posted below you will notice that the stars appear loading one by one, which is true because their loading method is executed with an interval of 0.2-0.3 seconds.

We created 4 different update queues, in which each script can register any number of update methods and handle how and when they are executed:

Update: {
    queueSequence: [], // one job is executed on each frame
    queueEachFrame: [], // all jobs are executed on each frame
    queueFixed: [], // all jobs are executed on a fixed time interval
    queueAsync: [], // each job is executed on its own defined interval
    queues: [],
    paused: false
}

To properly take advantage of this update control we now have, we created a camera-distance.js script which allows objects (stars, planets etc.) to listen for camera events that fire when a specific distance from the object is reached.

this.cameraLevels = {
    planet: 250,
    system: 10000,
    neighborhood: 100000,
    galaxy: 1000000
};

This means when viewing a star system from a distance greater than 10.000, the planets can be hidden and their orbit loops paused.

We use those hooks for managing during runtime the update threshold for async loops. For example the star flare billboards that use a lookAt camera method require 4-5ms per frame to be calculated for 300 stars. If we slow down the update time from once per frame to once every 0.2 seconds, to improve performance, we notice a jitter in the motion of the flare. For a billboard that is close to camera that is unacceptable but for billboards that are far away it isn't (distant stars). Anyhow, we could always simulate the speed of light which is quite slow for such distances, that way this looks right :)

We did something like this which allowed us to gain 3-4ms per frame from those methods, as at any given frame only a handful of stars are close to the camera:

// --- camera distance events
this.on('Camera:space', function(level){


    switch(level) {
        case 'planet':          this.handleCameraDistance(true);
            break;
        case 'system':          this.handleCameraDistance(true);
            break;
        case 'neighborhood':    this.handleCameraDistance(false);
            break;
        case 'galaxy':          this.handleCameraDistance(false);
            break;
    }
}, this);


StarFlare.prototype.handleCameraDistance = function(state){

    if( state === true ){
        
        // Zero here means this update method will run per frame
        this.entity.script.billboard.changeUpdateThreshold(0.0);
        
    }else{
        
        this.entity.script.billboard.changeUpdateThreshold(0.2);
    }
};

Here is a test build in which you can orbit around our solar system and 300+ stars. Hint, if you know where Proxima Centauri is located you can get a glimpse of some ... exoplanets!

Escaping Earth 0.018 build
https://playcanv.as/b/6UWJvbcE/

And here is a build to help you navigate around with the star names labeled:

Escaping Earth 0.018 build
https://playcanv.as/b/JLpBsmH5/

The star systems rendered are created automatically based on the data consumed on load time, loaded from the star database. But any system can be overridden through the Playcanvas editor, and planets or other objects like asteroid belts can be added. Even a second sun!

Playcanvas editor

This will allow creating hand crafted star systems as the story and concept art progress.

 

Where we go from here?

Stay tuned! We are already in the process of developing some cool space stuff and taking off the limits of HTML5 games. If you would like to see more articles like this support us on our Patreon page. We would to love to have the resources to turn these blog posts to full blown tutorials.

If you haven't played the prototype, now is the time! You can access it here: Escaping Earth

Thanks for reading!

Escaping Earth, 3D space platformer - prototype