Pages

Showing posts with label HTML5. Show all posts
Showing posts with label HTML5. Show all posts

Monday, August 1, 2011

HTML5 - Sliding Tile Puzzle Game


Presented below is the HTML5 source code for a puzzle game called Sliding Tile puzzle or Mystic Square puzzle. Numbers 1 to 15 are jumbled in a 4x4 board. You have to arrange the numbers in order by moving the blank tile or magic square.
At the bottom of the board, you can see images in shuffled position. With each move on the board, the images will get re-aligned. Once the puzzle is solved, you can see the complete picture in the Canvas Area.
HTML5's Drag And Drop, Offline Storage, Canvas features are used. It is tested on Chrome 12.0 and Firefox 5.0 and NOT compatible with mobile devices.

Screen Shot:



HTML Code
<!DOCTYPE HTML>
<html manifest="cache.manifest">
<head>

<link rel=StyleSheet href="slidetile.css" TYPE="text/css">

<script src="jquery-1.6.2.min.js"></script>
<script src="slidetile.js"></script>
</head>
<body onload="initialize();">

<div id="row1" class="row">
<div id="1" class="tile" draggable="true"></div>
<div id="2" class="tile" draggable="true"></div>
<div id="3" class="tile" draggable="true"></div>
<div id="4" class="tile" draggable="true"></div>
</div>

<div id="row2" class="row">
<div id="5" class="tile" draggable="true"></div>
<div id="6" class="tile" draggable="true"></div>
<div id="7" class="tile" draggable="true"></div>
<div id="8" class="tile" draggable="true"></div>
</div>

<div id="row3" class="row">
<div id="9" class="tile" draggable="true"></div>
<div id="10" class="tile" draggable="true"></div>
<div id="11" class="tile" draggable="true"></div>
<div id="12" class="tile" draggable="true"></div>
</div>

<div id="row4" class="row">
<div id="13" class="tile" draggable="true"></div>
<div id="14" class="tile" draggable="true"></div>
<div id="15" class="tile" draggable="true"></div>
<div id="16" class="tile" draggable="true"></div>
</div>

<div id="moveStatus" class="row">
<div id="status">Ready to start?</div>
</div>

<canvas id="myCanvas" width="200" height="200" class="canvas">
</canvas>

<div id="buttons" class="row">
<input type="button" id="newGameButton" class="button" value="New"
onclick="clearStorage();initialize();"></input> <input type="button"
id="saveGameButton" class="button" value="Save"></input>
</div>

<div id="rules" class="rules">
<div id="rulesInfo" class="infoTitle">
<strong>Rules:</strong>
</div>
<div class="row">1. Arrange the numbers on the board from 1 to
15.</div>
<div class="row">2. Move the tiles around by moving only the
blank tile.</div>
<div class="row">3. The blank tile can be swapped only with the
adjacent tiles.</div>
<div class="row">4. Drag and Drop the tiles using the mouse.
Images are not draggable.</div>

<div class="infoTitle">
<strong>About:</strong>
</div>
<div class="row" id="AboutInfo">Sliding tile puzzle is also called Gem Puzzle or Mystic Square puzzle. If you can solve within 80 moves,well, you are lucky. The algorithm is complex to solve and sometimes impossible. Wish you patience and good luck. </div>

<div class="infoTitle">
<strong>Note:</strong>
</div>
<div class="row" id="NoteInfo">This version of game is NOT compatible with mobile. Offline caching enabled for modern browsers. Tested for Chrome 12.0 and Firefox 5.0</div>

<div class="infoTitle">
<strong>Best Finish:</strong>
</div>
<div class="row" id="bestMove"></div>
</div>

<div class="flashMessage" id="flashMessage"></div>

</body>
</html>


