Click here to Skip to main content
15,878,852 members
Articles / Web Development / HTML
Article

Jigsaw Puzzle Game using AJAX Drag and Drop

Rate me:
Please Sign up or sign in to vote.
4.74/5 (18 votes)
20 Apr 2008CPOL5 min read 149.3K   4K   54   38
A jigsaw puzzle game using AJAX drag and drop (ASP.NET 2.0 AJAX Futures November CTP).

Screenshot.jpg

Introduction

This tutorial is intended to explain quickly how to implement drag and drop using the ASP.NET 2.0 AJAX Futures November CTP. To explain this technology, I've created a simple project with a custom AJAX control that implements a jigsaw puzzle game.

Background

When I started to learn the new ASP.NET AJAX framework, I asked my company to buy a book, and I chose an amazing book:

In this book, I found a chapter that explains how to use the PreviewDragDrop to implement drag and drop on web. I used this chapter and other information from Internet (Google) to create my AJAX control.

The ASP.NET AJAX Framework

The basic idea within the ASP.NET AJAX Framework is to have a possibility to use object-oriented programming in JavaScript (simulated OOP) and make it similar to C#. Most C# features are available in JavaScript: namespace, class, interface, enum etc. Besides the OOP features is available the possibility to implement visual custom controls (client side controls) that extend the HTML elements' functionalities.

Basically, we have two types of controls (visual controls):

  • Behavior (extending Sys.UI.Behavior)
  • Control (extending Sys.UI.Control)

The difference is just logic, but whilst generally Sys.UI.Behavior is used to extend HTML element behaviors for different types of elements, Sys.UI.Control is used to extend HTML element behaviors for a single type of element.

For example, if we want to implement a behavior that shows an alert on the click event, we can create a class that extends Sys.UI.Behavior, and then we can use this code with several HTML element types: DIV, SPAN, INPUT etc.

C#
//Namespace declaration
Type.registerNamespace("MyNamespace");

//Constructor
MyNamespace.MyBehavior = function(element)
{
   MyNamespace.MyBehavior.initializeBase(this, [element]);
}

MyNamespace.MyBehavior.prototype =
{
   initialize : function()
   {
     // Add event handler on click
      // Parameters: 
      // 1) The HTML element
      // 2) Event name without "on" ("onclick"="click")
      // 3) Control instance
      $addHandlers(this.get_element(), { "click" : this._onClick }, this);
   },

   dispose : function()
   {
      // Remove all events handlers for the current HTML element
      $clearHandlers(this.get_element());
   },

   // Event handler onclick
   _onClick : function(evt)
   {
      // Show the id of current HTML Element
      alert(this.get_id());
   }
};

// Register class
MyNamespace.MyBehavior.registerClass("MyNamespace.MyBehavior", Sys.UI.Behavior);

When we need to use it within our page, we can just write the following code:

JavaScript
// Create an instance of our Behavior
// and attach it to HTML element with id 'elementId'
// Parameters:
// 1) Class name with namespace
// 2) Properties in JSON format
// 3) Events in JSON format
// 4) References in JSON format
// 5) HMTL element
$create(MyNamespace.MyBehavior, {}, {}, {}, $get('elementId'));

If we need to implement behaviors for an element type or we need to implement a complex control (a visual control composed of different elements), we need to extend Sys.UI.Control.

AJAX Enabled Server Control

Generally, control are not manually created using $create in JavaScript, but automatically generated by an ASP.NET Server Control (server side version of the control). This way, we can implement a server control and have design-time support within Visual Studio. When we want to create a AJAX enabled Server Control, we need to extend ScriptControl (instead of WebControl). This base class contains all methods useful to make a relation between the client control (JavaScript) and the server control (.NET).

In ScriptControl, we need to override two methods:

  • GetScriptDescriptors: pass the name of the JavaScript class and the properties to the client control.
  • GetScriptReferences: pass the scripts used by our client control. (The ScriptManager automatically loads these scripts during page load).
C#
protected override IEnumerable<System.Web.UI.ScriptDescriptor> GetScriptDescriptors()
{
    if (!string.IsNullOrEmpty(this.Filename))
    {
        ScriptControlDescriptor descriptor = new 
          ScriptControlDescriptor("JigsawPuzzleGameControl.PuzzleGameAjax", 
          this.ClientID);
        descriptor.AddProperty("nRows", this.NRows);
        descriptor.AddProperty("nColumns", this.NColumns);

        yield return descriptor;
    }
}
         
