Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

Tips to accelerate your original game

To make your game more interesting, you should pay much attention to keep high performance. This is UX problem, but it is not designer who can solve. Only developer has solution for this problem, so we should learn about when we face problem and how many approaches we have.

Reducing I/O

Cache

This is popular tip for background-image, map-chip and character-chip.

Load picture and draw it onto cache on RAM, then you do not have to access to storage. For instance, your STG may load background-image when player decided the stage to play. By this cache, your STG does not have to read storage for background image during this stage.

Lazy-loading

In previous case, your STG needs to lock screen while it loads resources onto RAM*1. It's better to shorten this time, or player will feel that your game is boring.

To reduce locking, lazy-loading can be solution. At initialising phase, your STG does not have to load background-image of boss-stage. Postpone loading, then you can shorten the lock.

Pre-loading

Here is another and opposite solution. While player is choosing stage to play, your STG can load resources onto RAM. When player decides stage, necessary data is already loaded so you can start game immediately for player.

To use this tip, programmer should understand player's need and how they control your game. For instance, when player enters stage-select page, your STG may load SE (Sound Effect) of shooting action because you knows that player will choose stage so your STG should load such resources later. I think this is similar to implementing recommendation engine.

Are you implementing HTML5 game? If so, you may try pre-fetch API.

Reuse drawn picture

During user plays your STG, you should draw background-image and scroll it from right to left. So in each frame you should draw large picture, it costs resource of player's computer.

To reduce this cost, you can reuse background-image which is already drawn. You shift background-image some pixels, and draw only the right part. You can reuse almost all of drawn picture, and focus on drawing new parts.

Here is another example: even though you are implementing 3D game, you do not have to compute 3D models in each frame, because you can store computed images to RAM and use it instead.

Put multiple resource into one file

This is popular tip for map-chip and character-chip. And this is also very famous for web developer as CSS Sprites. Data URI also can be solution.

By this tip, you can reduce number of resource to load. So it's effective especially when resource is far from player. Learn latency for detail.

Compress data

You may like raw data format like BMP format, but when you publish your product it's better to use compressed format. Then you can reduce data size to load, so it will reduce time to load. Learn Throughput for detail.

To compress data, your may use ZIP or other format. It's OK but please remember that decompression costs machine resource.

Reducing computing cost

divide main-loop and loop-to-render

When you implement graphical game, you should have main-loop like below:

function main(){
  compute();
  render();
  setTimeout(main, 15); // about 60 FPS
}
main();

It works, but it has one problem.

This code tries to render image 66.6 times per second, but in my environment 6 of them has no meaning because we render twice or more between 2 display refresh. You can try it at this page.

It means that we render needless picture 6 times per second... it should be stopped.

var previousTimeToRender = 0;
function tryToRender(){
  var now = Date.now();
  if (now - previousTimeToRender > 1000/60) {
    previousTimeToRender = now;
    draw();
  }
  requestAnimationFrame(tryToRender);
};

function main(){
  compute();
  setTimeout(main, 1000/60);
}

main();
requestAnimationFrame(tryToRender);

Looks too complex? Then capsule it:

function Renderer(fps) {
  this.fps_ = fps;
  this.previousTimeToRender_ = 0;
  this.callback_ = null;
};
Renderer.prototype.tick = function(){
  var now = Date.now();
  if (now - this.previousTimeToRender_ > 1000/this.fps_) {
    this.previousTimeToRender_ = now;
    this.callback_();
  }
  requestAnimationFrame(this.tick.bind(this));
};
Renderer.prototype.register = function(callback){
  this.callback_ = callback;
  this.tick();
};

// then you can code like below:
function main(){
  compute();
  setTimeout(main, 1000/60);
}
main();
var renderer = new Renderer(60);
renderer.register(render);

And if we can reduce FPS to draw without UX problem, it's also good way to improve performance.

var renderer = new Renderer(30); // draw 30 times per seconds. we can keep computing 60 times per second.

Algorithm

Algorithm is very important to implement game. Routing, Z-sort, collision detection, AI... there are a lot of algorithm used in game. Brute-force is acceptable during development, but before you publish your game, it's better to consider to replace it with efficiently implementation.

This is too large topic for this article, so I just list up sample codes:

Now I'm interested in Simulated Annealing, I'll try to code a simple one.

*1:you may know that some PSP games display 'LOADING...' again and again