In this Post I will be sharing a DOM based game prototype I made.

What are DOM games?

DOM games are games which are made purely using the DOM, no canvas, no flash.  They are essentially built like web pages, where DIVS are game elements which are styled with CSS style sheets, and elements then animated around using javascript/jQuery.

The purpose of this demonstration is to
1) demonstrate that ‘simple games’ are possible without requiring the canvas,
2) show the clear limitations of DOM based games.
3) encourage you to look into canvas 🙂

My webpage is too narrow to show the game in full, so open it in a new browser by clicking the link or image below:
www.johnstejskal.com/stuff/html5/mario/

mario

CONCLUSION

DOM based games pretty much suck. Although they work to a degree on desktop browsers, however they die in the ass on mobile browsers, experiencing low frame rates and touch event latency issues.
In my example I am moving a single coin across the screen, any more then one, and the frame rate takes a big hit.. nasty.
The only benefit from using this technique over  Canvas is that it would run on IE8/IE7. Where canvas is only supported by modern browsers IE9 >.
Such an example would be great for a website banner or something basic, but in truth is barely a ‘game’. Nevertheless, it is kinda cool in its own way. :/

Here is the source code… may the force be with you.

index.html

<pre id="line1">”."><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="<a>http://www.w3.org/1999/xhtml</a>">
<head>
<meta http-equiv="<a>Content-Type</a>" content="<a>text/html; charset=utf-8</a>" />
<title>Untitled Document</title>

<link href="<a href="view-source:http://johnstejskal.com/stuff/html5/mario/css/layout.css">css/layout.css</a>" rel="<a>stylesheet</a>" type="<a>text/css</a>" />
</head>

<body>

<div id="<a>wrap</a>">
	<div id="<a>floor</a>">
    </div>

    <div id="<a>player</a>">
    </div>

    <div id="<a>scoreBox</a>">
    <p>Score 0</p>
    </div>

    <div id="<a>titleScreen</a>">
    </div>

</div>

<script type="<a>text/javascript</a>" src="<a href="view-source:http://johnstejskal.com/stuff/html5/mario/js/jquery-1.9.0.min.js">js/jquery-1.9.0.min.js</a>"> </script>
<script type="<a>text/javascript</a>" src="<a href="view-source:http://johnstejskal.com/stuff/html5/mario/js/init.js">js/init.js</a>"> </script>
</body>
</html></pre>

Css file


/* CSS Document */

body
{
display:none;
}
#wrap
{
width:700px;
height:500px;
background:url(../images/bg.gif) repeat-x;
position:absolute;
overflow:hidden;

}

#floor
{
width:700px;
height:93px;
background:url(../images/floorTile.jpg) repeat-x;
position:absolute;
bottom:0px;
display:none;
}

#player
{
width:91px;
height:133px;
background:url(../images/mario.png) repeat-x;
position:absolute;
bottom:93px;
left:100px;
display:none;
}

.coin
{
width:44px;
height:58px;
background:url(../images/coin.png) no-repeat;
position:absolute;
z-index:99;
bottom: 250px;
left:700px;
}

#scoreBox
{
width:411px;
height:70px;
position:absolute;
top:-10px;
right:0px;
overflow:hidden;
background:url(../images/scoreBacking.png);
display:none;

}
#scoreBox p
{
font-family:Verdana, Geneva, sans-serif;
color:#FFF;
font-size:30px;

font-weight:bold;
text-shadow: 1px 1px 1px #333333;
-moz-text-shadow: 1px 1px 1px #333333;
-webkit-text-shadow: 1px 1px 1px #333333;
left:150px;
top:-10px;
position:absolute

}

#titleScreen
{
background:url(../images/title.jpg) no-repeat;
width:700px;
height:500px;
z-index:999;
}

&nbsp;

javascript file init.j

// JavaScript Document

var oFloor;
var oPlayer;
var floorMoveSpeed = "-=10";
var intGameLoop;

//timer used in game loop to animate character
var charAnimTimer = 2;
var charAnimCount = 0;

var coinCreateTimer = 60;
var coinCreateCount = 0;