protected override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
{
    if (!string.IsNullOrEmpty(this.Filename))
    {
        List<ScriptReference> scripts = new List<ScriptReference>();

        ScriptReference scriptReference1 = new ScriptReference("PreviewScript.js", 
                                           "Microsoft.Web.Preview");
        scripts.Add(scriptReference1);

        ScriptReference scriptReference2 = new ScriptReference("PreviewDragDrop.js", 
                                           "Microsoft.Web.Preview");
        scripts.Add(scriptReference2);

        ScriptReference scriptReference3 = new ScriptReference();
        scriptReference3.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                                "JigsawPuzzleGameControl.Resources.Helpers.js");
        scripts.Add(scriptReference3);

        ScriptReference scriptReference4 = new ScriptReference();
        scriptReference4.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                                "JigsawPuzzleGameControl.Resources.PuzzleGameAjax.js");
        scripts.Add(scriptReference4);

        return scripts;
    }
    else
    {
        return new List<ScriptReference>();
    }
}

Drag and Drop

To implement drag and drop in our control, we need to implement two interfaces within two client controls:

  • Client control that extends Sys.Preview.UI.IDropTarget: This control represents the drop area
  • Client control that extends Sys.Preview.UI.IDragSource: This control represents the drag element

In Sys.Preview.UI.IDropTarget, we need to implements the following methods:

  • get_dropTargetElement: return the HTML element of the drop area
  • canDrop: check if drop is available for a particular drag element
  • drop: execute the drop action
  • onDragEnterTarget: normally used with onDragLeaveTarget to implement the visual effect
  • onDragLeaveTarget: normally used with onDragEnterTarget to implement the visual effect

We also need to add an event handler within the method Initialize for the MouseDown event and then call Sys.Preview.UI.DragDropManager.startDragDrop:

JavaScript
initialize : function()
{
    JigsawPuzzleGameControl.DragPuzzleGameAjaxElement.callBaseMethod(this, 
                                                            "initialize");
    $addHandlers(this.get_element(), 
      { "mousedown" : this._onMouseDown }, this);
},

_onMouseDown : function(evt)
{
    window._event = evt;
    evt.preventDefault();
    
    Sys.Preview.UI.DragDropManager.startDragDrop(this, 
                            this.get_element(), null);
},

In Sys.Preview.UI.IDragSource, we need to implement the following methods:

  • get_dragDataType: return the type of the drag element (the string used in canDrop to check if the drag item is compatible with the drop area)
  • getDragData: return data that drags the item and passes to the drop area (drop method)
  • get_dragMode: return if the drag operation is Move or Copy
  • onDragStart: is called when the drag operation starts
  • onDragEnd: is called when the drag operation ends
  • onDrag: is called when the drag operation is completed

We also need to register and unregister the client component as the drop area:

JavaScript
initialize : function()
{
    JigsawPuzzleGameControl.DropPuzzleGameAjaxElement.callBaseMethod(this, "initialize");
    Sys.Preview.UI.DragDropManager.registerDropTarget(this);
},

dispose : function()
{
    Sys.Preview.UI.DragDropManager.unregisterDropTarget(this);
    JigsawPuzzleGameControl.DropPuzzleGameAjaxElement.callBaseMethod(this, "dispose");
},

The Game

The project is divided into two projects:

  1. A web site containing an example of using the control
  2. A library project containing the control

Within the library project is a class called PuzzleGameAjax that extends ScriptControl (the base class for all custom controls in AJAX). This class is the server side code of my control.

On the client side, we have three JavaScript classes:

  • PuzzleGameAjax (contains code to implement the game)
  • DropPuzzleGameAjaxElement (contains code to implement a drop area)
  • DragPuzzleGameAjaxElement (contains code to implement a drag area)

DropPuzzleGameAjaxElement implements the Sys.Preview.UI.IDropTarget interface and DragPuzzleGameAjaxElement implements the Sys.Preview.UI.IDragSource interface. These two interfaces are used by the AJAX framework to handle the drag and drop in a generic way.

Points of Interest

AJAX ASP.NET is a very good technology, and I'm currently working with it to implement a very complex behavior to improve the user experience. The drag and drop feature is absolutely the most user friendly feature, and it makes a software very intuitive to use. Normally, on web, this feature takes a lot of JavaScript code, but with PreviewDragDrop, everything is easy.

History

  • 30 March 2008 - First release (very poor to be honest, but I wanted to make it better!).
  • 06 April 2008 - I made the article more complete.
  • 08 April 2008 - Fixed a problem within the solution.
  • 09 April 2008 - Now works with Visual Studio 2005/2008 (Express Edition included).
  • 22 April 2008 - Added online demo.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) sparesFinder
