PDA

View Full Version : Making code more efficient


Mickstah
08-13-2009, 11:54 AM
Hi guys. I've just decided to take the plunge and teach myself AS3, so far it's been okay, but I really need to know how to streamline my code.

I've been able to get things working, albeit in a very sloppy way. I've been trying to find ways to streamline things but I keep breaking my code.

var otherindex = getChildIndex(square_mc);
var otherindex1 = getChildIndex(circle_mc);

square_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp);
square_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt);
circle_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp);
circle_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt);

function pickUp(event:MouseEvent):void {
event.target.startDrag(true);


}
function dropIt(event:MouseEvent):void {
event.target.stopDrag();
}
square_mc.buttonMode = true;
circle_mc.buttonMode = true;


bg1.addEventListener(MouseEvent.CLICK, background1);
bg2.addEventListener(MouseEvent.CLICK, background2);
bg3.addEventListener(MouseEvent.CLICK, background3);
bg4.addEventListener(MouseEvent.CLICK, background4);

function background1(event:MouseEvent):void
{
setChildIndex(mc1, otherindex - 1);
setChildIndex(mc1, otherindex1 - 1);

}
function background2 (event:MouseEvent):void
{
setChildIndex(mc2, otherindex - 1);
setChildIndex(mc2, otherindex1 - 1);
}
function background3(event:MouseEvent):void
{
setChildIndex(mc3, otherindex - 1);
setChildIndex(mc3, otherindex1 - 1);
}
function background4(event:MouseEvent):void
{
setChildIndex(mc4, otherindex - 1);
setChildIndex(mc4, otherindex1 - 1);
}

So basically the above code is playing with drag and drop of two shapes which swap depths on click. They always stay above the backgrounds. There are 4 different background to select between, and I've set the depths so that they always sit behind the shapes, but above each other.

However the way I've done it just looks really bloated to me. What I'd like to do is group the two shapes so that instead of calling otherindex and otherindex1, I can just group both shapes into other index and call upon it once.

Is it possible to group objects? I can get away with it at the moment because there is only two shapes, but if there were 10 shapes, all of a sudden I'm writing 40 lines of code that REALLY doesn't need to be there.

Teach a n00b some new tricks please :)

tango88
08-13-2009, 12:13 PM
Is it possible to group objects?

Sure, you can have an array of objects. Let me dig up a link for you...here...

http://www.tech-recipes.com/rx/1383/flash-actionscript-create-an-array-of-objects-from-a-unique-class/

Mickstah
08-13-2009, 12:43 PM
Sure, you can have an array of objects. Let me dig up a link for you...here...

http://www.tech-recipes.com/rx/1383/flash-actionscript-create-an-array-of-objects-from-a-unique-class/
Thanks for that!

So I should be able to use
var dropArray:Array = new Array(square_mc, circle_mc);To create the array?

Mickstah
08-13-2009, 01:06 PM
Okay I *think* I'm starting to understand the deal here.

var dropArray:Array = new Array(square_mc, circle_mc);

var i:int;
for (i = 0; i < (dropArray.length); i++) {
var otherindex = getChildIndex(dropArray[i]);
}
Create the array, then loop the array to call all the elements in the array, then use dropArray[i] to call those elements. But this seems to be causing errors.

rawmantick
08-13-2009, 01:24 PM
Something about efficiency, some general things...
http://docs.google.com/present/view?id=d4jrvds_0hjb794hr

Mickstah
08-13-2009, 01:46 PM
Woohoo I managed to get things working how I want more efficiently.

// Create an array with specified elements.
var dropArray:Array = new Array();
dropArray[0]= squareMc;
dropArray[0]= circleMc;

var otherindex = getChildIndex(dropArray[0]);


squareMc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp);
squareMc.addEventListener(MouseEvent.MOUSE_UP, dropIt);
circleMc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp);
circleMc.addEventListener(MouseEvent.MOUSE_UP, dropIt);

function pickUp(event:MouseEvent):void {
event.target.startDrag(true);
}
function dropIt(event:MouseEvent):void {
event.target.stopDrag();
}

dropArray[0].buttonMode = true;

bg1.addEventListener(MouseEvent.CLICK, background1);
bg2.addEventListener(MouseEvent.CLICK, background2);
bg3.addEventListener(MouseEvent.CLICK, background3);
bg4.addEventListener(MouseEvent.CLICK, background4);

function background1(event:MouseEvent):void
{
setChildIndex(mc1, otherindex - 1);
}
function background2 (event:MouseEvent):void
{
setChildIndex(mc2, otherindex - 1);
}
function background3(event:MouseEvent):void
{
setChildIndex(mc3, otherindex - 1);
}
function background4(event:MouseEvent):void
{
setChildIndex(mc4, otherindex - 1);
}