var runMaxLgth = 2;
var runCurrLgth = 1;

var isJumping = false;
var playerFloorYPos = 93;

var arrCoinPool = [];
var maxCoins = 3;

var score = 0;
var intGameLoop;
//-----------------------------------------------------------o
// Collision detection method
// usage,call:  hitTest( div1, div2 ); (returns true or false).
//-----------------------------------------------------------o
var hitTest = (function () {
    function getPositions( elem ) {
        var pos, width, height;
        pos = $( elem ).position();
        width = $( elem ).width() / 2;
        height = $( elem ).height();
        return [ [ pos.left, pos.left + width ], [ pos.top, pos.top + height ] ];
    }

    function comparePositions( p1, p2 ) {
        var r1, r2;
        r1 = p1[0] < p2[0] ? p1 : p2;
        r2 = p1[0] < p2[0] ? p2 : p1;
        return r1[1] > r2[0] || r1[0] === r2[0];
    }

    return function ( a, b ) {
        var pos1 = getPositions( a ),
            pos2 = getPositions( b );
        return comparePositions( pos1[0], pos2[0] ) && comparePositions( pos1[1], pos2[1] );
    };
})();
//-----------------------------------------------------------o

//-----------------------------o
//-- constructor
//-----------------------------o
$(window).load(function(e) {

	oFloor = document.getElementById("floor");
	oPlayer = document.getElementById("player");

	//add start button mouse listener
	$('#titleScreen').mousedown(function(){
	$('#titleScreen').remove();
	startGame();
	})

	$('body').css('display', 'block');

});

function startGame()
{
	$(oPlayer).css('display', 'block')
	$('#scoreBox').css('display', 'block')
	$(oFloor).css('display', 'block')

	$('body').mousedown(function(){
	playerJump();
	})

	//set gameloop
 intGameLoop = self.setInterval(function(){loop()},33);
}

//-----------------------------------------------------------o

//------------------------------------o
// Game Loop
//------------------------------------o
function loop()
{

	//change floor bg mapping
	$(oFloor).css("background-position", floorMoveSpeed);
	$('#wrap').css("background-position", '-=1');
	coinCreateCount ++
	 if(coinCreateCount >= coinCreateTimer &&  arrCoinPool.length < maxCoins ){
	 createCoin();
	 coinCreateCount = 0;
	 }

	for(i = 0; i < arrCoinPool.length; i++)
	{
		var c = $(arrCoinPool[i])
		$(c).css('left', floorMoveSpeed)
		//console.log($(c).css('left'))

		if($(c).css('left') < '-40px')
		{
		$(c).remove();
		arrCoinPool.splice(i, 1);
		}

		if(hitTest(oPlayer, c))
		{
		$(c).remove();
		arrCoinPool.splice(i, 1);
		score += 100;
		$('#scoreBox p').text('Score ' + score);
		}

	}

	if(charAnimCount >= charAnimTimer )
	{
		if(isJumping)
		return;

	 charAnimCount = 0;

	 if(runCurrLgth == 1)
	 $(oPlayer).css("background-position", "-=91")
	 else
	 $(oPlayer).css("background-position", 0)

	 if(runCurrLgth >= runMaxLgth)
	 runCurrLgth = 0;
	 else
	 runCurrLgth ++;

	}
	else
	{
	charAnimCount ++;

	}

}

//----------------------------o
//  player jump
//----------------------------o

function playerJump()
{
	if(isJumping)
	return;

	isJumping = true;
	//goTo jump frame
	$(oPlayer).css("background-position", 91)

	$(oPlayer).animate({
		bottom: 200},300, 'swing',
		function(){

			$(oPlayer).animate({
			bottom: playerFloorYPos},300,'swing',
			function()
			{
			isJumping = false;
			})

	})

}

function createCoin()
{
		var oCoin = document.createElement('div')
		$(oCoin).addClass('coin');
		$('#wrap').append(oCoin);
		arrCoinPool.push(oCoin)
}

In my next few posts I will be concentrating on HTML5 Canvas games using great tools like easelJS and TypeScript.