Flash as3 Drag and Drop

Fair Warning: This swf file plays sounds!!!

This tutorial will probably be unlike anything you've seen before on the subject of Flash drag-and-drop. It begins with the things you already know (startDrag and stopDrag), then it progresses into some things you maybe had never considered before (MOUSE_UP problems, the use of a "currentClip" variable, "snapping" to a screen location, etc). It discusses how to use the built-in hit testing methods to detect hits on the target clips. Then, after the timeline code is developed to a certain point, it will show you how to turn the whole thing into a versatile, reusable class that's sure to come in handy whenever you want to make a drag-and-drop style game. In making the class, you will also see how you can employ interfaces, and also dispatch (and listen for) your own custom events! What fun!

This tutorial owes a debt of gratitude to my good friend Jessamin Swearingen, with whom I have been developing some Flash games for school kids in NYC! Hi, kids! Anyway, if you are a teacher like Jessamin, you will probably enjoy this one. Even if you aren't into AS3 programming that much, you might still want to at least grab a copy of the DragGame class, read enough to learn how to use it, and put it to work for you!

Drag & Drop

Hi

When I try to down load the source files I get an unexpected file format message.

I'm using CS3

Any idea what is happening?

Thanks

Gandhi Quote

Live like you will die tomorrow

Learn like you will live forever

Jody Hall's picture

Files are in CS4 format

Ynot sailing,

Sorry about that. I am using Flash CS5. When I write my tutorials, I save all the files in CS4 format. CS5 will save files in CS4 format, and CS4 will save files in CS3 format, but I no longer have Flash CS4 on my computer.

Not having the source files just means you will have to create them yourself, but the good news there is that you will learn much more that way.

Jody

 

 

Thanks Jodi. I suspectred it

Thanks Jodi. I suspectred it might be something like that

Tony (aka Ynot)

Gandhi Quote

Live like you will die tomorrow

Learn like you will live forever

Hello

im having problem with this can you help me out?

Problem: I cannot do the hitTestObject properly. It's working but only in one movieclip.

import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.ui.Mouse;
var u:uint;
for (u=0; u<2; u++)
{
    var sCard:targetMe = new targetMe  ;
    sCard.name = "_sCard" + u;
    sCard.y = 220;
    sCard.x = 20 + u * 90;
    addChild(sCard);
    var sBtn:MovieClip = MovieClip(getChildByName("_sCard" + u));
    sBtn = MovieClip(getChildByName("_sCard" + u));
    trace(sBtn.name);

}
var i:uint;
for (i=0; i<2; i++)
{
    var tCard:cardPlacer = new cardPlacer  ;
    tCard.name = "_tCard" + i;
    tCard.y = 120;
    tCard.x = 10 + i * 90;
    addChild(tCard);
    //trace(tCard.name);
    var tBtn:MovieClip = MovieClip(getChildByName("_tCard" + i));
    tBtn.addEventListener(MouseEvent.CLICK, tBtnHandler);
    tBtn.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
    tBtn.addEventListener(MouseEvent.MOUSE_UP, upHandler);
    tBtn.buttonMode = true;
//    trace('xpos = '+tCard.x);
//    trace('ypos = '+tCard.y);

}

function upHandler(event:MouseEvent)
{
    var tBtn:MovieClip = event.currentTarget as MovieClip;
    addChild(tBtn)//bring to front
    //var sBtn:MovieClip = MovieClip("_sCard"+event.target.name);
    //var sBtn:MovieClip = event.target as MovieClip;
    tBtn.stopDrag();
    //var tBtn:MovieClip = event.currentTarget as MovieClip;
    trace(sBtn.name)
    if (tBtn.hitTestObject(sBtn))
    {
        tBtn.x = sBtn.x;
        tBtn.y = sBtn.y;
        /*trace('xpos = '+tBtn.x);
        trace('ypos = '+tBtn.y);*/

    }
}

