AS3 forlooping buttons and functions - actionscript-3

I'm learning Actionscript and I'm kind of stuck on for loop.
I have this code ,
movieClip.thumbnail1.addEventListener(MouseEvent.CLICK ,myBtn1);
function myBtn1(evt:MouseEvent):void
{
var myMC:MC1 = new MC1();
mcPlacement.addChild(myMC);
}
movieClip.thumbnail2.addEventListener(MouseEvent.CLICK ,myBtn2);
function myBtn2(evt:MouseEvent):void
{
var myMC2:MC2 = new MC2();
mcPlacement.addChild(myMC2);
}
and I am wondering, how do you use for loop to stack them up so that I can run over 10 buttons without having to type the long way, should I make use of arrays as well?

If movieClip contains only the thumbNails that you want to add event listeners for then you can do :
private function addEventListeners():void
{
for(var i=0; i<movieClip.numChildren; i++)
{
var dp:DisplayObject = movieClip.getChildByIndex(i) as DisplayObject;
dp.addEventListener(MouseEvent.CLICK,onThumbNailClicked);
}
}
private function onThumbNailClicked(e:MouseEvent):void
{
trace("Clicked : "+e.target.name);
}
If you know the names of the thumbnails before hand you can create different movie clips inside the event handler and add them to mcPlacement.
private function onThumbNailClicked(e:MouseEvent):void
{
var mcs:Object = {
"thumbNail1":MC1,
"thumbNail2":MC2
};
trace("Clicked : "+e.target.name);
var mc:MovieClip = new mcs[e.target.name]();
mcPlacement.addChild(mc);
}

Related

Actionscript 3 Call to a possibly undefined method

Here is the problem, the object is moved together with the clicked object. I want it to be moveable following the mouse pointer, but let the clicked object stays. so when an object is clicked, there will be 2 objects in the stage(the static and moving one).
I think I've figured it out by adding a new object to be moved. in function onClickHero I've tried movingHero = new heroes but it says "call to a possibly undefined method heroes". My question is there any other way how to make another clone of the clicked object since I made it in array? And why does movingHero = new heroes doesn't work?
I'm still amateur at classes. Sorry if it's messed up. Thanks for helping.
package {
import flash.display.MovieClip
import flash.events.MouseEvent
import flash.events.Event
import flash.display.Sprite
public class Hero {
private var heroesArray:Array;
private var heroContainer:Sprite = new Sprite;
private var hero1:MovieClip = new Hero1();
private var hero2:MovieClip = new Hero2();
private var moveHero:Boolean = false;
private var movingHero:MovieClip;
private var _money:Money = new Money();
private var _main:Main;
public function Hero(main:Main)
{ _main = main;
heroesArray = [hero1,hero2];
heroesArray.forEach(addHero);
}
public function addHero(heroes:MovieClip,index:int,array:Array):void
{
heroes.addEventListener(Event.ENTER_FRAME, playerMoving);
heroes.addEventListener(MouseEvent.CLICK, chooseHero);
}
public function playerMoving(e:Event):void
{
if (moveHero == true)
{
movingHero.x = _main.mouseX;
movingHero.y = _main.mouseY;
}
}
public function chooseHero(e:MouseEvent):void
{
var heroClicked:MovieClip = e.currentTarget as MovieClip;
var cost:int = _main._money.money ;
if(cost >= 10 && moveHero == false)
{
_main._money.money -= 10;
_main._money.addText(_main);
onClickHero(heroClicked);
moveHero = true;
}
}
public function onClickHero(heroes:MovieClip):void
{
movingHero = heroes;
heroContainer.addChild(movingHero);
}
public function displayHero(stage:Object):void
{
stage.addChild(heroContainer);
for (var i:int = 0; i<2;i++)
{
stage.addChild(heroesArray[i]);
heroesArray[i].x = 37;
heroesArray[i].y = 80+i*70;
heroesArray[i].width=60;
heroesArray[i].height=55;
heroesArray[i].buttonMode = true;
}
}
}
}
EDIT: I've tried to make movingHero = new Hero1(); but since I don't know which hero will be clicked so I can't just use Hero1 from library. and If I use movingHero = heroClicked I only get the value of hero1 which is a var from Hero1 movieclip. So, is there any way to call the movie clip from library the same as which hero was clicked in stage?
You seemingly want to clone an object while not knowing its type. If that object also containg game logic, it's not the best idea to say spawn new heroes of either type, this might make a mess of your code. But if not, you can get the exact class of the object given, and make an object of that class via the following code:
public function onClickHero(heroes:MovieClip):void
{
if (!heroes) {
trace('heroes is null!');
return;
}
var heroClass:Class = getDefinitionByName(getQualifiedClassName(heroes)) as Class;
movingHero = new heroClass(); // instantiate that class
heroContainer.addChild(movingHero);
// movingHero.startDrag(); if needed
}
Don't forget to clean up the movingHero once it's no longer needed.

