Writing an 'if' statement in ActionScript - actionscript-3

Is there a way of writing an if statement that involves the following?
if (MovieClip1 reaches last frame)
{
addChild(MovieClip2)
removeChild(MovieClip1)
}
Basically, all I want to happen is when my MovieClip finishes, it will change to another MovieClip or image. I know it is probably very simple, but how can I do it?

All code runs on command. So your conditional will run immediately and never run again.
Instead, you use events. You attach a listener to an event and when that event fires (is "dispatched" to use correct vocabulary), your code is called again.
var movieClip:MovieClip = new MovieClip();
movieClip.addEventLister( Event.ENTER_FRAME, this.enterFrameHandler ); //will be called on every frame enter
function enterFrameHandler( e:Event ):void {
if ( movieClip.currentFrame == movieClip.totalFrames ) {
// do something
}
}
So you listen for each new frame and in that handler, you check if it is the last frame or not.
As an extra tidbit, the standard naming convention for AS3 is to use lowercase, camelcase (thisIsAnExampleOfthat) for all objects. Package names should be in all lowercase and only Class names should be capitalized.

package
{
import flash.display.MovieClip;
import flash.events.KeyboardEvent;
import flash.events.Event;
public class Main extends MovieClip
{
var firstScene:FirstScene = new FirstScene;
var movement:Movement = new Movement;
var green:Green = new Green;
public function Main()
{
addChild(firstScene);
firstScene.addEventListener(KeyboardEvent.KEY_DOWN, mClick);
movement.addEventListener(Event.ENTER_FRAME, endChange);
}
function mClick(event:KeyboardEvent):void
{
if (event.keyCode == 77);
{
addChild(movement);
removeChild(firstScene);
}
}
function endChange(event:Event):void
{
if (movement.currentFrame == movement.totalFrames)
{
addChild(green);
removeChild(movement);
}
}
}
}

Related

Custom events not working in AS3

I have an event called SelectEvent. Whenever I click the buyer, the select event should be launched. But that is not what is happening.
My code of base:
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
public class FashionFrenzy extends MovieClip
{
public var Buyer_mc:Buyer;
public var Buyers:Array;
private var BuyerNumber:Number;
public var xpositions:Array;
public var ypositions:Array;
public var SelectedBuyer:Number;
public function FashionFrenzy()
{
GameTimeController();
xpositions=new Array();
xpositions.push(523,563,603);
ypositions=new Array();
ypositions.push(377,377,377);
Buyers = new Array ;
BuyerNumber=0;
Time_mc.gameTimer.addEventListener(TimerEvent.TIMER,GenerateBuyers);
addEventListener(SelectEvent.BUYERSELECT,showselectbuyer);
}
public function GameTimeController()
{
Time_mc.StartGame();
}
public function showselectbuyer(event:SelectEvent):void
{
trace("Bamba");
}
public function GenerateBuyers(event:TimerEvent):void
{
if(BuyerNumber<6)
{
if (Math.random() < 0.01)
{
var position:Number = Math.floor(Math.random()*3);
var newBuyer_mc = new Buyer(xpositions[position],ypositions[position],BuyerNumber);
ypositions[position]-=40;
Buyers.push(newBuyer_mc);
addChild(newBuyer_mc);
BuyerNumber++;
}
}
for each (var buyer_mc:Buyer in Buyers)
{
if(buyer_mc.walking==true)
{
buyer_mc.Enter();
}
}
}
}
}
My code of the buyer:
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
public class Buyer extends MovieClip
{
public var buyerTimer:Timer;
public var walking:Boolean;
public var stopposition:Number;
public var buyerCode:Number;
public function Buyer(startx:Number, stopy:Number, code:Number)
{
x=startx;
stopposition=stopy;
walking=true;
buyerCode=code;
BuyerProperties();
}
public function Enter():void
{
if(y>stopposition)
{
walking=false;
StartFunction();
}
else
{
y= y+3;
}
}
public function BuyerProperties():void
{
buyerTimer = new Timer( 25 );
trace(" I am generated");
}
public function StartFunction():void
{
buyerTimer.start();
addEventListener(MouseEvent.CLICK,Select);
trace("My timer starts now within Buyer.as");
}
public function Select(event:MouseEvent):void
{
trace(buyerCode);
dispatchEvent( new SelectEvent(SelectEvent.BUYERSELECT));
}
}
}
Now that when I'm clicking the buyer, the MouseEvent.CLICK is activated and then in the buyer.as, buyercode is traced on the screen. But the event is not dispatched or else it is dispatched but the eventlistener is not executing the code. I'm not getting any runtime errors. the function "showselectbuyer" is never even launched.
How should I solve it?
The accepted answer is incorrect. The provided solution works but for the wrong reasons. It creates a direct dependency to the object supposed to listen to the custom event and then makes that object be the dispatcher. All together this makes the whole idea of using event/custom event unnecessary at best since in that case a simple callback would work just as well. Instead using the useCapture flag would make the whole system work as expected:
addEventListener(SelectEvent.BUYERSELECT,showselectbuyer, true);
The accepted solution is also the inverse way of dealing with non DisplayObject event propagation. The dispatcher should be the listener (no dependencies) and not the listener should be the dispatcher (dependency necessary).
The trouble with custom events is that they don't bubble up the display list, so in case your event to be registered you need to dispatch it to the class instance that has a listener to that event attached. In your case it's an instance of FashionFrenzy. Apparently buyers don't know about a fashion frenzy instance they are running in, so they dispatch the event to themselves and wonder why no one else listens. In order to resolve this, either attach the listener to the buyer, or in the buyer class dispatch the event to parent, which is apparently the instance you want to receive the event.