function tBtnHandler(event:MouseEvent)
{
    //var tBtn:cardPlacer = event.currentTarget as cardPlacer;
    var tBtn:MovieClip = event.currentTarget as MovieClip;
}
function downHandler(event:MouseEvent)
{
    //var tBtn:cardPlacer = event.currentTarget as cardPlacer;
    var tBtn:MovieClip = event.currentTarget as MovieClip;
    tBtn.startDrag();

}

 

Thank you so much for the help

Jody Hall's picture

keep reading the tutorials

grumbler,

That doesn't work because in your first for loop you are reusing the variable each time. Nothing wrong with this technique, but after the loop runs, your variable only points to the last object created, because it is being overwritten on each iteration of the loop. You need some other way of saving all these references if you are going to use them later. Also, you need some way of making each dynamically generated MovieClip that you are going to drag "know" what MovieClip target it "belongs" to (or matches).

Obviously, in your upHandler function, you can easily get a reference to the clip being dragged because it's the event.currentTarget of the MOUSE_UP event. This gives you a reference to either one of the two clips that could possibly be dragged. But I see you fighting hard to get a reference to whichever of the two clips is supposed to be the matching clip. This is because at this point, you only have one valid variable reference. You might possibly get other references using getChildByName(), but you have no way of knowing which one is supposed to "match" the clip being dragged, because that would have to be established ahead of time somehow.

I usually solve this problem using parallel arrays. If you are creating all the clips dynamically, just "push" them into an array as you create them. Either that or use the loop counter for your index. This will give you references you can use for all the clips. Now, the two arrays have no relationship to each other, except that each clip in one array should have its matching clip at the same position in the other array. In your upHandler, if you can find the position of the clip being dragged in its array (and you can, using indexOf), then you can use that position number to get a reference to the matching clip in the other array.

Here's some code that does just that:

import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.ui.Mouse;

var dragArray:Array = new Array();
var targetArray:Array = new Array();

var u:uint;
for(u = 0; u < 2; u++) {
	var sCard:targetMe = new targetMe();
	sCard.y = 220;
	sCard.x = 20 + u * 90;
	addChild(sCard);
	targetArray.push(sCard);
}

var i:uint;
for(i=0; i<2; i++) {
	var tCard:cardPlacer = new cardPlacer();
	tCard.y = 120;
	tCard.x = 10 + i * 90;
	addChild(tCard);
	tCard.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
	tCard.addEventListener(MouseEvent.MOUSE_UP, upHandler);
	tCard.buttonMode = true;
	dragArray.push(tCard);
}

function downHandler(event:MouseEvent):void {
	var clip:MovieClip = event.currentTarget as MovieClip;
	clip.startDrag();
}

function upHandler(event:MouseEvent):void {
	var dragClip:MovieClip = event.currentTarget as MovieClip;
	var index:int = dragArray.indexOf(dragClip);
	var targetClip:MovieClip = targetArray[index];
	dragClip.stopDrag();
	if(dragClip.hitTestObject(targetClip)) {
		dragClip.x = targetClip.x;
		dragClip.y = targetClip.y;
	}
}

Anyway, keep reading my tutorials, and you will pick up some of these techniques, because it's all explained in there.

ok

Hello jody,

thank you so much for the information you've given me. Now i know my code is not right. I having trouble with the movie clip. It's giving me a null value then i've try to get it by child name but still it doesnt the way it suppose to be.

thanks again! it is very helpful for a beginer like me.

i will revise my code.

I cannot change the target hit test object

Hello Jody,

from the previous code. the object will snap at the right index of the dragclip array. right?

Is there a way i can do the hit test also without detecting the right index of the drag clip?

For example, i drag one of the movie clip and put it on the first box?  then snap.

...... some thing like this. I drag the third movie clip to the first target movie clip then snap?

 

thank you so much.

 

 

 

 

Jody Hall's picture

grumbler, try this

grumbler,