Flash remove child from timer

I have 25 objects of movie clip class named drone, and when i click it, after 2 seconds I want the object to disappear. I also have 25 timers named countdown. Here is what i do:
function clickHandler (event:MouseEvent):void{
event.currentTarget.hp--;
if(event.currentTarget.hp <= 0)
{
for(var i:int = 0;i<25;i++)
{
if(event.currentTarget == _drone[i])
{
countdown[i].start(); //start timer
}
}
}
}
Here is my timer:
for(var i:int = 0;i<25;i++)
{
countdown[i] = new Timer(2000);
countdown[i].addEventListener(TimerEvent.TIMER,timerHandler);
}
function timerHandler(e:TimerEvent):void {
//remove the drone I clicked
//I also dont know which drone i'm clicking
}
What should I do in the timerHandler to remove the object I clicked?
You can use Dictionary. Use the timer as key and movielcip as value.
import flash.utils.Dictionary;
var dict:Dictionary = new Dictionary();
function clickHandler (event:MouseEvent):void{
event.currentTarget.hp--;
if(event.currentTarget.hp <= 0)
{
for(var i:int = 0;i<25;i++)
{
if(event.currentTarget == _drone[i])
{
dict[countdown[i]] = _drone[i];//set the target mc here
countdown[i].start(); //start timer
break;
}
}
}
}
function timerHandler(e:TimerEvent):void {
var mc:MovieClip = dict[e.target] as MovieClip;//get the object been clicked
if (mc && mc.parent) {
mc.parent.removeChild(mc);//remove it
}
}
With minimal changes, set up an array to track the drones:
var arrayToRemove:Array = new Array();
and then in the click handler store drones to be removed in there:
arrayToRemove.push(event.currentTarget);
and in the timerHandler just remove the first element of the array:
removeChild(arrayToRemove.shift());
Since every delay is the same the order of the events and removals will be preserved. Although, it would probably be better to generalize the code using the above example and store all drones and timers in an arrays, so you can have any number of them.

1120: Access of undefined property shuffledArray

Please can you help me out I am new to as3 and I am trying to create a shuffled deck using the Fisher-Yates Algorithm. When I run the code with ctrl-enter it compiles with no errors but when I try to output it with trace(); it comes back with:
Scene 1, Layer 'actions', Frame 1, Line 6 1120: Access of undefined property shuffledArray.
Like I said I am new to this and it will be me doing something very stupid but all the same i'm stuck.
Here is the code
package src.CardDeck
{
public class CardDeck
{
public var allCards:Array = [];
public var cardNames:Array;
public var cardValues:Array;
public var gameType:String;
public var drawnCards:uint = 0;
public function CardDeck(game:String)
{
gameType = game;
cardNames = ["Ace","Two","Three",
"Four","Five","Six",
"Seven","Eight","Nine",
"Ten","Jack","Queen","King"];
if(gameType == "texasholdem")
{
cardValues = [1,2,3,4,5,6,7,8,9,10,10,10,10];
}
makeSuit("Spade");
makeSuit("Heart");
makeSuit("Diamond");
makeSuit("Club");
}
function makeSuit(suitString:String):void
{
var card:Object;
for(var i:uint = 0; i < cardNames.length; i++)
{
card = {};
card.cardType = suitString;
card.cardName = cardNames[i];
card.cardValue = cardValues[i];
card.isDrawn = false;
allCards.push(card);
}
}
public function shuffleFisherYates():Array
{
var shuffledArray:Array = [];
var randomCardIndex: int;
do
{
randomCardIndex = Math.floor(Math.random()* allCards.length);
shuffledArray.push(allCards[randomCardIndex]); // add to mix
allCards.splice(randomCardIndex,1); // remove from deck
}while(allCards.length); // Meaning while allCards.length != 0
return shuffledArray;
}
}
}
and here is the .fla actions layer
import src.CardDeck.CardDeck;
var deck:CardDeck = new CardDeck("texasholdem");
trace(shuffledArray);
I know its probably something silly but i'm struggling.
Thanks in advance!
Paul
var deck:CardDeck = new CardDeck("texasholdem");
trace(shuffledArray);
This doesn't work because shuffledArray isn't defined there.
Try :
var deck:CardDeck = new CardDeck("texasholdem");
var array:Array = deck.shuffleFisherYates();
for(var i:int=0; i<array.length; i++)
{
trace(array[i].cardName);
trace(array[i].cardType);
trace(array[i].cardValue);
trace(array[i].isDrawn);
}
"shuffledArray" is a property inside of your CardDeck object. To access public methods and properties within it, you need to use the dot syntax:
trace(deck.shuffleFisherYates());
However, depending on what you are doing, you may not need to really be accessing the array directly, if your CardDeck object is meant to control the entire deck.