AS3: class not functioning properly

Sorry for a blurry title, but this is probably the best way I can describe the issue that seems absurd to me by now.
I need a simple action done by an MC: going to a certain frame. I couldn't get it to work, although I had an exact same type of action done by another Movie Clip in the same class code. Here's how I did it:
if (currentItem.type == "blue") {
guy.gotoAndPlay("blue")
}
Yes, the class I'm referring to ('guy') is extended as a Movie Clip. Again, exact same code works fine with other Clips. I tried another method: switching the frame from the Clip's class, the frame it switches to is defined by a variable which is changed by main class. But somehow, this doesn't work either. It gives me the 1069 error. Here's the code of the 'guy' class:
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class guy extends MovieClip
{
public static var gotoer:String = "fffuuu"
public function shaman_armsUp()
{
super();
addEventListener(Event.ADDED_TO_STAGE, init)
}
public function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init)
armLoop()
}
public function armLoop():void {
if (gotoer == "brown") {
this.gotoAndPlay("brown")
}
if (gotoer == "red") {
trace(gotoer)
this.gotoAndPlay("red")
}
}
}
}
Is there anyone who has a logical explanation for this? Can this be caused by a bug?
maybe the code you are writing in the method shaman_armsUp() should be moved to the constructor?
Follow my edited version of your class guy (also, renamed to Guy, follow the class name convention)
package
{
import flash.display.FrameLabel;
import flash.display.MovieClip;
import flash.events.Event;
// renaming the class name (guy to Guy)
public class Guy extends MovieClip
{
// not sure if using an static variable for this case is the best idea, but I decided to keep because I don't know your initial idea
public static var gotoer:String = "fffuuu";
public function Guy()
{
// move the addedToStage event to the constructor
super();
addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
}
public function shaman_armsUp()
{
}
public function init(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
armLoop();
}
public function armLoop():void
{
// Note: the value of gotoer is "fffuuu" and there is no conditional for it.
// are you chaging this value before calling armLoop? because when the init method is called it has the same value
// why not try something like:
// checking if the frame exist and if so, calling the gotoAndPlay method (try to imagine if you have 100 frame names? the old approach will be very hard to maintain
if (hasFrameLabel(gotoer))
{
this.gotoAndPlay(gotoer);
}
else
{
trace('frame: ', gotoer, ' not found');
}
/*
if (gotoer == "brown")
{
this.gotoAndPlay("brown");
}
if (gotoer == "red")
{
trace(gotoer);
this.gotoAndPlay("red");
}
*/
}
// helper function to avoid calling a frame that doesn't exist
private function hasFrameLabel(frameLabel:String):Boolean
{
var returnValue:Boolean;
const obj:Object = this.currentLabels;
for each (var i:FrameLabel in obj)
{
if (i.name == frameLabel)
{
returnValue = true;
break;
}
}
return returnValue;
}
}
}