CSS:
.button {
color: white;
padding: 5px 20px;
text-shadow: 1px 1px 0 #145982;
font-family: Arial, Helvetica, sans-serif;
font-size: 15px;
font-weight: bold;
text-align: center;
border: 1px solid #60b4e5;
margin-right: 20px;
margin-top: 20px;
float: left;
position: relative;
right: -35%;
width: 100px;

/*
CSS3 gradients for webkit and mozilla browsers fallback color for the rest:
*/
background-color: #59aada;
background: -moz-linear-gradient(left center, rgb(200, 0, 0),
rgb(79, 79, 79), rgb(21, 21, 21) );
background: -webkit-gradient(linear, left top, right top, color-stop(0, rgb(200, 0,
0) ), color-stop(0.50, rgb(79, 79, 79) ),
color-stop(1, rgb(21, 21, 21) ) ); to (#FFA4E6) );
box-shadow: 3px 3px 3px #000000;
-moz-box-shadow: 3px 3px 3px #000000;
-webkit-box-shadow: 3px 3px 3px #000000;
border: 1px solid #F902B6;
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
background-color: #59aada
}


.button:hover { /* Lighter gradients for the hover effect */
text-decoration: none;
background-color: #F902B6;
background-image: -moz-linear-gradient(#6bbbe9, #57a5d4);
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#6bbbe9),
to(#57a5d4) );
box-shadow: 3px 3px 3px #333;
-moz-box-shadow: 3px 3px 3px #333;
-webkit-box-shadow: 3px 3px 3px #333;
}
/* Prevent the text contents of draggable elements from being selectable. */
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
}

.row {
width: 100 %;
clear: both;
}

.infoTitle {
width: 100 %;
clear: both;
margin-top: 20px;
text-shadow: 1px 0px 0 #145982;
font-family: Arial, Helvetica, sans-serif;
font-size: 15px;
font-weight: bold;
}

.rules {
position: absolute;
top: 0;
right: 0;
width: 200px;
text-align: left;
color: #800000;
font-size: small;
font-family: Arial, Helvetica, sans-serif;
}

.flashMessage {
position: absolute;
top: 50px;
left: 50px;
width: 220px;
height: 60px;
text-align: left;
margin-right: 10px;
margin-leftt: 15px;
line-height: 1.5em;
color: #fff;
font-size: large;
font-family: Arial, Helvetica, sans-serif;
clear: both;
margin-top: 20px;
background: -moz-linear-gradient(left center, rgb(100, 0, 0),
rgb(179, 79, 79), rgb(121, 21, 21) );
background: -webkit-gradient(linear, left top, right top, color-stop(0, rgb(100, 0,
0) ), color-stop(0.50, rgb(179, 79, 79) ),
color-stop(1, rgb(121, 21, 21) ) );
}

#moveStatus {
clear: both;
float: left;
position: relative;
right: -35%;
text-align: left;
margin-top: 20px;
width: 215px;
background: -moz-linear-gradient(left center, rgb(200, 0, 0),
rgb(79, 79, 79), rgb(21, 21, 21) );
background: -webkit-gradient(linear, left top, right top, color-stop(0, rgb(200, 0,
0) ), color-stop(0.50, rgb(79, 79, 79) ),
color-stop(1, rgb(21, 21, 21) ) );
color: #fff;
text-shadow: 1px 1px 0 #145982;
font-family: Arial, Helvetica, sans-serif;
font-size: 15px;
font-weight: bold;
box-shadow: 3px 3px 3px #000000;
-moz-box-shadow: 3px 3px 3px #000000;
-webkit-box-shadow: 3px 3px 3px #000000;
}

.tile {
height: 50px;
width: 50px;
float: left;
position: relative;
right: -35%;
border: 2px solid #666666;
background-color: #ccc;
margin-right: 1px;
line-height: 2em;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 3px #000;
box-shadow: inset 0 0 3px #000;
text-align: center;
cursor: move;
background: -moz-linear-gradient(left center, rgb(0, 0, 0),
rgb(79, 79, 79), rgb(21, 21, 21) );
background: -webkit-gradient(linear, left top, right top, color-stop(0, rgb(0, 0, 0)
), color-stop(0.50, rgb(79, 79, 79) ), color-stop(1, rgb(21, 21, 21) )
);
color: #fff;
font-size: x-large;
}

.canvas {
clear: both;
height: 200px;
width: 215px;
float: left;
position: relative;
right: -35%;
border: 2px solid #666666;
background-color: #ccc;
margin-right: 1px;
margin-top: 10px;
line-height: 2em;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 3px #000;
box-shadow: inset 0 0 3px #000;
background: -moz-linear-gradient(left center, rgb(0, 0, 0),
rgb(79, 79, 79), rgb(21, 21, 21) );
background: -webkit-gradient(linear, left top, right top, color-stop(0, rgb(0, 0, 0)
), color-stop(0.50, rgb(79, 79, 79) ), color-stop(1, rgb(21, 21, 21) )
);
color: #fff;
font-size: x-large;
height: 200px;
}

.over {
border: 2px dashed #000;
}

Javascript Code:
// Global Variable
var myarray = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
"12", "13", "14", "15", "" ];
var gameStatus = 0;
var moveCount = 0;
var positionDifference = 0;

