AS3 example Drag and Drop

From EduTech Wiki
Jump to: navigation, search

Draft


1 Introduction

This example belongs to the AS3 Tutorials Novice and is part of our Actionscript 3 tutorial series.

You will learn how to implement simple drag and drop applications.

2 ActionScript Program

Note: For now, the drag and drop works when you click anywhere on the tile but the letter itself. We keep things simple and won't provide a workaround.

package {

  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.text.TextField;  

  public class AnagramDragDrop extends Sprite { 
    private var dragTarget:Sprite;

    public function AnagramDragDrop() {
      var board:Sprite = new Sprite();
      var letters:Array = new Array("d","i","r","t","y","r","o","o","m")
      var l:String;
      var xPos:uint = 50
      var yPos:uint = 100
      for each (l in letters) {
        var tile:Sprite = new Sprite();
        tile = createLetterTile(l as String) // size, color yellow
        tile.x = xPos;
        tile.y = yPos;
        xPos += 50;
        board.addChild(tile);
        tile.addEventListener(MouseEvent.MOUSE_DOWN, dragStarter, false);
        tile.addEventListener(MouseEvent.MOUSE_UP, dragStopper);
      }
      addChild(board)

      var instructions:TextField = new TextField();
      instructions.text = "Re-order the letters to form another word."
      instructions.x = 20
      instructions.y = 20
      instructions.width = 300;
      addChild(instructions)

    }

    private function dragStarter(event:MouseEvent):void {
      if (event.target is Sprite) {
        dragTarget = event.target as Sprite;
        dragTarget.startDrag();
      }
    }

    private function dragStopper(event:MouseEvent):void {
      dragTarget.stopDrag();
    }
        
    private function createLetterTile(txt:String):Sprite {
      var s:Sprite = new Sprite();
      var letter:TextField = new TextField();
      var tileBackColor:uint = 0xDBD9A6;
      var tileShadowColor:uint = 0x676420;
      var tileBorderColor:uint = 0x000000;
      
      s.graphics.beginFill(tileShadowColor);
      s.graphics.drawRect(-2, 2, 40, 40);
      s.graphics.endFill();
      s.graphics.beginFill(tileBackColor);
      s.graphics.drawRect(0, 0, 40, 40);
      s.graphics.endFill();
      s.graphics.lineStyle(1, tileBorderColor, 100);
      s.graphics.drawRect(0, 0, 40, 40);
    
      letter.text = txt
      letter.selectable = false;
      letter.mouseEnabled = false;
      letter.x = 14
      letter.y = 14
      letter.width = 14
      letter.height = 16
      s.addChild(letter)
 
      return s;
    }
  }
}

3 Walkthrough

---

package {

  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.text.TextField;  

  public class AnagramDragDrop extends Sprite { 

Package declaration, import statements, class definition.

---

    private var dragTarget:Sprite;

Declaration of all variables that will be used in more than one functions. We store in a variable information about the sprite object that was the target of the drag. When the mouse gets up, we want the drag action to stop, whether the mouse is over that object or not.

---

    public function AnagramDragDrop() {
      var board:Sprite = new Sprite();
      var letters:Array = new Array("d","i","r","t","y","r","o","o","m")
      var l:String;
      var xPos:uint = 50
      var yPos:uint = 100
      for each (l in letters) {
        var tile:Sprite = new Sprite();
        tile = createLetterTile(l as String) // size, color yellow
        tile.x = xPos;
        tile.y = yPos;
        xPos += 50;
        board.addChild(tile);
        tile.addEventListener(MouseEvent.MOUSE_DOWN, dragStarter);
        tile.addEventListener(MouseEvent.MOUSE_UP, dragStopper);
      }
      addChild(board)

      var instructions:TextField = new TextField();
      instructions.text = "Re-order the letters to form another word."
      instructions.x = 20
      instructions.y = 20
      instructions.width = 300;
      addChild(instructions)

    }

Rather than draw a single object on the screen to be dragged and dropped, we spice things up a bit. We will draw a number of tiles letters.

It would be quite tedious to have something of the like:

 var tile1:Sprite = createLetterTile("d")
 tile1.x = 50
 tile1.y = 50
 addChild(tile1)

 var tile2:Sprite = createLetterTile("i")
 tile2.x = 50+30
 tile2.y = 50
 addChild(tile2)

 var tile3:Sprite = createLetterTile("r")
 tile3.x = 50+(30*2)
 tile3.y = 50
 addChild(tile3)

What if we were to decide to change to offset all times by 10 pixels? What if we wanted to change the anagram to appear on the screen. This would be a very slow, tedious process, and error prone process.

We opt for a more efficient of coding this. We put the letters in an array and we use Flash built in for each (value in array) to rapidly loop across the items with in this array.

We also define a point of origin (x=50, y=100), where the first tile will appear. Within the for each loop, we add 50 pixels to the x position, causing the tiles to appear one on the right of the other.

Because all tiles are to look the same except for the letter in the middle, we delegate the creation of each tile to a function. This way, we are free to change the look and feel of a tile later on.

For convenience reasons, we create a board object to store all sprites. This way, we can treat the tiles as component and position it on its own.

Finally, we add two mouseEvent listener, one to trigger a function whenever a mousedown event occurs, another one to trigger another function whenever a mouseup event occurs. They will be used to trigger start drag and stop drag actions, respectively.

---

    private function dragStarter(event:MouseEvent):void {
      dragTarget = event.target as Sprite;
      dragTarget.startDrag();
    }
    private function dragStopper(event:MouseEvent):void {
      dragTarget.stopDrag();
    }

whenever a mousedown event occurs anywhere on the interface, the event is forwarded to the function specified as parameter to the addListener function. In this program, it is the dragStarter function.

The function is called and the information about the event that toke place passed as a parameter to this function. We therefore create a parameter event, of type MouseEvent, to be able to access information about the event from within our function.

Different information become available, the target, the mouse location and others. These information vary slightly from mouseevent to mouseevent. Detailed information about event information can be obtained on the MouseEvent entry in the Actionscript Language Reference.

Here, we are only interested in the target property. This holds information on the on-screen object that was the target of the event. We store this information in a variable because we want a mouse up action to interrupt the dragging of the object on which a dragging action was initiated rather than the object currently under the mouse.

---

    private function createLetterTile(txt:String):Sprite {
      var s:Sprite = new Sprite();
      var letter:TextField = new TextField();
      var tileBackColor:uint = 0xDBD9A6;
      var tileShadowColor:uint = 0x676420;
      var tileBorderColor:uint = 0x000000;
      
      s.graphics.beginFill(tileShadowColor);
      s.graphics.drawRect(-2, 2, 40, 40);
      s.graphics.endFill();
      s.graphics.beginFill(tileBackColor);
      s.graphics.drawRect(0, 0, 40, 40);
      s.graphics.endFill();
      s.graphics.lineStyle(1, tileBorderColor, 100);
      s.graphics.drawRect(0, 0, 40, 40);
    
      letter.text = txt
      letter.selectable = false;
      letter.mouseEnabled = false;
      letter.x = 14
      letter.y = 14
      letter.width = 14
      letter.height = 16
      s.addChild(letter)
 
      return s;
    }

Function to create a given tile object. We create a tile, which is a sprite, draw a rectangle around it, and add a text field displays the letter on the tile. Setting the textField to be not selectable prevents the user from selecting the letter with the mouse. But the mouse events still recognize that there is a text field there unless we also set the text field to not be mouseEnabled. With mouseEnabled set to false, the user can grab any part of the tile to drag.

---

  }
}