Access of undefined property issues in AS3

I am having a bit of trouble with some AS3. First time using this language and have more experience with web development then OOP so am getting a bit confused.
I am trying to make it so that when someone clicks a 'powerbutton' which is a "movieclip" symbol within flash then another symbol should then become visible. This is all being done within the Kitchen class.
The code for the main class is which i got from a youtube tutorial video i followed;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
public function DragFood() {
myKitchen = new Kitchen;
originalPosition = new Point (x, y);
buttonMode = true;
addEventListener (MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent):void
{
parent.addChild(this);
startDrag();
stage.addEventListener (MouseEvent.MOUSE_UP, stageUp);
}
protected function stageUp (event:MouseEvent):void
{
stage.removeEventListener (MouseEvent.MOUSE_UP, stageUp);
stopDrag();
if (dropTarget)
{
if(dropTarget.parent.name == "bowl")
{
trace("The " + this.name + " is in the bowl");
this.visible = false;
} else {
returnToOriginalPosition();
}
} else {
returnToOriginalPosition();
}
}
protected function returnToOriginalPosition():void
{
x = originalPosition.x;
y = originalPosition.y;
}
}
}
Within it i call the other class;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
The code for the kitchen class is;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Kitchen extends MovieClip
{
// This is a function. This particular function has the same name as our class and therefore will be executed first
public function Kitchen()
{
// This is a "call" to another function that is defined later in the program.
init();
trace("Hello world");
}
public function init():void
{
// If we want an object (on the screen or otherwise) to be notified about an event we must add a listener for that event to that object.
// We also need to specify what happens everytime the event we are listening for happens.
PowerButton.addEventListener(MouseEvent.CLICK, handleButtonClicks);
}
//This function is called when the oven on button recieves a click.
public function handleButtonClicks(event:MouseEvent):void
{
OvenOn.visible = true;
trace("the oven is being switched on");
}
}
}
The issue i keep getting is that OvenOn and PowerButton are giving me a undefined access issue and im not sure how to fix it. I have found posts on similar subjects like - Access of Undefined property? Actionscript 3
but im not quite sure how to apply it to my issue if anyone could offer any help that would be great.
When you're programming on the timeline, code is referencing the local namespace, and objects you make there (movieclips, textfields, etc.) are automatically instantiated in that namespace so that you can simply call OvenOn.visible = true. However, for each class, their local namespace is whatever is inside the class, so unless you actually created a property on your class called OvenOn, it will most definitely give you Access of Undefined Property errors.
Think of each class as its own island. For them to touch eachother, they need some sort of connection. That connection can be made once the parent instantiates the class in its own namespace. For example...
var foo:String = "Hello!";
var bar:MyClass = new MyClass();
// At this point, whatever code runs inside of MyClass has no concept of foo, or how to access it.
addChild(bar);
// Now that we've added it to the stage, the bar has some properties that have automatically been populated such as "root", "parent", or "stage".
foo.someProperty = "World";
// Since this namespace has a variable pointing to the instance, we can change properties on that class.
Now that we've instantiated MyClass on the stage, we can reference parent properties the class didn't know about. Mind you, this is not necessarily best practice.
package
public class MyClass extends MovieClip {
var someProperty:String = "cheese";
public function MyClass() {
trace(parent.foo) // this will fail
addEventListener(Event.ADDED_TO_STAGE, test);
}
public function test(e:Event):void {
trace(this["parent"].foo); // this will succeed
}
}
}
If you absolutely must change something that is not part of your Kitchen class, pass either the parent of OvenOn or that object specifically as a property of Kitchen. You could do this a couple ways.
with the Constructor...
var something:*;
public function MyClass(someObject:*) {
something = someObject;
}
public function test():void {
something.visible = false;
}
...or by Assigning the Property...
var bar:MyClass = new MyClass();
bar.something = OvenOn;
bar.test(); // will turn off the OvenOn now that 'something' is pointing to it.

How to improve this AS3 code structure to be more effective?

