3D Css transformations to make a lightning -fast ipad game with creative Javascript
It's possible to create even smoother animated graphics with CSS manipulated in Javascript,
Using transformations, move HTML elements in 3D space caniuse.com
automatically rendered by the GPU,which massively improves performance.
Our game has three main visual components:
the puffer fish , the background layers, and the particles that occur when the fish explode
Every graphical object is a DOM element-in fact, they're all just divs with image backgrounds and i'm animating them by adjusting their CSS properties with Javascript.
Game variables
We need to know half the width and height for working out the centerof the screen
Fish objects are stored in the fishes array and spareFishes is used to store the fishes we are not currently using
The container's 3D properties
container.style.webkitPerspective which specifies how extreme the 3D perspective is
The webkitPerspectiveOrigin should be the middle of your game screen,otherwise things will disappear into the top left as they move into the distance
Events and game loop timer
function init() {
initMouseListeners();
setInterval(gameLoop,1000/60);
}
We use setInterval to call gameLoop 60 times a second. Because setInterval requires time in milliseconds, we want to know the number of mils there are per frame.
convert fps into mils per frame ,simply divide 1000 by the frame rate.
requestAnimationFrame
fires on a browser screen redraw.
this has the benefit of syncing smoothly with the refresh cycle on your graphics card,
which avoids screen tearing.
But beause you never know how frequently requestAnimationFrame will fire,ensuring that your game runs at the same speed across differnet computers and browsers is complicated.
The other benefit to requestAnimationFrame is that it stops firing when your browser tab is hidden,saving CPU and batttery life Chrome has implemented a throttle on setInterval so that it only fires once per second if the page isn't visible .
Game loop overview
adding more fish , updating the parallax layers iteraing through all the fish , and updating them all. then finally calling emitter.update.
Making new fish
Fish object handles the postion update, and appearance of our fish. The constructor
parameters specify its 3D position , the image URL, the image size.create an HTML div elment and setting its css properties so it has a fixed size, absolute position ,and a background image.
div or img?
It'd be easier with divs. adjusting the div's background offset
this.update = function() {
this.velY = this.gravity;
this.posX += this.velX;
this.posY += this.velY;
this.posZ += this.velZ;
counter ++;
this.rotate(2);
}
velocity is how much it moves in each direction evry frame.
Fish render
This is a pretty scary-looking function. to move, scale and rotate the fish
this.render = function() {
var dom = this.domElemnt,
styleStr,
sx = Math.sin(counter*0.4)*0.04 + this.size,
xy = Math.sin(Math.PI + counter* 0.4) * 0.04 + this.size;
dom.style.webkitTransform ="translate3d(" + this.posX+"px, " + this.posY +
"px," + this.posZ + "px) scale(" + sx+"+sy+") rotate(" + Math.sin(counter* 0.05)*20 + "deg)";
}
adjusting translate3d,which is the 3D transformation.
scalled in both x and y axis rotate in 2d using antoer sine value that causes the fish's left and right oscillating rotation
Setting the fish properties
plus a random x and z offset between -250 and 250
a slightly random velocity and give it a gravity of -0.05 which is the negative
fish.posX = HALF_WIDTH + randomRange(-250,250);
fish.posY = SCREEN_HEIGHT + 100;
fish.posZ = randomRange(-250,250);
fish.velX = randomRange(-1,1);
fish.velY = randomRange(-1,-2);
fish.velZ = randomRange(-1,1);
fish.size = 1;
fish.gravity = -0.05;
Recycling the fish
take it out of the arry and forget about it ,but this is bad for memory management.
even a fish is cleared out of memory with the gabage collector, it still takes CPU to constantly create new DOM elements and Javascript objects
function removeFish(fish) {
fish.enabled = false;
fish.domElment.style.visibility = "hidden";
spareFishes.push(fish);
}
a simple pooling system,
Exploding the fish
touchstart event has an array of touch objects; it may well be that you touched down with multiple fingers at once