// If you have 10 number of 200x200 images, use 9.
var imageNumber = Math.floor(Math.random()*9);
var sourceDiv = null;
var bestMove;
var bestTime;

$(document)
.ready(

function () {

Element.prototype.hasClassName = function(name) {
return new RegExp("(?:^|\\s+)" + name
+ "(?:\\s+|$)").test(this.className);
};

Element.prototype.addClassName = function(name) {
if (!this.hasClassName(name)) {
this.className = this.className ? [
this.className, name ].join(' ') : name;
}
};

Element.prototype.removeClassName = function(name) {
if (this.hasClassName(name)) {
var c = this.className;
this.className = c.replace(
new RegExp("(?:^|\\s+)" + name
+ "(?:\\s+|$)", "g"), "");
}
};



function handleDragStart(e) {
// Target (this) element is the source node.
sourceDiv = this;
this.style.opacity = '0.7';
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}

function handleDragEnter(e) {
// this / e.target is the current hover target.
this.addClassName('over');
}

function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to
// drop.
}

e.dataTransfer.dropEffect = 'move'; // See the
// section on
// the
// DataTransfer
// object.
this.addClassName('over');
return false;
}

function handleDragLeave(e) {
this.removeClassName('over'); // this / e.target
// is previous
// target element.
}

function handleDrop(e) {
// this/e.target is current target element.
this.style.opacity = '1.0';
sourceDiv.style.opacity = '1.0';

if (e.stopPropagation) {
e.stopPropagation(); // Stops some browsers
// from redirecting.
}

// Stop Game when it is over
if (!gameStatus)
{

// Don't do anything if dropping the same column
// we're dragging.
if (sourceDiv != this) {

// Swap boxes only if one of them is BLANK
if (sourceDiv.innerHTML == ""
|| this.innerHTML == "") {

// Restrict box movements to one level (up,
// down, left, right)
positionDifference = Math.abs(sourceDiv.id
- this.id);

if (positionDifference == 1
|| positionDifference == 4) {

if (positionDifference == 4 || (!((sourceDiv.id%4==0 && this.id%4==1) || (sourceDiv.id%4==1 && this.id%4==0))))
{
// Set the source column's HTML to the
// HTML of the column we dropped on.
sourceDiv.innerHTML = this.innerHTML;
if (e.dataTransfer.getData('text/html') == null) {
this.innerHTML = "";
} else {
this.innerHTML = e.dataTransfer
.getData('text/html');
}

moveCount = moveCount + 1;

// Check Game Status
gameStatus = checkGameStatus();

if (gameStatus) {
if (bestMove == null || (bestMove > moveCount))
{
bestMove = moveCount;
localStorage.setItem('BEST_MOVE',bestMove);
document.getElementById("bestMove").innerHTML = bestMove + " moves";
}
document.getElementById("status").innerHTML = "You are Awesome!!. You took " + moveCount + " moves";
document.getElementById("flashMessage").innerHTML = "Game Over";
$('#flashMessage').slideDown('1000');
$('#flashMessage').delay('3000');
$('#flashMessage').slideUp('1000');
} else {
document.getElementById("status").innerHTML = "Number Of Moves :: "
+ moveCount;
}

drawCanvas();

}
else {
displayNotification();
}
}
else {
displayNotification();
}
} else {
displayNotification();
}

}
}
return false;
}