closing the class definition and the package declaration.

---

4 Variants

4.1 Fridge Magnets

You could design a basic fridge magnet application the same way. The magnets can be moved by clicking on the green tab that appears in front of them and dragging the magnet around the screen.

Here is the code:

package {

   import flash.display.Sprite;
   import flash.events.Event;
   import flash.events.MouseEvent  
   import flash.text.TextField;  
   import flash.text.TextFieldAutoSize;
   import flash.text.TextFormat;
        
   public class FridgeMagnets extends Sprite { 
     private var dragTarget:Sprite;
 
     public function FridgeMagnets() {
       var board:Sprite = new Sprite();
       var words:Array = new Array("flash.","Sprite","display.","import")
       var w:String;
       var xPos:uint = 0
       var yPos:uint = 0
       for each (w in words) {
         var magnet:Sprite = createMagnet(w as String)
         magnet.y = yPos;
         magnet.x = xPos;
         xPos += magnet.width;

         board.addChild(magnet);
         magnet.addEventListener(MouseEvent.MOUSE_DOWN, dragStarter);
         magnet.addEventListener(MouseEvent.MOUSE_UP, dragStopper);
       }
       
       board.x = 20; board.y = 100;
       addChild(board)
     }
 
      private function dragStarter(event:MouseEvent):void {
        dragTarget = event.target as Sprite;
        dragTarget.startDrag();
      }
      private function dragStopper(event:MouseEvent):void {
        dragTarget.stopDrag();
      }
      
     private function createMagnet(txt:String):Sprite {
       var s:Sprite = new Sprite();
       var m:TextField = new TextField();
       var format:TextFormat = new TextFormat();
       m.selectable = false;
       m.mouseEnabled = false;
       m.autoSize = TextFieldAutoSize.LEFT;
       m.background = true;
       m.border = true;
       m.height=20;
       format.font = "Verdana";
       format.color = 0x000000;
       format.size = 14;
       m.defaultTextFormat = format;
       m.text = txt;
       
       s.graphics.beginFill(0x3E7D24)
       s.graphics.drawRect(-9,1,10,20)
       s.graphics.endFill()
       
       s.addChild(m)
       return s;
     }
   }
 }

Why not use this to set yourself some exercises to practice your ActionScript? You could mix words of a line like shown here.

5 Challenge

5.1 Drag lines and blocks of lines

Write a program that presents lines of text. The task is then to put the lines in the correct order. For extra difficulty, make it possible to have single lines of text as well as multilines.

When finished, why not use it to present programs like the ones above (if you don't allow for multiline blocks, shorter programs may be more convenient) in a somewhat shuffled order. Set yourself or your friends the task to put the lines back in a correct order.

5.2 Dominos

Write a smini-game game of dominos. Information about the game and the rules can be found on this page about Dominos puzzle and logic game. To keep things simple have a board where only horizontal dominos are used.