If I am understanding you correctly, then you want any dragging clip to be a match for any of the clips in the other array. In that case, there is no need to get the index of the clip being dragged. But you do need to loop though all the clips in the match array, find the first one that hit tests true, "snap" to that one's screen location, then exit the loop:

function upHandler(event:MouseEvent):void {
	var dragClip:MovieClip = event.currentTarget as MovieClip;

	for(var i:int = 0; i < targetArray.length; i++) {
		if(dragClip.hitTestObject(targetArray[i])) {
			dragClip.x = targetArray[i].x;
			dragClip.y = targetArray[i].y;
			break;
		}
	}
}

Be aware that this code will snap to the first hit it finds, in the order listed in the array. It doesn't discriminate based on "the biggest hit" (overlapping the most) or anything. If you want something like that, it can be done also. Depends on what you need, and how your target clips are spaced on your layout. Hope that helps.

 

: )

Hello Jody,

Im sorry if i have to many question to you. To a beginner like me, my head has a big question for all of this.

Actually im trying to make a game for my self , based on flash like a text twist game. You're tutorial and replies giving me the best solution and helping me to understand it.

Thank you so much. hehe

Jody Hall's picture

No problem. More help for you.

grumbler,

No problem. Hopefully that's what I'm here for. 

I understand that it might be quite a step for a beginner to understand how loops and arrays work together. But if (and when) you do, it opens up lots of creative possibilities. I have an idea that this tutorial: theflashconnection.com/content/streamlining-your-as3-code would help you a lot, and it's really an easy read. The last page deals with arrays and loops.

Jody

How can i shuffle the x position of a movieclip??

Hello Jody,

Im here again. hehe.

Problem:
i have a 5 box of movie clips on the stage then a shuffle button on the top corner.

the x position of 5 movieclip came from an array;

var xPos:Array = new Array();

var i:uint;

xPos = (20,110,200,290,380);

for(i=0;i<xPOs.length;i++) {

mC.x = xPos[i];

}

when i click the shuffle button, the 5 movie clip will exchanges places. (X Position only)

 

thank you so much jody

 

 

just got it

hello jody,

dont mind my comment. i just got it

Hello

Hello jody,

here's what im doin.

import flash.text.TextField;
import flash.events.Event;
import flash.display.*;
import flash.events.*;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.utils.setInterval;
import flash.utils.Timer;

stop();
var stringCount:Number;
var stringArray:Array = new Array();
var i:Number;
var dragArray:Array = new Array();
var targetArray:Array = new Array();
var stringFieldArray:Array = new Array();
var myStrng:String;
var hintWord:String;

var randomPosition:Array = new Array();
var randomPositionArray:Array = new Array();
var positionArray:Array = new Array();
var item:uint;
var ranNum:int;
var stWord:String;
var xmldata:XML;
xmldata = new XML();
var xmlURL:URLRequest = new URLRequest("XML/lib.xml");
var xmlLoader:URLLoader = new URLLoader(xmlURL);
xmlLoader.addEventListener(Event.COMPLETE,xmlLoaded);
xmlLoader.addEventListener(IOErrorEvent.IO_ERROR,xmlLoadError);
function xmlLoadError(event:IOErrorEvent)
{
    trace(event.text);
}
function xmlLoaded(event:Event)
{
    trace('==========\nXML LOADED\n==========');
    xmldata = XML(event.target.data);
    item = xmldata.item.length();
    ranNum = Math.floor(item * Math.random());
    stWord = xmldata.item.word.attributes()[ranNum];
    trace("Random Word = " + stWord);
    stringCount = stWord.length;
    trace("String Count = " + stringCount);
    var startList:Array = new Array();
    var endList:Array = new Array();
    var c,j,u,r:int;
    for (c=0; c<stringCount; c++)
    {
        j = 20 + c * 90;
        startList[c] = j;
    }

    for (i=0; i<stringCount; i++)
    {
        stringArray[i] = stWord.charAt(i);
        var cPlacer:cardPlacer = new cardPlacer();
        cPlacer.y = 150;
        r = Math.floor(Math.random() * startList.length);
        endList.push(startList[r]);
        startList.splice(r,1);

        cPlacer.x = endList[i];
        cPlacer.sLetter.text = stringArray[i];
        cPlacer.name = stringArray[i];
        addChild(cPlacer);
        cPlacer.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
        cPlacer.addEventListener(MouseEvent.MOUSE_UP, upHandler);
        cPlacer.buttonMode = true;
        dragArray.push(cPlacer);
        var tMe:targetMe = new targetMe();
        tMe.y = 220;
        tMe.x = 20 + i * 90;
        addChild(tMe);
        targetArray.push(tMe);
        tMe.alpha = .5;

    }

    hintWord = xmldata.item.word[ranNum].hint;
    hintTxt.text = hintWord;
    hintTxt.selectable = false;

    myTimer.start();
    myTimer.addEventListener(TimerEvent.TIMER, sayHello);
    myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, sayBye);

}

