/gameoflife-gamejs

Conway's Game of Life for GameJs

Primary LanguageJavaScript

Game of Life

GameJs implementation of Conway's Game of Life http://en.wikipedia.org/wiki/Conway's_Game_of_Life.

The three commits represent the optimization stages this app went through:

Unoptimized simulation & drawing

http://apps.gamejs.org/gameolife/0opt

A two-dimensional array containing booleans holds the cells alive status. Two nested for loops update the simulation data by creating a new array, checking each cell's neighbour count every frame. For every cell I draw a gamejs.draw.rect().

At this point, the simulation part was the bottleneck: 30-40% of the CPU time was spent in countAliveNeighbors(): each cell re-calculates its neighbours every frame.

Optimized simulation

http://apps.gamejs.org/gameolife/1opt

Usuall, after a short while, the Game of Life simulation consists of mostly stable cells; i.e. cells that don't change their alive status.

Because so few cells change their status at a particular frame it is cheaper to update the cached neighborCount value of effected cells than to re-calculate that value every frame.

And indeed, after caching the neighbour count for each cell, the new bottleneck was the gamejs.draw.rect function taking up 25% of our time. This is the last function we still call for each cell every frame.

Optimized rendering

http://apps.gamejs.org/gameolife/2opt

gamejs.draw.rect is too slow to be called so often: it does a canvas context switch, parameter checking & type conversions. If we could directly set the couple of pixels this cell represents, instead of going throw the rect layer, we would probably be better off. There are just too many, mostly small updates to the screen every frame.

gamejs.surfacearray.SurfaceArray is for such cases: the surface's individual pixels are manipulated with set() and the SurfaceArray later blit on another Surface with a single gamejs.surfacearray.blitArray call.

Additionally, I added the dirty flag 'isModified' to each cell. This is set if a cell's alive status changes - it isModified isn't set I leave the pixel status to what it is from last frame.