I have made an AS3 code to be a function. But I think my code is too lengthy. Could you help to improve it? Thank you!
I created test.fla first and added 5 grey block(external pictures from PSD) to stage. My function is to display different pictures when hovering mouse on corresponding grey block.
I converted those 5 grey blocks to Movie Clip and set instance name as sp1, sp2, sp3, sp4 and sp5. Then I created a document class, test.as and set 5 EventListener.
sp1.addEventListener(MouseEvent.MOUSE_OVER,clickmouse1);
sp2.addEventListener(MouseEvent.MOUSE_OVER,clickmouse2);
sp3.addEventListener(MouseEvent.MOUSE_OVER,clickmouse3);
sp4.addEventListener(MouseEvent.MOUSE_OVER,clickmouse4);
sp5.addEventListener(MouseEvent.MOUSE_OVER,clickmouse5);
So my first question is can I have any method to combine those 5 EventListener to be one? Because in my mind, so many EventListener will cost much more resource of PC.
My second question is I set 5 target pictures as 5 class.
In test.as I created code below:
public class EuroCup extends Sprite{
var arr:Array=new Array();
var Res1:Result609=new Result609();
var Res2:Result610=new Result610();
var Res3:Result611=new Result611();
var Res4:Result612=new Result612();
var Res5:Result613=new Result613();
var i:int=0;
public function EuroCup() {
arr[1]=Res1;
arr[2]=Res2;
arr[3]=Res3;
arr[4]=Res4;
arr[5]=Res5;
}
}
I think that is too lengthy. Is there any way to simplify it?
Here is the test.fla and test.as:Download
Whatever, thank u guys!
Restructuring:
public class EuroCup extends Sprite {
private var arr:Array;
public function EuroCup() {
arr = [ new Result609(), new Result610(),
new Result611(), new Result612(), new Result613()
];
}
}
Then use results as arr[0], arr[1] and so on. Also, if you have several sprites to listen clicks on, with similar listeners, you can connect all such sprites to single listeners and use event.target to distinguish them, where event is MouseEvent. Or place them into container and create one listener to that container - again, event.target will tell what sprite is clicked.
And yet two things - every time you see new Array(), replace it with [] - its faster and shorter. And place all code into constructor, not class body - it will be compiled to be executed faster.
You can/should use a Dictionary for associations between the grey rects and the images to display.
package {
public class EuroCup {
private var _children:Array, _current:Sprite, _map:Dictionary;
public function EuroCup() {
super();
initialize();
}
protected function initialize():void {
_children = [];
_map = new Dictonary();
// i don't know the image's symbol name.
// _map[_children[_children.length] = new Result609()] = new SYMBOL_NAME();
for each(var child:Sprite in _children) {
child.addEventListener(MouseEvent.CLICK, click_handler);
}
}
private function click_handler(event:MouseEvent):void
{
if (_current) {
_current.visible = false; // or use fading, etc
}
_current = _map[event.currentTarget] as Sprite;
if (_current) {
_current.visible = true; // or use fading, etc
}
}
}
}
One option for simplifying the code would be to associate the sp and Res instances with each other by identity, using a Dictionary. That allows you to avoid the work of tracking array indices, which is half of the reason you have separate event handler methods. Once the instances are associated by identity, then you can use the currentTarget property of a dispatched event to determine which element in the Dictionary you want to show on the stage.
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.utils.Dictionary;
public class test extends Sprite
{
var dict:Dictionary = new Dictionary();
var visibleResult:MovieClip;
public function test()
{
dict[sp1]=new Result609();
dict[sp2]=new Result610();
dict[sp3]=new Result611();
dict[sp4]=new Result612();
dict[sp5]=new Result613();
sp1.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp2.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp3.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp4.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp5.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
}
private function clickmouse(evt:MouseEvent):void
{
if(visibleResult)
{
removeChild(visibleResult);
}
var Res:MovieClip = dict[evt.currentTarget] as MovieClip;
addChild(Res);
Res.x=300;
Res.y=400;
visibleResult=Res;
}
}
}
If you expect to have more than 5 sp instances in the application, then you could use a loop to assign the event listeners. But for less than 10 instances, you probably don't gain much from a loop.
I would go for a more simple version; add only one event listener and use Event.target to determine on which item is clicked, using a switch-statement.
This is helpful if the buttons should do different things.
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Test extends Sprite
{
public var sp1:Sprite;
public var sp2:Sprite;
public var sp3:Sprite;
public function Test()
{
this.addEventListener(MouseEvent.MOUSE_OVER, handleClick);
}
private function handleClick(event:MouseEvent):void
{
trace("Clicked on: " + event.target)
switch (event.target)
{
case this.sp1:
{
// do something here
break;
}
case this.sp2:
{
// do something here
break;
}
case this.sp3:
{
// do something here
break;
}
default
{
trace("No handler defined for: " + event.target)
}
}
}
}
}
However, you can also make smart use of it's type. Let's say all you buttons extend a custom class called CustomButton, and they all need to do the same (like call a function), but with a parameter based on it's id.
This is helpful if the buttons should basically do the same thing.
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Test extends Sprite
{
public function Test()
{
this.addEventListener(MouseEvent.MOUSE_OVER, handleClick);
}
private function handleClick(event:MouseEvent):void
{
if (event.target is CustomButton)
{
var button:CustomButton = event.target as CustomButton; // you're now sure it's a CustomButton
this.showById(button.id); // let's say CustomButton has a public var 'id'
}
}
private function showById(id:int):void
{
// do something
}
}
}
Hope that helps.
Tip: Always start your class+filename with a capital. Variables start with capitals. This is very common in the actionscript world.