var myTimer:Timer = new Timer(1000,60);
var timerCont:Number;

function sayHello(e:TimerEvent):void
{
    timerCont = 0;
    timerCont = myTimer.currentCount;
    //trace('Timer = ' + timerCont.toString( ));
    timerTxt.text = Number(timerCont).toString();
}

function sayBye(e:TimerEvent):void
{
    myTimer.stop();
    gotoAndStop(3);

}

stringFieldArray.length = stringCount;
function downHandler(event:MouseEvent):void
{

    var clip:MovieClip = event.currentTarget as MovieClip;
    clip.startDrag();
    addChild(clip);

}
function upHandler(event:MouseEvent):void
{
    var clip:MovieClip = event.currentTarget as MovieClip;
    var index:int = dragArray.indexOf(clip);
    //var sameClip:MovieClip = targetArray[index];
    clip.stopDrag();
    for (var i:int = 0; i < targetArray.length; i++)
    {
        if (clip.hitTestObject(targetArray[i]))
        {

            clip.x = targetArray[i].x;
            clip.y = targetArray[i].y;
            //removeChild(clip);
            //removeChild(targetArray[i]);
            //trace(targetArray)
            stringFieldArray[i] = event.currentTarget.name;

        }
    }
}
checkMc.addEventListener(MouseEvent.CLICK, checkMcHandler);
function checkMcHandler(event:MouseEvent):void
{
    trace('==========\nCHECK WORD\n==========');
    myStrng = stringFieldArray.join("");
    trace('myStrng = ' + myStrng);
    if (myStrng == stWord)
    {
        trace('true');
        sCore +=  20;
        scoreTxt.text = Number(sCore).toString();
        myTimer.stop();
        gotoAndStop(3);

    }
    else
    {
        sCore +=  -5;
        scoreTxt.text = Number(sCore).toString();
        trace('false');
    }

}

 

remember i say im doin something like a text twist game. My problem here is that the drag clip is overlapping on each other i cannot make a restriction that if the drag clip has been placed to the targetclip it should be not enabled to put another clip to it. i've tried a lot but it does seems not working and giving me error.

 

Jody Hall's picture

remove target clip from its array

In your upHandler, just after you set the x and y, you need to follow up with a line that removes the target clip from the target array:

targetArray.splice(i, 1);

This will keep it from being hitTested again. Just removing the clips from the display list with removeChild doesn't do it, as you discovered. Clips that are not on the display list still have x, y, width, and height properties, and that is what hitTestObject uses to determine if they are colliding. It's all math and has nothing to do with the visuals.

 

 

Problem with slide in the dragged item into right place holder

 HI,

Please have look of this game http://www.showtoclients.com/game/drag&drop.html

I tried to work on this game and made upto here with lot's of change around. Now the final problem with this game are:

-the words don't slide into the boxes ( This means only right word is sliding while eben the wrong word should also be slide in just like right one)