AS3 Creating an array of objects

I would like to add a bunch of cars to the stage, and store them in an array as objects. The problem is I hate using external AS files and would like to keep it as simple as possible.
I tried doing :
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
var test:Array = new Array()
for (var i:Number=0; i<10; i++) {
test.push(car)
}
The problem is if I try to set a value of one object in the like
test[1].carscale = 5
Every object in the array gets their attribute carscale set to 5.
Is there any way I can do this without using external class files?
While you should use external AS files (its a good practice), here's the reason why you are having the issue, and I'm going to explain line-by-line
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
//This creates an object called car. Suppose it saves it in memory at "location" 0x12345
var test:Array = new Array();
//This creates an empty array
for (var i:Number=0; i<10; i++) {
test.push(car);
//This adds the object "car" to the array
//Since Object is a reference type, its memory location is actually added to the array
//This means you added 0x12345 to the array (10 times over the loop)
}
//The array now contains
[0x12345, 0x12345, 0x12345, .......];
//So now
test[1]; //returns the object at 0x12345
test[1].carscale=5; //sets the carscale property of the object at 0x12345
Since all objects in the array point to the same location, getting any of them will actually return the same object. This means that all of them will show carscale as 5
A solution to this would be:
var test:Array = new Array();
for (var i:Number=0; i<10; i++) {
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
test.push(car);
}
A better, REAL Object oriented solution would be to create a class called Car and then instead of doing
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
you use
var car:Car = new Car();
The Car.as class would be like this:
public class Car {
public function Car() {
//this is the constructor, initialize the object here
//Suppose the default values of the car are as follows:
carcolor="red";
carscale=5;
carpower=1000;
}
public var carcolor:String;
public var carscale:Number, carpower:Number;
}
In fact, you could even use another constructor that automatically sets the properties based on arguments:
public function Car(_color:String, _scale:Number, _power:Number) {
carcolor=_color;
carscale=_scale;
carpower=_power;
}
and call it as
var car:Car=new Car("red", 5, 1000);
In fact, the car before carcolor, carscale and carpower is not even necessary because it is obvious when you put them in a class called Car.
Like TheDarkIn1978 said you're pushing a reference of your car instance into your array. When you change the value of one instance's property the same happens for each reference.
The simple answer is to create a new object upon each interation of your for loop like in the following:
var test:Array = [];
for (var i:Number = 0; i < 10; i++)
{
var car:Object = {carcolor:String, carscale:Number, carpower:Number};
test.push(car);
}// end for
[UPDATE]
I know you said that you didn't want to use "external classes" but there are advantages to using a custom class object to store values as opposed to a Object object. Here is an example:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var cars:Vector.<Car> = new Vector.<Car>();
cars.push(new Car("red", 1, 1));
cars.push(new Car("blue", 2, 2));
cars.push(new Car("green", 3, 3));
trace(cars[2].color); // output: green
}// end function
}// class
}// end package
internal class Car
{
private var _color:String;
private var _scale:Number;
private var _power:Number;
public function get color():String { return color; }
public function get scale():String { return scale; }
public function get power():String { return power; }
public function Car(color:String, scale:Number, power:Number)
{
_color = color;
_scale = scale;
_power = power;
}// end function
}// end class
This is a good example of creating an object for the sole purpose of storing values that never change by only allowing the object's properties to be set upon initiation and using getter methods to make the values read only.
I feel dumb, I found the answer here :
http://board.flashkit.com/board/showthread.php?t=792345
You're pushing the Object reference to the array, not a unique Object each time. You have to do something like:
for(var temp=0;temp<100;temp++){
var roomData:Object=new Object;
roomData.first_time=true;
rooms.push(roomData);
}
you're adding the same object to the array multiple times. you need to create new instances of your car object.
EDIT:
although it would be a best practice to create your own "Car" class and create new instances of it, even if it's only a small object with 3 properties, here's a quick example that should get you started.
package
{
//Imports
import flash.display.Sprite;
//Class
public class Main extends Sprite
{
//Constants
private static const DEFAULT_CAR_COLOR:Number = 0x000000;
private static const DEFAULT_CAR_SCALE:Number = 1.0;
private static const DEFAULT_CAR_POWER:int = 50;
//Properties
private var carsArray:Array;
//Constructor
public function Main():void
{
init();
outputCarColors();
}
//Initialize
private function init():void
{
carsArray = new Array();
for (var i:int = 0; i < 10; i++)
{
carsArray.push(CreateCar(Math.random() * 0xFFFFFF));
}
}
//Output Car Colors
private function outputCarColors():void
{
for (var i:int = 0; i < carsArray.length; i++)
{
trace("Color of car " + i + " : " + carsArray[i].carColor);
}
}
//Create Car Object
private function CreateCar(carColor:Number = DEFAULT_CAR_COLOR, carScale:Number = DEFAULT_CAR_SCALE, carPower:int = DEFAULT_CAR_POWER):Object
{
var result:Object = new Object();
result.carColor = carColor;
result.carScale = carScale;
result.carPower = carPower;
return result;
}
}
}

