In the Last log where I posted a link to a live version of my adventure engine, I mentioned that I was experimenting with various ways to build up a screen to figure out what works and what not and what methods are efficient and usable. It occurred to me that various game types must have different approaches on how to render a screen that make sense for that specific type and I wasn't sure if my approach was the right one.
So I forked my adventure engine code and retooled it to be a continues side scrolling tile based platformer. The reason for the continues scrolling was because the engine already tries to draw the entire screen 30 times a second. A non scrolling game is easier on the CPU, but more difficult to code as all moving parts will need their own background redraw buffer. I know there are other options in HTML5 Canvas to make assets act more like real sprites, but I would like this project to be as basic as possible controlling every sub-pixel.
The quick proof of concept I whipped up did yield some interesting results. Instead of going down a list of object to draw as I do in the adventure engine, the platformer just scans the 320 by 200 pixels and using offsets and a tile map, figures out which pixel from which tile to draw. It looks a bit like this :
The snowy background just is random noise. The draw function also does not clip edges. What this demo does is simply take this data :
<mapData> 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, 2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5, 1,1,1,1,1,1,1,1,1,4,4,4,4,4,4,4, 1,1,1,1,1,1,1,1,4,4,4,4,4,4,4,4, 1,1,1,1,1,1,1,4,4,4,4,4,4,4,4,4 </mapData>
And per pixel uses this to determine where the image data should come from. Now here is where it gets interesting because when I first implemented this I used a tilemap, or simply an image that held all the tiles in order.
Using only the first tile was fine. Well under one third of a second to draw 30 frames, but as soon as I put in the code that moves the coordinates in the drawing routine to get the data from the second, third to sixth tile, the render loop slowed down by a factor of 10.
This code wasn't that much different from the function I use in the adventure engine for animating the assets, but I never saw any drastic reduction in performance. In this case I did!
It turned out to be a single multiplication in the line where the X and Y coordinates were mapped to the image object. Apparently the impact of that one multiplication, per pixel, either gave an enormous overhead or completely nullified any clever predictive execution methods that I am not aware of to make the whole thing become unusable.
The solution was simple and crude. Instead of an image map, all the tiles were simply loaded into their own containers. The asset loader is quite capable of that, so I just cut them up and did it this way. Just passing the ID of the image data cause no slowdown and the engine now is perfectly capable of drawing the entire screen 30 times a second with a myriad of tiles and tile sized in fractions of a second.
I found this really interesting and it made me realize that this to is an area where it helps to have some intuition from experience. This frame shifting method is fine for a system where only a couple of assets are animated in this way, but not for others.
This set me out to explore other methods to build up a screen. I already named a few, but there obviously are more. Now what I'm doing is in no means using ASM on a 8-bit micro, racing the beam, but the general methods hold true.
This made me experiment with various effects and methods which resulted in a strange screensaver result that I would like to share with you now :
What this is, is the platformer code forked and made to draw the assets more like the adventure game, but also use the scanline function to do some effects. This turned out to be a real cheap way to get rudimentary blurring/dithering on the fly for background and forground effects.
The tile objects are just bounding about, being drawn with various amounts of "chaos", while the buffer is constantly altering and shifting the data around, resulting in a type of iTunes Flurry effect. Also note that this effect is VERY HARD on Youtube's compression algorithm. It looks much cleaner in real life.
These types of effects could be very useful in a space fighter top scrolling game where, at least the characters would be drawn from a list in such a way.
I'll experiment with these types of render methods a bit more and try to formalize it into a single effects/tile/sprite library. I think these adventures are giving me some insight on what data and what attributes should be structured in what way considering game type X or Y.
Perhaps sometimes an asset does need to contain a part of its own drawing function and variables after all and perhaps sometimes the buffer is more then just a blank canvas.
And just for fun, another configuration.. FIREBALLS!!!!