Did you know that games with advanced graphics and controls are possible on the Wii's Internet Channel (Opera 9.0) using nothing but HTML and efficiently-coded Javascript? I'm not talking about Pong, either. I'm referring to games with graphics that rival those of Starfox for the SuperNES or the original Wolfenstein 3D for the PC. This is the first in a three-part article that will help you achieve just that. This article focuses on thinking in the mindset of optimizing your Javascript code as much as possible for both speed and memory in areas specific to the Wii. Articles already exist on the Wii Remote and the canvas object, so I will not spent a great deal of time on the specifics of those but will dive right into the meat of the topic.
Integer Math
Whenever time-critical calculations must be made, it is a good idea to work in integer-only math. (Plus, pixels are integer coordinates, anyways.) Since javascript variables are all of one type, there is no specific integer variable, so tricks must be employed to pull the extra speed boost from integer calculations over floating-point ones. There are a few ways to do this:
scale = Math.floor((x2-x1)/img.width);
scale = ((x2-x1)/img.width)>>0;
scale = ((x2-x1)/img.width)|0;
For calculations of our needs,
always avoid the first example. Javascript's built-in Math class is very slow compared to bit shifts or bit comparisons. If all values are integers already, then conversions are only needed on divides. For rounding numbers, add half of the denominator to the numerator before dividing. The second example leads us into bit shifting over division and multiplications. Divides (and to a lesser extant: multiplies) can be processor-intensive when used repeatedly, so always use bit-shifts when an integer is going to be multiplied or divided by a power of two, like so:
centerx = (x1+x2)/2;
centerx = (x1+x2)>>1;
Inner-Loop Optimization
With pixel and scanline plotting, there will almost always be some kind of looping structure that passes between two bounds to complete a final image on the screen. These will always be time-critical when animations and interactions are concerned. Take the wall texture-mapping example below (which will be covered in-depth in a future article):
while(Math.abs(tempX)<=absdx){
destH2 = (destH*tempX+dy1)|0;
this.context.drawImage(img, (sourceX*tempX/destH2)|0, 0, 1, sourceH, tempX+x1, (destY*tempX+y1)|0, absscale, destH2);
tempX+=fullscale;
}
Most of the variable calculations were moved outside the loop, leaving only the ones that absolutely had to be recalculated on each iteration of
tempX, which is the scanline variable. Other tricks for speed boosts include avoiding global and outside-scope variables if at-all possible (No, it was not possible to avoid
this.context.drawImage.) because javascript checks for the narrowest scoped variable of the given name first, then progressively broadens, leading to slowdowns.
Memory Optimization
The Wii has considerably less RAM than today's home computers, plus it lacks virtual memory, meaning the free RAM it has is the absolute limit. There are many ways to reduce the RAM footprint to avoid the dreaded out-of-memory system hang. Below is a list of those optimizations and examples, starting with the most beneficial:
Image Resolution - When texturing, why use an image that's larger than the canvas?
Image Compression - Choose a format that best fits the job based on bitdepth, transparency, and clarity.
Garbase Collection - When an array is no longer needed,
null it.
Imported Code - If you're not using all functions in a file, create a new file with just what's needed.
Code Efficiency - Compact code as much as possible
Whitespace - Avoid excessive whitespace between lines
Graphical Optimization
This Wii also is slow than many of today's home computers, so any tweaks to graphics that increase speed is greatly beneficial. Below are some examples of such optimizations in no particular order:
Opacity - Avoid opacity unless it is absolutely needed.
Z-Sorting - Sorting as little as 100 polygons inefficiently can be very noticeable.
Hidden Surfaces - Skip drawing elements that are outside bounds or facing away.
Image Resolution - Use low-res images if higher-res ones are not absolutely needed.
Page Layout - Avoid repeated page layout changes like motion, hiding, z-index changes, etc.
Closing
I've gathered some of these optimization techniques over the years, but most have come from the School of Hard Knocks while developing the
Wii Opera SDK. As I find more tweaks, I will be sure to include them in future articles. Thank you for taking time to read this. I will see you next time in the second article of the series which will focus on plotting solid triangles in 3D space on a canvas.
--Daniel Gump, HullBreachOnline.com