To continue our series of articles, we’re presenting the subsequent steps on how to correctly implement detecting collisions using JS.
Step III – JS
Motion and detection of events related thereto is actually a loop that in subsequent iterations refreshes the position of all interactive elements created using HTML. If methods such as setInterval() or setTimeout() are coming to your mind right now, then you’re on the right track.
If we think about the ‘components’ that we need, we’ll surely come to the conclusion that the following are essential:
- main control loop (in order to ‘animate’ the image using subsequent iterations) – but we already know that;
- function implementing transform3d (unfortunately, jQuery without additional plugins doesn’t support CSS3);
- support for keypad cursors for objects in motion;
- creating strictly JS objects responsible for storing data on elements vulnerable to collisions (jQuery itself is too slow, and moreover – as indicated in point 3 – it doesn’t support transform3d);
- method displaying new position of the objects;
and finally, function checking the collisions.
1. Main control loop – window.requestAnimationFrame
Although creating a main loop could be done using the above-mentioned setInterval() and setTimeout() methods, we’re looking for the most optimal and also more sophisticated ways. Window.requestAnimationFrame, the native API used for supporting animation, can be helpful here. The main advantages of requestAnimationFrame are:
- use of GPU,
- optimization of simultaneous animations by fitting them in one cycle, which results in improved hardware performance as well as smoothness of the animation itself,
- stopping the current animation at the moment of minimizing the browser’s window or changing the tab.
However, this method also has one flaw – it is supported only by the latest web browsers (http://caniuse.com/#search=requestanimationframe). In order to circumvent this flaw, we will use a polyfill developed by Erik Moeller (Opera), Paul Irish (Google) and Tino Zijdel (Tweakers.net):
/* Request Animation Frame */
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
}
}
More information on window.requestAnimationFrame can be found, for example, here:
http://creativejs.com/resources/requestanimationframe/
2. Function implementing transform: transform3d()
The next step will be writing a function enabling dynamic support of transform3d() using JS.
Let’s start by downloading all required elements using jQuery, so that we can work on them:
/* Get all objects */
var $objs = $(".obj"), // all objects
$obj1 = $(".obj-1"), // object 1
$obj2 = $(".obj-2"), // object 2
$obj3 = $(".obj-3"), // object 3
$obj4 = $(".obj-4"), // object 4
$obj5 = $(".obj-5"), // object 5
$objInMotion = $(".obj-in-motion"); // object in motion
Since we already have all the <div>s, let’s create a function supporting 3D transformations in order to set the elements in the starting position:
/* Set position of elements */
function setPosition(obj, x, y, z) {
var translate = "translate3d(" + x + "," + y + "," + z + ")";
obj.css({
"-ms-transform" : translate, /* IE 9 */
"-webkit-transform" : translate, /* Chrome, Safari, Opera */
"transform" : translate /* General */
});
}
As you can see, it’s not a difficult function. It takes obj, that is the previously downloaded jQuery element, as arguments. The remaining arguments are the coordinates x, y, and z, but in the place of the ‘z’ coordinate we’ll give 0, since we’re using a 2D space.
Now, let’s apply our function to all jQuery elements:
/* Call setPosition() */
setPosition($obj1, "100px", "90px", 0);
setPosition($obj2, "760px", "90px", 0);
setPosition($obj3, "100px", "300px", 0);
setPosition($obj4, "760px", "300px", 0);
setPosition($obj5, "430px", "195px", 0);
setPosition($objInMotion, 0, 0, 0);
Here, we should bear in mind that the x and y coordinates should be given as a String with a ‘px’ suffix. Otherwise the objects would still be in position zero, since transform3d doesn’t accept numbers, but only a string.
The next part coming soon!