Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411656 Posts in 69395 Topics- by 58451 Members - Latest Member: Monkey Nuts

May 15, 2024, 03:10:15 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Drag-and-drop with movieclips in an array
Pages: [1]
Print
Author Topic: Drag-and-drop with movieclips in an array  (Read 2835 times)
Craig Stern
Level 10
*****


I'm not actually all that stern.


View Profile WWW
« on: June 14, 2010, 11:17:47 PM »

Okay, it's AS3 newbie question time again. (Sorry.) Same card game as before--this time, I'm trying to make the cards drag-and-drop. All code shown here is in the document class.

This code, which isn't for dragging-and-dropping, works perfectly:

Code:
function showDeck () {

var cardMCsArray:Array = new Array ();

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

var myCard:Card = new Card(playerDeck[i][1] , playerDeck[i][2]);
myCard.name = "card" + i;
addChild(myCard);

myCard.x = 10;
myCard.y = 40 + (i * 25);
myCard.rotation = 0;
myCard.gotoAndStop(playerDeck[i][0]);

cardMCsArray.push(myCard);
cardMCsArray[i].addEventListener(MouseEvent.CLICK, selectCard);

function selectCard (event:MouseEvent):void{
trace(event.currentTarget.name);
}
}
}

This, on the other hand, fails miserably:

Code:
function showDeck () {

var cardMCsArray:Array = new Array ();

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

var myCard:Card = new Card(playerDeck[i][1] , playerDeck[i][2]);
myCard.name = "card" + i;
addChild(myCard);

myCard.x = 10;
myCard.y = 40 + (i * 25);
myCard.rotation = 0;
myCard.gotoAndStop(playerDeck[i][0]);

cardMCsArray.push(myCard);

//MAKE DRAGGABLE
cardMCsArray[i].addEventListener(MouseEvent.MOUSE_DOWN, startCardDrag);
stage.addEventListener(MouseEvent.MOUSE_UP, stopCardDrag);
cardMCsArray[i].addEventListener(Event.ENTER_FRAME, dragCard);

var clickOffset:Point = null;

function startCardDrag(event:MouseEvent) {
clickOffset = new Point(event.localX, event.localY);
}

function stopCardDrag(event:MouseEvent) {
clickOffset = null;
}

function dragCard(event:Event) {
if (clickOffset != null) { //if Card is being dragged
cardMCsArray[i].x = mouseX - clickOffset.x;
cardMCsArray[i].y = mouseY - clickOffset.y;
}
}
}
}

It just returns an error:

Quote
TypeError: Error #1010: A term is undefined and has no properties.
   at MethodInfo-11()

I'm sure that this error has something to do with the way I'm referencing the cards in the dragCard function, but I'm not sure how else to do it. (Using myCard in place of the array call results in Flash only performing drag-and-drop with the last card it puts down.)

Any ideas?
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1 on: June 15, 2010, 02:20:20 AM »

You've been bit by a closure gotcha. Nothing to do with objects.

Closures in AS3 can read (and modify) the variables of the enclosing scope. You are doing this for i. But it is reading it, not copying it at the time the closure is made. So each dragCard sees the same value of i, which will be length. Not what you want.

Instead, you must make sure to create a new variable *inside the for loop*, i.e.

      var j:int = i;
      function dragCard(event:Event) {
         if (clickOffset != null) {   //if Card is being dragged
            cardMCsArray[j].x = mouseX - clickOffset.x;
            cardMCsArray[j].y = mouseY - clickOffset.y;
         }
      }

now each j referenced will be different.


P.S. debugging is way easier if you get line numbers - you should use a debug build of Flash.
Logged
Craig Stern
Level 10
*****


I'm not actually all that stern.


View Profile WWW
« Reply #2 on: June 15, 2010, 06:04:23 AM »

Thanks for the help, but it doesn't seem to referencing a different j each time: every time I click on a card, it now drag-and-drops the last card Flash put down.
Logged