Italy Italy
I'm an Italian Software Developer from about 15 years.
I worked a long time in south Italy (where I was born) and after 2 years in Milan and an year in UK, I'm working remotely from Italy as Senior ASP.NET C# Developer using ASP.NET Ajax technology for a UK company.

Check out my personal blog:
http://techcookies.net/

and my first Android game (Fifteen Puzzle X):
https://play.google.com/store/apps/details?id=it.megasoft78.fifteenpuzzlex

Comments and Discussions

 
Questionhow to handle when game is completed? Pin
lalit bisht10-Oct-11 2:26
lalit bisht10-Oct-11 2:26 
AnswerRe: how to handle when game is completed? Pin
Ferreri Gabriele (Megasoft78)10-Oct-11 2:53
Ferreri Gabriele (Megasoft78)10-Oct-11 2:53 
QuestionRe: how to handle when game is completed? Pin
tariqbaig20-Aug-23 6:30
tariqbaig20-Aug-23 6:30 
GeneralMouse position inside drop event Pin
stels8624-Sep-10 0:13
stels8624-Sep-10 0:13 
GeneralRe: Mouse position inside drop event Pin
Ferreri Gabriele (Megasoft78)24-Sep-10 2:11
Ferreri Gabriele (Megasoft78)24-Sep-10 2:11 
QuestionHow to drag image Pin
manisha yadav13-Apr-10 4:16
manisha yadav13-Apr-10 4:16 
AnswerRe: How to drag image Pin
Ferreri Gabriele (Megasoft78)13-Apr-10 10:41
Ferreri Gabriele (Megasoft78)13-Apr-10 10:41 
GeneralThis is Excellent! Thanks for posting this. Pin
stever(398)17-Mar-10 15:19
stever(398)17-Mar-10 15:19 
QuestionHow to use it on a website? Pin
imgr8839-Sep-09 17:37
imgr8839-Sep-09 17:37 
AnswerRe: How to use it on a website? Pin
Ferreri Gabriele (Megasoft78)9-Sep-09 20:27
Ferreri Gabriele (Megasoft78)9-Sep-09 20:27 
GeneralRe: How to use it on a website? Pin
imgr88310-Sep-09 12:36
imgr88310-Sep-09 12:36 
Questionhow to use a unique image Pin
yasi2211-Aug-09 8:26
yasi2211-Aug-09 8:26 
AnswerRe: how to use a unique image Pin
Ferreri Gabriele (Megasoft78)11-Aug-09 20:10
Ferreri Gabriele (Megasoft78)11-Aug-09 20:10 
Generalthis.get_enableControl() Pin
Patch7913-Nov-08 22:55
Patch7913-Nov-08 22:55 
GeneralRe: this.get_enableControl() Pin
Ferreri Gabriele (Megasoft78)14-Nov-08 1:10
Ferreri Gabriele (Megasoft78)14-Nov-08 1:10 
Generalnot working Pin
sp4ceman28-Aug-08 21:27
sp4ceman28-Aug-08 21:27 
GeneralRe: not working Pin
Ferreri Gabriele (Megasoft78)30-Aug-08 3:09
Ferreri Gabriele (Megasoft78)30-Aug-08 3:09 
GeneralRe: not working Pin
srkanna2-Sep-08 0:13
srkanna2-Sep-08 0:13 
GeneralonDrag: Pin
masko29-Jun-08 17:02
masko29-Jun-08 17:02 
AnswerRe: onDrag: Pin
Ferreri Gabriele (Megasoft78)30-Jun-08 2:02
Ferreri Gabriele (Megasoft78)30-Jun-08 2:02 
GeneralRe: onDrag: Pin
masko30-Jun-08 11:33
masko30-Jun-08 11:33 
GeneralRe: onDrag: Pin
Ferreri Gabriele (Megasoft78)1-Jul-08 9:59
Ferreri Gabriele (Megasoft78)1-Jul-08 9:59 
GeneralGood one Pin
Alexey.Kucherenko21-Apr-08 20:41
Alexey.Kucherenko21-Apr-08 20:41 
GeneralRe: Good one Pin
Ferreri Gabriele (Megasoft78)22-Apr-08 11:59
Ferreri Gabriele (Megasoft78)22-Apr-08 11:59 
GeneralRe: Good one Pin
Alexey.Kucherenko22-Apr-08 20:41
Alexey.Kucherenko22-Apr-08 20:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.