However I still need to declare mouse event listeners for each shape, if I try to use the array it only allows drag/drop for one shape.

snickelfritz
08-13-2009, 05:58 PM
Actionscript and construction technique are two sides of the same coin.
FLA is attached.

background_mc.stop();

var targetID:int;
var n:int = buttons_mc.numChildren;

for (var i:int = 0; i < n; i++)
{
var b:MovieClip = MovieClip(buttons_mc.getChildAt(i));
b.gotoAndStop(i + 1);
b.buttonMode = true;
b.id = i;
b.addEventListener(MouseEvent.CLICK, btnClick);
}

function btnClick(e:MouseEvent):void
{
targetID = int(e.currentTarget.id + 1);
background_mc.gotoAndStop(targetID);
}

dragdrop_mc.addEventListener(MouseEvent.MOUSE_DOWN , pickUp);
dragdrop_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt);

function pickUp(e:MouseEvent):void
{
dragdrop_mc.addChild(MovieClip(e.target));
e.target.startDrag();
}

function dropIt(e:MouseEvent):void
{
e.target.stopDrag();
}

Mickstah
08-16-2009, 05:02 PM
Wow!

Snickelfritz I think I love you - that is amazing! I was using the background movie clips as separate symbols and swapping depths, but what you put together makes so much more sense!

I also love the idea of all the shape assets in the same movie clip, but I really don't understand how that part of the code works.

I know it is a massive ask, but are you able to explain to me how it operates? I'd love to know how you managed to get it working so simply!

snickelfritz
08-16-2009, 06:54 PM
The explanation might seem a bit complex, but the underlying principles and concepts are elegant and simple, due to the nature of the awesome AS3 displaylist.
IMO, AS3 absolutely trounces AS2 in this regard.
On the stage you have Movieclip "buttons_mc".
buttons_mc is essentially just a "graphical array" of movieclips (there are 4 in this case, but the actual number of nested movieclips is irrelevant).
In AS3, array indexes begin with 0, so the bottom-most movieclip within buttons_mc has an index of 0.
The next one up has an index of 1, and so forth.

The for..loop utilizes this graphical array as the basis for incrementing upward the value of i.
ie: first loop: i == 0; second loop: i == 1; and so forth until the value of i exceeds the number of children within buttons_mc, at which point, the for..loop is exited and the normal flow actionscript continues.

Within the for..loop, the playhead within the movieclip currently being processed (which is the movieclip targeted in the variable "b") is sent to the frame number that corresponds to the current value of i+1, and is stopped there permanently.
"i+1" is used, because the timeline begins with 1, not 0. (which IMO, is a consistency flaw in the IDE)

Also assigned to the current MovieClip is an "id" number that corresponds to the current value of i, which conveniently correlates with the index of the MovieClip within buttons_mc.

This is the real magic of this technique, and fully leverages the speed and power of the AS3 displaylist.
You can subsequently use this id number as the basis for accessing arrays, XMLLists, moving the playhead, etc...

So for example, button0 has an index of 0 within button_mc, and an id number of 0;
When clicked, send the background_mc playhead to the frame number that is equal to the id number of the button + 1; (again, because the timeline begins with 1, not 0).
This frame number calculation is stored in the public variable "targetID", which is referenced in the call: gotoAndStop(targetID);

BTW, imagine for a moment, that "background_mc" is actually "pages_mc", and instead of background images, each frame contains a page of content for your website.
You would then have the basis for a simple gotoAndStop frame navigation system for your website!

Mickstah
08-16-2009, 08:41 PM
That's amazing! I love it!

It really puts how I would code timeline actions in AS2 to shame, I'm almost ashamed of myself! Thanks for taking the time to explain it for me, it really helps!

I was thinking, with something like this you could use variable 'b' to assign a layer on which the dragdrop children could 'live' on once the clip is 'dropped' right?

So I could use 'b' to determine the depth index like:

var depthIndex = getChildIndex(b);

Then it would just be a case of modifying the dropIt function like so:

function dropIt(e:MouseEvent):void
{
e.target.stopDrag();
setChildIndex(depthIndex);
}

Is this the best way to do things or should I forget depthIndex altogether?

Actually wait, scratch that, if I was to assign a depthIndex that moved the symbol to a new layer then it would strip the clip of any drag/drop functionality, or would AS3 still consider it a child of dragdrop_mc even though it no longer lives in dragdrop_mc?

snickelfritz
08-16-2009, 09:20 PM
AddChild(); does the same thing, since two instances of the same object cannot co-exist in the same space.
So using addChild() on an object already on the displaylist simply moves the object to the top of the stack, and the other objects in the list move down to fill the hole.

Event propagation takes care of the drag/drop behavior.
Any eligible displayObject (any object that can be an event target) within dragdrop_mc will have this behavior.

