Multimedia Development
Example – SVG/Javascript ‘Asteroids’ Game
Try it here: http://www.it.nuigalway.ie/~sredfern/svg/asteroids.svg
<svg width="602px" height="602px" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" onload="init();">
<script>
<![CDATA[
// GLOBAL DATA
// ----------var
var
var
var
Root=document.documentElement;
astObj = new Array();
bulletObj = new Array();
shipObj, flameObj;
// UTILITY FUNCTIONS
// ----------------function getScreenBBox(element) {
// macro to create an SVGPoint object
function createPoint (x, y) {
var point = document.documentElement.createSVGPoint();
point.x = x;
point.y = y;
return point;
}
// macro to create an SVGRect object
function createRect (x, y, width, height) {
var rect = document.documentElement.createSVGRect();
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
return rect;
}
// get the complete transformation matrix
var matrix = element.getScreenCTM();
// get the bounding box of the target element
var box = element.getBBox();
// create an array of SVGPoints for each corner
// of the bounding box and update their location
// with the transform matrix
var corners = [];
var point = createPoint(box.x, box.y);
corners.push( point.matrixTransform(matrix) );
point.x = box.x + box.width;
point.y = box.y;
corners.push( point.matrixTransform(matrix) );
point.x = box.x + box.width;
point.y = box.y + box.height;
corners.push( point.matrixTransform(matrix) );
point.x = box.x;
point.y = box.y + box.height;
corners.push( point.matrixTransform(matrix) );
var max = createPoint(corners[0].x, corners[0].y);
var min = createPoint(corners[0].x, corners[0].y);
// identify the new corner coordinates of the
// fully transformed bounding box
for (var i = 1; i < corners.length; i++) {
var x = corners[i].x;
var y = corners[i].y;
if (x < min.x) {
min.x = x;
}
else if (x > max.x) {
max.x = x;
}
if (y < min.y) {
min.y = y;
}
else if (y > max.y) {
max.y = y;
}
}
// return the bounding box as an SVGRect object
return createRect(min.x, min.y, max.x - min.x, max.y - min.y);
}
function overlaps(bb1,bb2) {
// do 2 boxes overlap?
var left1 = bb1.x, right1
var left2 = bb2.x, right2
var top1 = bb1.y, bottom1
var top2 = bb2.y, bottom2
=
=
=
=
bb1.x+bb1.width;
bb2.x+bb2.width;
bb1.y+bb1.height;
bb2.y+bb2.height;
if (left1 > right2)
return false;
if (right1 < left2)
return false;
if (top1 > bottom2)
return false;
if (bottom1 < top2)
return false;
return true;
}
function enableKeys() {
try {
// DOM2
window.addEventListener("keydown", doKey, true);
window.addEventListener("keyup", doKeyUp, true);
} catch (e) {
// MSIE6
document.attachEvent("onkeydown", doKey);
document.attachEvent("onkeyup", doKeyUp);
}
}
function rnd(low,high) {
range = high-low;
return low + Math.floor(Math.random() * range);
}
// FUNCTIONS THAT HANDLE GAME OBJECTS
// ---------------------------------function update(obj) {
obj.x += obj.dx;
obj.y += obj.dy;
obj.rot += obj.drot;
var passedBounds=false;
if (obj.x>650) {
obj.x -= 650;
passedBounds=true;
}
else if (obj.x<-50) {
obj.x += 650;
passedBounds=true;
}
if (obj.y>650) {
obj.y -= 650;
passedBounds=true;
}
else if (obj.y<-50) {
obj.y += 650;
passedBounds=true;
}
if (passedBounds==true && obj.isBullet==true) {
// bullets are destroyed when they pass the edge of the
arena
return true;
}
else {
var move="translate("+obj.x+","+(obj.y)+") rotate(" +
obj.rot + ") scale(" + obj.scale + ")";
obj.setAttributeNS(null,"transform",move);
}
return false;
}
function createAsteroid(x,y,rot,scale) {
var num = astObj.length;
var A=document.getElementById("ast");
var NewA = A.cloneNode(true);
Root.appendChild(NewA);
astObj[num] = NewA;
astObj[num].x = x;
astObj[num].y = y;
astObj[num].rot = rot;
astObj[num].dx = rnd(-5,5);
astObj[num].dy = rnd(-5,5);
astObj[num].drot = rnd(-5,5);
astObj[num].scale = scale;
return NewA;
}
function createBullet() {
var num = bulletObj.length;
var B=document.getElementById("bullet");
var NewB = B.cloneNode(true);
Root.appendChild(NewB);
NewB.isBullet = true;
bulletObj[num] = NewB;
bulletObj[num].x = shipObj.x;
bulletObj[num].y = shipObj.y;
bulletObj[num].rot = shipObj.rot;
bulletObj[num].dx = shipObj.dx;
bulletObj[num].dy = shipObj.dy;
var ang = shipObj.rot*3.1415/180.0; // radians
bulletObj[num].dx += 8 * Math.sin(ang);
bulletObj[num].dy -= 8 * Math.cos(ang);
bulletObj[num].scale = 1.0;
bulletObj[num].drot = 0.0;
shipObj.laserCharge = 0;
}
function explodeAsteroid(a) {
// remove from array the asteroid that was destroyed
var aObj = astObj[a];
for (i=a; i<astObj.length; i++)
astObj[i] = astObj[i+1];
astObj.length--;
// if asteroid is large enough then create some smaller ones
if (aObj.scale > 0.75) {
var num = rnd(3,6);
for (i=0; i<num; i++) {
rot = rnd(0,360);
scale = (aObj.scale*rnd(8,16)) / (num*10);
NewA = createAsteroid(aObj.x, aObj.y, rot, scale);
NewA.dx += aObj.dx;
NewA.dy += aObj.dy;
}
}
Root.removeChild(aObj);
}
function testAsteroidCollision(obj) {
// if the bounding box of obj overlaps that of any asteroid,
then destroy the asteroid and return TRUE
// note that the getBBox() method does not apply the current
transform
var bb1 = getScreenBBox(obj);
for (a=0; a<astObj.length; a++) {
var bb2 = getScreenBBox(astObj[a]);
if (overlaps(bb1,bb2)) {
explodeAsteroid(a);
return astObj[a];
}
}
return false;
}
function init() {
enableKeys();
startGame();
}
function startGame() {
for (a=0; a<6; a++) {
var x = 300, y=300;
while (x>=200 && x<=400 && y>=200 && y<=400) {
x = rnd(10,590);
y = rnd(10,590);
}
rot = rnd(0,360);
scale = 2.5;
createAsteroid(x,y,rot,scale);
}
shipObj = document.getElementById("ship");
shipObj.dx = shipObj.dy = shipObj.drot = shipObj.rot = 0;
shipObj.x = shipObj.y = 300;
shipObj.scale = 1.0;
shipObj.laserCharge = 50;
flameObj = document.getElementById("flame");
animate();
}
function animate() {
setTimeout("animate();", 50);
for (a=0; a<astObj.length; a++) {
update(astObj[a]);
}
for (b=0; b<bulletObj.length; b++) {
var destroyed = false;
if (update(bulletObj[b])) {
destroyed = true;
}
else if (testAsteroidCollision(bulletObj[b])) {
destroyed = true;
}
if (destroyed) {
// bullet has been deleted so remove it from array
and from SVG DOM
Root.removeChild(bulletObj[b]);
for (i=b; i<bulletObj.length; i++)
bulletObj[i] = bulletObj[i+1];
b--;
bulletObj.length--;
}
}
update(shipObj);
if (testAsteroidCollision(shipObj)) {
// to do: game over!
}
shipObj.laserCharge++;
}
function doKeyUp(e) {
handlekey(e,false);
}
function doKey(e) {
handlekey(e,true);
}
function handlekey(e,down) {
var keynum;
if(window.event) // IE
{
keynum = e.keyCode;
}
else if(e.which) // Netscape/Firefox/Opera
{
keynum = e.which;
}
if (keynum==37) { // left-arrow
if (down)
shipObj.drot = -5;
else
shipObj.drot = 0;
}
else if (keynum==38) { // up-arrow
if (down) {
var ang = shipObj.rot*3.1415/180.0; // radians
shipObj.dx += Math.sin(ang);
shipObj.dy -= Math.cos(ang);
flameObj.setAttributeNS(null,"transform","scale(1.0)");
}
else
flameObj.setAttributeNS(null,"transform","scale(0.0)");
}
else if (keynum==39) { // right-arrow
if (down)
shipObj.drot = 5;
else
shipObj.drot = 0;
}
else
if (keynum==32 && shipObj.laserCharge>=10) { // spacebar
createBullet();
}
}
//]]>
</script>
// SVG OBJECTS
// ----------// the game arena
<rect x="0" y="0" width="600" height="600" fill="#EEEEEE"
stroke="blue" stroke-width="3" />
<defs>
// this group is the generic definition of an asteroid, to be cloned
<g id="ast">
<polygon fill="lime" stroke="blue" stroke-width="3" points="17,-14 15,-12 17,0 4,9 -4,20 -15,7" />
</g>
// this group is the generic definition of a bullet, to be cloned
<g id="bullet">
<polyline fill="red" stroke="red" stroke-width="1" points="0,-4
0,4" />
</g>
</defs>
// there is only one spaceship so we create it here
<g id="ship" transform="translate(300,300)">
<polygon fill="blue" stroke="red" stroke-width="2" points="0,-5 -5,8
5,8" />
// the flame that is displayed while the spaceship is thrusting:
inside the spaceship's co-ordinate system
<polygon id="flame" transform="scale(0.0)" fill="yellow" stroke="red"
stroke-width="1" points="-4,8 -6,20 0,8 -1,23 3,8 7,20 6,8" />
</g>
</svg>
© Copyright 2026 Paperzz