I’ve pushed out a major performance update today, if your world isn’t covered in plants you should see an improvement. Early to mid-game the frame-rates should stay pretty solid. There are two main areas I’ve been working on to get the framerates up, one in logic and one in rendering.
The change in logic, which was pushed out in the last update, was to introduce some spatial mapping. Every frame each creature has to be aware of which other creatures are within its viewing distance. Originally this was done by each creature looking at each other creature and measuring the distance to it. So if we have N creatures then each creature had to measure the distance to (N-1) other creatures. That resulted in (N)*(N-1) operations, so as the number of creatures increased in your simulation the number of operations increased rapidly. This was really wasteful because when considering a single creature most the other creatures will be outside its view distance.
To reduce the wasted effort I’ve introduced a simple spatial hash. What this amounts to is putting an imaginary grid over the world and keeping track of which grid square each creature is in. Then when a creature needs to get a list of all the other creatures it needs to ‘see’ it just looks in the grid squares which are in range. There are more sophisticated methods I could use, like kd-trees, but for now I think the spatial hash is reducing the number of operations enough.
The change in rendering, which was pushed out this morning, effects the plants and mini-map. Originally when I rendered a plant or dot on the mini-map I used a function arc() on canvas. If you don’t know canvas is an HTML5 api which allows you to very easily draw simple objects on the screen. Whenever you call arc() the browser has to calculate the pixels on the screen which need colouring. For a circle this is quite an expensive operation, so rendering plants and the mini map was a pretty costly task.
To improve things I now only draw each different coloured circle once, and save those onto a canvas image which is rendered off the screen. Then each time I need to draw a circle on the map I use the function drawImage() to ‘cut’ the circle out of the ‘off-screen’ canvas then paste it onto the game screen. This seems to work pretty well; when there are loads of plants on screen the improvement is around 5-10 FPS, but the biggest impact is on the mini-map drawing which is improving framerates in all situations. I hope you see a benefit – please let me know.
I know some people are unhappy with the performance when you have a really big world. I’m going to introduce a number of new game mechanics over the next few weeks which will make it harder for the plants to thrive. The first was introduced today, I’ve sped up the rainfall variability which should make things tougher for the plants. I’m going to add a fire mechanic next. I do think the plants have it a bit easy at the moment, which is causing poor framerates. What do you guys think?