Add an array of Movie Clips to a filter ActionScript 3

i stored 8 mc's in an array an i put them on the stage.
now I want to apply to these mc's a blur effect.
My problem is that i don't know how to apply for every mc the blur effect by clicking on it.
So for example I have all the mc's on the stage and if I click on one of them the clicked one should have the blur effect and so on.
How to apply the filter to the mc's?
Thank you for you time
You can loop through the mc's array and add event listeners on each of them:
var mcArrayLength:int = mcArray.length();
for (var i:int = 0; i < mcArrayLength; i++) {
var mc:MovieClip = mcArray[i] as MovieClip;
mc.addEventListener(MouseEvent.CLICK, onMcClick);
}
and the event handler:
function onMcClick(e:MouseEvent):void
{
var clickedMc:MovieClip = e.currentTarget as MovieClip;
clickedMc.filters = [myBlurFilter];
}
of course, if you wanted to have only one blurred mc at a time, you should keep a reference to it and remove blur once another mc is clicked:
var currentlyClickedMc:MovieClip;
function onMcClick(e:MouseEvent):void
{
var clickedMc:MovieClip = e.currentTarget as MovieClip;
clickedMc.filters = [myBlurFilter];
if (currentlyClickedMc) currentlyClickedMc.filters = [];
currentlyClickedMc = clickedMc;
}
something like this (untested) should work:
package
{
//Imports
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
//Class
public function ClickToBlur
{
//Variables
private var clickableObjects:Array;
//Constructor
public function ClickToBlur(clickableObjects:Array)
{
this.clickableObjects = clickableObjects;
init();
}
//Initialize
private function init():void
{
for each (var object:Object in clickableObjects)
{
object.addEventListener(MouseEvent.CLICK, clickMouseEventHandler);
}
}
//Click Mouse Event Handler
private function clickMouseEventHandler(evt:MouseEvent):void
{
if (evt.currentTarget.filters == [])
{
evt.currentTarget.filters = [new BlurFilter()];
}
else
{
evt.currentTarget.filters = [];
}
}
//Dispose
public function dispose():void
{
for each (var object:Object in clickableObjects)
{
object.removeEventListener(MouseEvent.CLICK, clickMouseEventHandler);
}
}
}
}
just pass your array to a new instance of the class
var ctb:Object = new ClickToBlur(myArrayOfObjects);
and clean up when your done:
ctb.dispose();
since they're all Movie Clips, you should use a Vector instead of an Array.