Mickstah
08-17-2009, 03:17 AM
Oh wow - I didn't even notice that in the fla you provided there already was depth swapping!! (it's more noticeable when you add more objects in dragdrop_mc) - but it makes sense, there is no reason to getChild when we're already using addChild.

You said that any eligible displayObject in dragdrop_mc will have the drag/drop function, but what I was trying to say before was what if we decided to assign the object to a new layer or movie clip (for instance, perhaps one of the background frames, or a new movie clip altogether). In a situation like that would drag/drop still function, or would there need to be event listeners for the new movie clip?

I hope that makes sense?

AishaRenee
08-17-2009, 03:29 AM
Hello All!

can any body help me out with my coding. Trying to code buttons i used this code as a short cut of sorts. when I test movie my site loops.

The complier error reported is:
scene 1, Layer 'actions', Frame 1, 1120: Access of undefined property event switch (event.currentTarget){

I've double and triple checked my code and cant find a problem, what am i missing? my code is as follows:
stop();

// Start Main Nav

function openLabel(Event:MouseEvent):void {
switch (event.currentTarget) {
case home_btn :
gotoAndStop("home");
break;
case aboutMe_btn :
gotoAndStop("aboutMe");
break;
case services_btn :
gotoAndStop("services");
break;
case portfolio_btn :
gotoAndStop("portfolio");
break;
case contact_btn :
gotoAndStop("contact");
break;
}
}

home_btn.addEventListener(MouseEvent.CLICK, openLabel);
aboutMe_btn.addEventListener(MouseEvent.CLICK, openLabel);
services_btn.addEventListener(MouseEvent.CLICK, openLabel);
portfolio_btn.addEventListener(MouseEvent.CLICK, openLabel);
contact_btn.addEventListener(MouseEvent.CLICK, openLabel);

// End Main Nav

snickelfritz
08-17-2009, 03:38 AM
You said that any eligible displayObject in dragdrop_mc will have the drag/drop function, but what I was trying to say before was what if we decided to assign the object to a new layer or movie clip (for instance, perhaps one of the background frames, or a new movie clip altogether). In a situation like that would drag/drop still function, or would there need to be event listeners for the new movie clip?

I hope that makes sense?

The dragdrop function is not strictly limited to the event listener assigned to dragdrop_mc; you can call this function from other listeners as well.
So for example, you add an object to the background_mc, and you wish the object to be draggable: simply add a mouse event listener to background_mc and call the pickup/dropit functions.
I haven't tested this specifically, but I see no reason why it wouldn't work.

GeorgeHK
08-17-2009, 08:54 AM
Hello All!

function openLabel(Event:MouseEvent):void {
switch (event.currentTarget) {
case home_btn :


First line uses Event. Second line used event. Simple capitalisation error. Don't worry, we all do it occcasionally ;-)

G.

Mickstah
08-19-2009, 09:57 AM
Okay I thought I was making good headway (I managed to add a sweet scroll function to contain all the drag/drop objects). The only problem with this is that they are masked and contained on that scrolling layer.

So I thought if I added an event listener to background_mc to handle the drag drop (works fine, but also moves the background even though it isn't a movieclip!) then set the childIndex to the background_mc depth on pickup (if I add it to drop then I would just get weird stuff happening to the scrollbox) then I'd be right, but it seems I'm not using the childIndex correctly.

background_mc.stop();
var targetID:int;
var n:int = buttons_mc.numChildren;

for (var i:int = 0; i < n; i++)
{
var b:MovieClip = MovieClip(buttons_mc.getChildAt(i));
b.gotoAndStop(i + 1);
b.buttonMode = true;
b.id = i;
b.addEventListener(MouseEvent.CLICK, btnClick);
}

function btnClick(e:MouseEvent):void
{
targetID = int(e.currentTarget.id + 1);
background_mc.gotoAndStop(targetID);
}

background_mc.addEventListener(MouseEvent.MOUSE_DO WN, pickUp);
background_mc.addEventListener(MouseEvent.MOUSE_UP , dropIt);
dragdrop_mc.addEventListener(MouseEvent.MOUSE_DOWN , pickUp);
dragdrop_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt);

function pickUp(e:MouseEvent):void
{
dragdrop_mc.addChild(MovieClip(e.target));
e.target.startDrag();
this.setChildIndex(background_mc.getChildAt(i));
}

function dropIt(e:MouseEvent):void
{
e.target.stopDrag();
}

I realise that adding event listeners to background_mc will mean that the objects will be getting reassigned childIndexes, but this shouldn't cause any conflicts assuming they're just going to stay on the same layer anyway?

And how do I get the background layer to stop moving, would it be best just to move the objects to another clip over the top of the background_mc instead or is this just adding unnecessary elements tot he stage?