Accessing Function on MovieClip from Document Class

[NOTE: Right off the bat, I already know the popular theory about "no code on MovieClips," so please don't reply with that (or
downvote because of it). Every project is different. I just need the answer.]
I have a project in Adobe Flash CS5.5, Adobe AIR 3, and ActionScript 3.
I need to call a function on the main timeline of the project that the document class is linked to from inside the document class. For the sake of example, let's call this function "Ring()".
How do I call this function, "Ring()" from inside my document class?
Put the function you want to call in your document class, and dispatch a custom event (or any event, if the code is readable) from the timeline of the object and listen for that event on your document class.
So the code breakdown would look like this:
On some frame of the timeline in your document (should work on any object):
var customEvent:Event = new Event(Event.COMPLETE);
this.dispatchEvent(customEvent);
In your document class:
public function DocumentClass()
{
// get the reference to the object
lolcats.objectThatDispatchesEvent.addEventListener(Event.COMPLETE, _customHandler);
}
protected function _customHandler(event:Event):void
{
// FUNCTION NAMES SHOULD START WITH LOWERCASE! ^_^
Ring();
}
http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html
Basically you register any string that defines your event, Event.COMPLETE evaluates to "complete", you can just register whatever you want, like:
var custEvent = new Event("anyCustomString");
this.dispatchEvent(custEvent);
// catch it with
addEventListener("anyCustomString", _handler);
Well, since you seem to be using some oldskool ninja techniques, I would suggest that you should keep it simple and straightforward.
Say you have some functions on the main timeline:
function Ring1():String
{
return "Ring1() called!";
}
var Ring2:Function = function () : String
{
return "Ring2() called!";
};
The scenario for a document class of the said timeline would be like this:
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.utils.getQualifiedClassName;
import flash.utils.describeType;
public class Test extends MovieClip
{
public function Test()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(event:MouseEvent):void
{
trace(getQualifiedClassName(this)+".onMouseDown()");
try {
var ring1:Function = this["Ring1"] as Function;
var ring2:Function = this["Ring2"] as Function;
} catch (error:Error) {
// ignore
}
if (ring1 != null) {
trace("\t", "Ring1", "=", ring1);
trace("\t", ring1());
} else {
trace("\t", "Ring1() function not found in "+this+"!");
}
if (ring2 != null) {
trace("\t", "Ring2", "=", ring2);
trace("\t", ring2());
} else {
trace("\t", "Ring2() function not found in "+this+"!");
}
// for your interest:
var doc:XML = describeType(this);
var ring1Node:XML = doc.descendants("method").(#name == "Ring1")[0];
var ring2Node:XML = doc.descendants("variable").(#name == "Ring2")[0];
trace("declaration of Ring1:", ring1Node.toXMLString());
trace("declaration of Ring2:", ring2Node.toXMLString());
// so, you may probably make use of reflection
// unless you need to reference dynamic members on the main timeline
}
}
}
See comments in the code above.