function handleDragEnd(e) {
// this/e.target is the source node.
var cols = document.querySelectorAll('.tile');
[].forEach.call(cols, function(col) {
col.removeClassName('over');
});

toggleFlashMessage();

}


$('#saveGameButton').click(function() {

if (!gameStatus)
{
for ( var i = 0; i < 16; i++) { myarray[i] = document.getElementById(i + 1).innerHTML; } localStorage.setItem('MY_ARRAY', myarray.toString()); localStorage.setItem('MOVE_COUNT', moveCount); localStorage.setItem('IMAGE_NUMBER',imageNumber); localStorage.setItem('GAME_STATUS',gameStatus); console.log("Move Count" +localStorage.getItem('MOVE_COUNT')); console.log("Image Number" +localStorage.getItem('IMAGE_NUMBER')); document.getElementById("flashMessage").innerHTML = "Game saved successfully"; $('#flashMessage').slideDown('1000'); $('#flashMessage').delay('1000'); $('#flashMessage').slideUp('1000'); } }); var cols = document.querySelectorAll('.tile'); [].forEach.call(cols, function(col) { col.addEventListener('dragstart', handleDragStart, false); col.addEventListener('dragenter', handleDragEnter, false); col.addEventListener('dragover', handleDragOver, false); col.addEventListener('dragleave', handleDragLeave, false); col.addEventListener('drop', handleDrop, false); col.addEventListener('dragend', handleDragEnd, false); }); }); function toggleFlashMessage() { $('#flashMessage').slideUp('1000'); } function initialize() { $('#notificationMessage').hide(); $('#flashMessage').hide(); if ((imageNumber = localStorage.getItem('IMAGE_NUMBER')) == null) { imageNumber = Math.floor(Math.random()*5); } if ((moveCount = localStorage.getItem('MOVE_COUNT')) == null) { moveCount = 0; document.getElementById("status").innerHTML = "Ready to start?"; } else { moveCount = parseInt(moveCount); if (moveCount != 0) { document.getElementById("status").innerHTML = "Number Of Moves :: " + moveCount; } else { document.getElementById("status").innerHTML = "Ready to start?"; } } if ((gameStatus = localStorage.getItem('GAME_STATUS')) == null) { gameStatus = 0; } else { gameStatus = parseInt(gameStatus); } if ((bestMove = localStorage.getItem('BEST_MOVE')) == null) { document.getElementById("bestMove").innerHTML = ""; } else { document.getElementById("bestMove").innerHTML = bestMove + " moves"; } if (localStorage.getItem('MY_ARRAY') == null) { // Shuffle Array Contents myarray.sort(function() { return 0.5 - Math.random(); }); } else { myarray = localStorage.getItem('MY_ARRAY').split(','); document.getElementById("flashMessage").innerHTML = "Game restored from previous session"; $('#flashMessage').slideDown('1000'); $('#flashMessage').delay('1000'); $('#flashMessage').slideUp('1000'); } // Populate Boxes with Numbers for ( var i = 0; i < myarray.length; i++) { document.getElementById(i + 1).innerHTML = myarray[i]; } drawCanvas(); } function clearStorage() { localStorage.removeItem('MOVE_COUNT'); localStorage.removeItem('MY_ARRAY'); localStorage.removeItem('IMAGE_NUMBER'); localStorage.removeItem('GAME_STATUS'); } function saveGame() { for ( var i = 0; i < 16; i++) { myarray[i] = document.getElementById(i + 1).innerHTML; } localStorage.setItem('MY_ARRAY', myarray.toString()); localStorage.setItem('MOVE_COUNT', moveCount); localStorage.setItem('IMAGE_NUMBER',imageNumber); localStorage.setItem('GAME_STATUS',gameStatus); console.log("Move Count" +localStorage.getItem('MOVE_COUNT')); console.log("Image Number" +localStorage.getItem('IMAGE_NUMBER')); } function checkGameStatus() { for ( var i = 1; i < myarray.length; i++) { var currentElement = document.getElementById(i); if (currentElement.innerHTML != i) { return 0; } } return 1; } function displayNotification() { document.getElementById("flashMessage").innerHTML = "Move not allowed"; $('#flashMessage').fadeIn('slow'); $('#flashMessage').delay(2000); $('#flashMessage').fadeOut('slow'); } function drawCanvas() { var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); canvas.width = 200; canvas.height = 200; context.clearRect(0,0,200,200); var imageObj = new Image(); imageObj.onload = function(){ // draw cropped image var x = 0; var y = 0; var x1 = 0; var y1 = 0; var width = 50; var height = 50; var element; var elementValue; var elementId; for (var i=0;i<16;i++) { element = document.getElementById(i+1); elementValue = element.innerHTML; elementId = element.id; // Handle blank box if (elementValue == null || elementValue == "") { elementValue = "16"; } x = ((elementValue-1)%4) * 50; y = parseInt(((elementValue-1)/4)) * 50; x1 = ((elementId-1)%4) * 50; y1 = parseInt(((elementId-1)/4)) * 50; context.drawImage(imageObj, x, y, width, height, x1, y1, width, height); } }; imageObj.src = imageNumber+".jpg"; }



Instructions: Create .html, .css, .js files with the above code. Download JQuery 1.6.2 to the same folder. Add 10 (jpg) images of exact size 200x200px. Have all the 14 files in the same folder.


Reference: http://www.html5rocks.com/en/tutorials/dnd/basics/

Saturday, December 18, 2010

HTML5 Editors

HTML5
When something new comes along, the old has to give away. Do you believe so? HTML5 is evolving and is already well supported by most of the smart phones and leading browsers. Ipad/IPhone enabled websites are all powered with HTML5. With increasing usage of Smart Phones, there is a compulsory need for every website to have a mobile friendly version. With the promising features like Offline support, enhanced multimedia, graphics, interactive Drag & Drop and advanced UI forms, HTML5 will eventually become the standard of the web.



Editors for HTML5:
The specification for this major version of HTML is not finalized yet. Probably because of this reason, there are not much HTML5 editors available for developers. Till HTML4, W3C would finalize the specification first and then the browsers and editors would start to implement them. With Google and Apple heavily backing up HTML5, browsers have started implementing the draft version of HTML5 and kept moving forward on their browse race. Developers are left with only a few options to choose their favorite editor for HTML5. The editors available on markets like Dreamweaver CS5, Aloha Editor (WYSIWYG based) are licensed and heavily priced. Web developers are forced to use Text Editors like Textpad, Editplus, Notepad++ or Eclipse IDE without any additional help for quick reference.



Eclipse & HTML5:
With the support of third party plug-in like Aptana Studio 3.0 beta, Eclipse (Version 3.4 or above) is able to provide HTML5 support for developers to some extent. The good thing about this plug-in is that, it supports code assistant for JQuery (Version 1.4.2). For web developers, this is a great boon, I would bet. The code assistant tool recognizes HTML4 tags well but eclipse will flag a compilation error for new HTML5 tags. Even the latest version of Eclipse 3.6 does not have a built in support of HTML5. Aptana has little support for CSS3 and built in Preview option for HTML files.. To install the plugin,


Netbeans & HTML5:
Netbeans.org has recently released their Beta version of IDE 7.0 with HTML5, Javascript, CSS, AJAX, JSON and JavaFX formatting support. The interesting feature about this release is that the code assistant tool is able to identify most of the HTML5 tags supported by leading browsers like Chrome, Firefox, Opera and Safari. The code assistant tool briefs the HTML5 tag syntax, attributes and the browsers that currently support the tag. It also shows example code with appropriate syntax and suggestions. The code assistant works out well for Javascript and CSS files as well but there is no support for JQuery. It also has an option to view the HTML5 specification (draft specification as of September 2010) in a separate browser. There is no need to update or install plug-ins for HTML5 support on it.












It would be great if we have the power of Aptana on Netbeans. But they themselves are competitors on Ruby and PHP front. We have to wait for Aptana Studio to fully support HTML5 or Netbeans to support JQuery. When something new comes along, it doesn’t mean that the old has to fail. They can live in harmony with one another and generate greater results. Agree?