-theres a strange bug in the game that shows the submit button before dragging all the words into the boxes. ( I got the falut but don't know it's solution. when user is taking the word on place holder , considering he is taking it to wrong place holder, the counter get's incremented by one , since word is not sliding in hence user try to place it appropratly inside the place holder and that increases the counter one again. )

-When one word is already in a box and another word is dragged into the same box. the word occupying the box should return to its default position. ( No clu how to do that)

 I would be greatful you can see the code and help me 

 

------

stop();

 

var num:int = 0;

var num1:int = 0;

 

ob1.addEventListener(MouseEvent.MOUSE_DOWN, startdragin1);

ob1.addEventListener(MouseEvent.MOUSE_UP, stopdragin1);

 

ob2.addEventListener(MouseEvent.MOUSE_DOWN, startdragin2);

ob2.addEventListener(MouseEvent.MOUSE_UP, stopdragin2);

 

ob3.addEventListener(MouseEvent.MOUSE_DOWN, startdragin3);

ob3.addEventListener(MouseEvent.MOUSE_UP, stopdragin3);

 

ob4.addEventListener(MouseEvent.MOUSE_DOWN, startdragin4);

ob4.addEventListener(MouseEvent.MOUSE_UP, stopdragin4);

 

ob5.addEventListener(MouseEvent.MOUSE_DOWN, startdragin5);

ob5.addEventListener(MouseEvent.MOUSE_UP, stopdragin5);

 

ob6.addEventListener(MouseEvent.MOUSE_DOWN, startdragin6);

ob6.addEventListener(MouseEvent.MOUSE_UP, stopdragin6);

 

ob7.addEventListener(MouseEvent.MOUSE_DOWN, startdragin7);

ob7.addEventListener(MouseEvent.MOUSE_UP, stopdragin7);

 

ob8.addEventListener(MouseEvent.MOUSE_DOWN, startdragin8);

ob8.addEventListener(MouseEvent.MOUSE_UP, stopdragin8);

 

complete_btn.addEventListener(MouseEvent.CLICK, startlevel);

 

function startdragin1(evt:MouseEvent):void

{

ob1.startDrag();

}

 

function startdragin2(evt:MouseEvent):void

{

ob2.startDrag();

}

 

function startdragin3(evt:MouseEvent):void

{

ob3.startDrag();

}

 

function startdragin4(evt:MouseEvent):void

{

ob4.startDrag();

}

 

function startdragin5(evt:MouseEvent):void

{

ob5.startDrag();

}

 

function startdragin6(evt:MouseEvent):void

{

ob6.startDrag();

}

 

function startdragin7(evt:MouseEvent):void

{

ob7.startDrag();

}

 

function startdragin8(evt:MouseEvent):void

{

ob8.startDrag();

}

 

function stopdragin1(evt:MouseEvent):void

{

ob1.stopDrag();

num1 +=  1;

if (ob1.hitTestObject(tr1))

{

ob1.x = tr1.x;

ob1.y = tr1.y;

num +=  1;

 

}

}

function stopdragin2(evt:MouseEvent):void

{

ob2.stopDrag();

num1 +=  1;

if (ob2.hitTestObject(tr2))

{

ob2.x = tr2.x;

ob2.y = tr2.y;

num +=  1;

 

}

}

function stopdragin3(evt:MouseEvent):void

{

ob3.stopDrag();

num1 +=  1;

if (ob3.hitTestObject(tr3))

{

ob3.x = tr3.x;

ob3.y = tr3.y;

num +=  1;

 

}

}

function stopdragin4(evt:MouseEvent):void

{

ob4.stopDrag();

num1 +=  1;

if (ob4.hitTestObject(tr4))

{

ob4.x = tr4.x;

ob4.y = tr4.y;

num +=  1;

 

}

}

function stopdragin5(evt:MouseEvent):void

{

ob5.stopDrag();

num1 +=  1;

if (ob5.hitTestObject(tr5))

{

ob5.x = tr5.x;

ob5.y = tr5.y;

num +=  1;

 

}

}

function stopdragin6(evt:MouseEvent):void

{

ob6.stopDrag();

num1 +=  1;

if (ob6.hitTestObject(tr6))

{

ob6.x = tr6.x;

ob6.y = tr6.y;

num +=  1;

 

}

}

function stopdragin7(evt:MouseEvent):void

{

ob7.stopDrag();

num1 +=  1;

if (ob7.hitTestObject(tr7))

{

ob7.x = tr7.x;

ob7.y = tr7.y;

num +=  1;

 

}

}

function stopdragin8(evt:MouseEvent):void

{

ob8.stopDrag();

num1 +=  1;

if (ob8.hitTestObject(tr8))

{

ob8.x = tr8.x;

ob8.y = tr8.y;

num +=  1;

 

}

}

 

addEventListener(Event.ENTER_FRAME,checkForLevel1Complete);

 

// and then add this function

function checkForLevel1Complete(e:Event):void

{

 

 

if (num1 >= 8)

{

// make the 'LEVEL 1 COMPLETE' button visible

complete_btn.visible = true;

 

// remove the event listener which checks for correctly placed flags

removeEventListener(Event.ENTER_FRAME, checkForLevel1Complete);

}

else

{

complete_btn.visible = false;

 

}

 

}

 

function startlevel(evt:MouseEvent):void

{

gotoAndPlay(2);

 

 

hope you can help. 

adding a timer

Hi Jody!
Thank you for this and the other tutorials, I'm using them to try to develop some exercises for my students. I wonder if you could give me some help, I searched but was unable to find solution, I'm quite a newbie.
The thing is I followed your tutorial to make a drag&drop map, no problem on that. Now, I'm trying to add a timer to it, so that, when the student completes the map, a message is displayed showing how long did it take. I have this code for a timer:

var startTime:int = getTimer();
addEventListener(Event.ENTER_FRAME, showClock);
function showClock(event:Event):void{
var timePassed:int = getTimer()-startTime;
var seconds:int = Math.floor(timePassed/1000);
var minutes:int = Math.floor(seconds/60);
seconds -= minutes*60;
var timeString:String = minutes + ":" + String(seconds+100).substr(1,2);
timeDisplay.text = timeString;
}

I put this code on the .fla file, and it gives me the timer (timeDisplay.text is a dynamic text on the stage), but I don't know how to store the final time on a variable so to pass it to another dynamic text, on the end scene, which is in the third frame. I also tried to store the timer as a class, but was also unable to do it properly, it gives me 1180 and 1120 errors, method not defined and property not defined.

I don't know if I explained myself, my english is not so good and neither is my programming, if I did and you have some time to help me, I would be very grateful.
Cheers!

Hi Jody, I wonder if you

Hi Jody,
I wonder if you could give me a hint about how you would do this:
I want to create a label game in which different objects share the same destinations, sort of:
objArray [cat,dog,horse,sparrow,seagull,eagle,bee,wasp,ant]
matchArray[mammals,birds,insects]
I'm trying to do it following your code and adding an if statement in which I assign to the objArray index a matchIndex:int, like:

if (0<=index<=2){
var matchIndex:int=0
};
if (3<=index<=5){
var matchIndex:int=1
};
if (6<=index<=8){
var matchIndex:int=2

and then setting matchClip as
var matchClip:MovieClip = MovieClip(_matchArray[matchIndex]);

this doesn't seem to work, it gives me back an 1009 error, can't access a property or method of a reference to a null object.

Any idea? is my method ok?

Thanks for your work and your attention.

Forget it

Hehe... I've seen my syntax is horrible, forget about it, I solved it... just "else if"...

flash_as3_drag_drop

Hi,

Im a complete Novice at action scripting ... but thanks to your tutorial i was able to make a drag and drop jigsaw puzzle .... following the exact instructions .... ive also been able to add a timer to the game, unfortunately i am unable to figure out how to restart the game again .... at the end of the tutorial u mentioned that ( ... you'd have to save all the positions of all the drag clips into another array. You would also have to move some of the actions from the constructor function into an init() type function so that those actions could be called again. )

being a complete beginner i was unable to understand how to do so ... hence was wondering if you could help me in this

Awaiting a reply

Regards,
Sheldon

Jody Hall's picture

Drag & Drop with Reset feature

Sheldon,

Thanks for your interest in the tutorial, and I really appreciate the feedback! Glad to hear that you were able to use the info to make a working application! Your inquiry has prompted me to finally modify the class so that it can accommodate a reset button! Maybe I'll also get around to writing it into a follow-up page to this tutorial. For now, I'll upload and post the ZIP file for you here. I made some comments in the code that should help explain the additions I made, both in the fla file's timeline code AND in the DragGame class's code.

Anyway, here's the download link for the ZIP file:

Drag & Drop With Reset Button

persistent image

Jody, I really have earned the title noob. Your example works great. However, the images remain when I proceed to other frames. How do I clear the triangle, square and circle (rect1, rect2, rect3 in my project) so they don't appear in subsequent frames? Thank you in advance.

deaconpt's picture

Hello there, noob alert (and

Hello there,

noob alert (and sorry for my bad English.)!

I wanted to put everything inside a movieclip, and place it wherever I want.
I did managed to copy all and put inside a new mc. But when I publish it, i can still drag the objects, but they don't stay in the target area.

Any idea, of what I am doing wrong? If necessary I can post a link to what I've done.

Thanks :)

Resetting the game on a new frame

Hi Jody,
I tried emailing you yesterday about a couple of things, but there was a problem with your contact form. I kept getting errors after I typed in the codes, but sorry if you got loads of emails.

Firstly, thanks so much for your detailed tutorials - I'm a designer learning AS3, and the way you explain everything is amazing! Your tutorials actually inspired me to write my own, but I'll come to that later..

I have the same problem as the guy above (Persistent image):

I've been trying out your drag and drop class, which is the best I've found online, however, I'm really stuck trying to reuse it. For instance, I work on the timeline on single stopped frames (primitive I know, but as a designer I like to see what I'm doing!). Say I've stuck two Mcs to their Match points, I then go back a frame on the timeline - but the Mcs still appear, as if they are stuck in the memory. I'd also like to start a new drag and drop scene on the following frame, but I don't know how to reset it! Making the draggable MCs 'visible=false' does not always work, so I'm really stuck. Any chance you have a solution for this? Your level is way over my head!

p.s Thanks for the new reset code you posted. It's very useful, but sadly does not effect the 'new frame' problem..

Thanks,
Matt

Jody Hall's picture

Re: Resetting the game on a new frame

Matt, The reason why this is a problem is because timeline navigation itself is at fault. Everyone seems to want to use timeline navigation for their applications, because it's easy and because gotoAndStop and gotoAndPlay are easily understood. But the big problem is that the keyframes in your movie clip are not isolated "scopes." A scope could be defined as an area where variables and functions must have unique names. The keyframe is not the scope, the whole movie clip is the scope. That being the case, you can define a function on one keyframe, and call it from a keyframe further down the timeline. Similarly, you can define a variable on one keyframe, and use its value on a later keyframe. You can't define a variable or function on a keyframe, and then use the same name to define it again on a later frame. That name is already "taken" because the scope of the memory space for variables and functions is the whole movie clip, not the individual keyframes. All of this adds up to making the movie clip's timeline a lousy choice for a navigation system. The burden is upon YOU to remember which variable names and function names you already used on other frames. Even worse when you come back to a project at a later date!

What's needed is a more modular system. If they invented a new kind of MovieClip where every keyframe is a scope of its own, that might be ideal. But that isn't likely to ever happen. Since the MovieClip as a whole is a scope, the best thing to do is just use whole movie clips for your different sections, instead of the keyframes of just one movie clip. This leads to the system I described in "Better Flash Navigation using AS3 classes" where movie clips are "screens," each one backed up by a linked class. Technically, you could also use a system like this without classes, with all your code on the first frame of each MovieClip. However, the linked class idea is much better! The tutorial will teach you this technique, and can also help you get familiar with classes, which is ultimately what you want to do.

So fixing your problem as it is, is kind of like saying "I'm rowing my rowboat across the desert and one of my oars is broken, help me fix it." Fixing your oar isn't going to fix the real problem, because rowing a boat across the sand is inefficient in the first place, just like timeline navigation systems are a pain in the first place. I sometimes help people fix their little problems with their timeline systems, but I am usually tempted to take the whole thing apart and structure it differently. I will also help you fix your file, if you send it to me at mazoonist at gmail dot com. I can fix it using the timeline navigation system you have in place (but the solution will feel like a hack), or I can completely restructure it for you. Give me a try, I don't mind either way. But I'd rather give you a dune buggy than fix your broken oar!

The movieclip method works - Thanks so much!

Hi Jody,
I understand what you mean by scopes now. I'll try to start using classes, but for now, putting everything into a separate Movie Clip works great. It also keeps everything neat and self contained. Learning to build a project from the class method is going to be quite a jump, as I don't know how I'll visualize everything, but I'm already getting into deep water with the timeline.

Expect a little donation from me soon, as I really appreciate your help. Here is the other part of the email I tried to send:

Thanks so much for your detailed tutorials - I'm a designer learning AS3, and your tutorials actually inspired me to write my own, which are basic, but have helped a few people trying out Flash to iOS. Designing for iPad was the reason I needed to start learning AS3 code.

Firstly, I combined some of your code to make a button counter. It probably looks terrible, but it's all I could patch together. All I wanted was a way to count button clicks, but could not find a simpler way (a guy helped me with the counter). I credit you here. If you happen to know a more concise method, feel free to comment and I'll update it!

http://www.mattwasser.co.uk/articles_Flash_Counting_button_Array.html

Thanks again,
Matt

(UK)

hi jody I have a different

hi jody

I have a different way of doing the drag and drop thing, ive made a jigsaw which worked pretty well, and now i am making a log bridge for children, it teaches them about sequencing numbers

having huge problems, basically i have code which will drop a correct log into place by checking against the targetname, but i also wish to be able to drop an incorrect log into place so that i can play an animation of my character falling,

the problem here though, is i need to check if the user intentionally moved the piece into place and if so play an animation of the log falling and then the character jumps and falls etc

and if not return the log to its startX position

ive opened a post here if you care to look at my code
http://forums.adobe.com/thread/964973?tstart=0

wondering if you have any suggestions?
thanks for a great site
fonzio

Jody Hall's picture

Send me your file

Fonzio,

Thank you for joining my site, and posting your comment.

When someone says the words "I have code" (like you did), it usually means they have code they are trying to use but they didn't write it. Because if YOU write the code, you can make it do whatever you want it to do (assuming you know how).

When someone has code that has function names like "pickUp" and "dropIt" and code that uses dropTarget, I know it came from the monkeyflash.com tutorial. This tutorial must have got a ton of exposure, because it used to come up in first place when you googled "flash drag drop." Also I have seen this code posted on forums many, many times before. Amazingly, I don't get anything when I try to go to monkeyflash.com (I just now tried).

I don't advocate using dropTarget. It's just more hassle to use than it's worth, and you can do the same thing(s) much easier with hit testing.

I looked at your code on the adobe forum you linked to. It looks like you are relying on the borrowed code too much instead of relying on your own. I would be glad to take a look at your problem file if you care to send it to me. Looking at the code doesn't always do it for me (I didn't see any obvious mistakes or anything). I need to be able to see how you set things up, and being able to test it is sometimes crucial. My email is mazoonist at gmail dot com.

Jody

thanks!

hi jody

would just like to say thanks for helping me on my drag and drop game, you really went above and beyond, ive donated to your site

thanks again
fonzio