Draknek
Level 6
*


"Alan Hazelden" for short


View Profile WWW
« Reply #3 on: June 15, 2010, 06:27:06 AM »

Try moving the var j:int = i; code into the dragCard function.

I think that's still the same problem: in AS3 variables always have function scope, so j is always the same variable each time around the loop. Moving it into dragCard puts it into a different scope so it's treated as a different variable every time.
« Last Edit: June 15, 2010, 06:31:16 AM by Draknek » Logged

Craig Stern
Level 10
*****


I'm not actually all that stern.


View Profile WWW
« Reply #4 on: June 15, 2010, 06:28:58 AM »

That just gives me

Quote
TypeError: Error #1010: A term is undefined and has no properties.
   at MethodInfo-11()
Logged

Draknek
Level 6
*


"Alan Hazelden" for short


View Profile WWW
« Reply #5 on: June 15, 2010, 06:41:16 AM »

Damn, that makes sense too.

Try this:

Code:
function dragCard(event:Event) {
if (clickOffset != null) { //if Card is being dragged
event.target.x = mouseX - clickOffset.x;
event.target.y = mouseY - clickOffset.y;
}
}
Logged

Craig Stern
Level 10
*****


I'm not actually all that stern.


View Profile WWW
« Reply #6 on: June 15, 2010, 06:44:42 AM »

That's...odd. Doing that results in the "drag the last card placed" bug, and the rest of the cards disappear from the stage for good measure.
Logged

bateleur
Level 10
*****



View Profile
« Reply #7 on: June 15, 2010, 07:16:41 AM »

Note that Flash only actually allocates variables at the function level, so it doesn't make the slightest bit of difference whether you declare variables inside or outside your loops.

The cleanest, most comprehensible way to write code for this kind of thing is to enter a new scope by calling a helper function, like this:

Code:
function showDeck() {
 ...
 for (i = 0 ; i < playerDeck.length ; i++ ) {
  ...
  addListeners(myCard);
 }
}

function addListeners(card:Card) {
 var clickOffset:Point = null;

 function startCardDrag(event:MouseEvent) {
  clickOffset = new Point(event.localX, event.localY);
 }

 function stopCardDrag(event:MouseEvent) {
  clickOffset = null;
 }

 function dragCard(event:Event) {
  if (clickOffset != null) { //if Card is being dragged
   card.x = mouseX - clickOffset.x;
   card.y = mouseY - clickOffset.y;
  }
 }
}
Logged

Craig Stern
Level 10
*****


I'm not actually all that stern.


View Profile WWW
« Reply #8 on: June 15, 2010, 07:36:47 AM »

Sweet, thanks! This did the trick.

Code:
function showDeck () {

var cardMCsArray:Array = new Array ();

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

var myCard:Card = new Card(playerDeck[i][1] , playerDeck[i][2]);
myCard.name = "card" + i;
addChild(myCard);

myCard.x = 10;
myCard.y = 40 + (i * 25);
myCard.rotation = 0;
myCard.gotoAndStop(playerDeck[i][0]);

cardMCsArray.push(myCard);

addListeners(myCard);

function addListeners (card:Card) {

card.addEventListener(MouseEvent.MOUSE_DOWN, startCardDrag);
stage.addEventListener(MouseEvent.MOUSE_UP, stopCardDrag);
card.addEventListener(Event.ENTER_FRAME, dragCard);

var clickOffset:Point = null;

function startCardDrag(event:MouseEvent) {
clickOffset = new Point(event.localX, event.localY);
}

function stopCardDrag(event:MouseEvent) {
clickOffset = null;
}

function dragCard(event:Event) {
if (clickOffset != null) {
card.x = mouseX - clickOffset.x;
card.y = mouseY - clickOffset.y;
}
}
}
}
}
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #9 on: June 16, 2010, 02:46:58 PM »

Thanks, bateleur. That had passed my mind thanks to wishful thinking while answering before.
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic