Flex - Objects within Objects - arrays

So I'm still trying to get my head around Flex and OOP and I am stuck right now. Here is the code I'm currently working with.
var labs:ArrayCollection = new ArrayCollection();
var sets:ArrayCollection = new ArrayCollection();
var labsArray:Array = ["ProDPI","WHCC","Tin"];
var setsArray:Array = [ ["Set01","Set02","Set03","Set04"],["Set11","Set12","Set13","Set14"], ["Set21","Set22","Set23","Set24"] ];
var objLab:Object = new Object;
objLab.labName = labsArray[0];
objLab.setFolders = undefined;
labs.addItem(objLab);
for (var i:int = 0; i < setsArray.length; i++) {
var objSets:Object = new Object;
objSets.setName = setsArray[i];
sets.addItem(objSets);
objLab.setFolders = objSets;
}
labFolderList.labelField="labName";
labFolderList.dataProvider=labs;
setFolderList.labelField="setFolders";
setFolderList.dataProvider=sets;
The objLab object is returning as I wish it to. The objSets is displaying in my ComboBox as object, Object. The application is ComboBox #1 will be populated by labsArray, which is working. Depending on the selection of [0,1,2] from the array this will call from the sets array the array in the matching position.
Finally, with the selection of the ComboBox#1, the second ComboBox#2 will change to the matching selection.
Any help on how to get the object Objects to rendering correctly would be of great help. Also if my execution is not the best way to do this any direction (links/documentation) I will take as well. Thanks in advance.

I edited your original code based on assumptions for what you were trying to accomplish, I added the Array objects directly to the collection being assigned the dataprovider, in this case you should see the output of the .toString() method called on the Array instead of the Object class, the Object class .toString() will output the [object Object] you were seeing in the display. The Array .toString() method will call .toString() on each element in the array and separate them with commas and surround them with curly braces, very similar to what you have when defining the array. Alternatively you could create your own class that extends Object and make your own toString method to override the default behavior, using Object is generally not a great practice (there are exceptions to this it's not a hard rule but it tends to be better to use a specific class type, or even better an interface when possible).
var labs:ArrayCollection = new ArrayCollection();
var sets:ArrayCollection = new ArrayCollection();
var labsArray:Array = ["ProDPI","WHCC","Tin"];
var setsArray:Array = [ ["Set01","Set02","Set03","Set04"],["Set11","Set12","Set13","Set14"], ["Set21","Set22","Set23","Set24"] ];
var objLab:Object = new Object;
objLab.labName = labsArray[0];
objLab.setFolders = undefined;
labs.addItem(objLab);
for (var i:int = 0; i < setsArray.length; i++) {
sets.addItem(setsArray[i]);
objLab.setFolders = setsArray[i];
}
labFolderList.labelField="labName";
labFolderList.dataProvider=labs;
setFolderList.labelField="setFolders";
setFolderList.dataProvider=sets;
Another alternative aside from making a Class as I explained above is to use the labelFunction instead of the labelField, using a labelFunction each item:Object in the dataProvider will be passed into your custom labelFunction and you can return a string based on whatever logic you see fit. It would be something along these lines:
setFolderList.labelFunction = myLabelFunction;
private function myLabelFunction(item:Object):String
{
var retString:String = "";
for(var i:int=0; i<item.setName.length; i++)
{
if(i>0)
retString += ", ";
retString += item.setName[i];
}
return retString;
}

Related

Use value from array to set addeventListner to multiple buttons

I'm making a game that have multiple instance of a MC in stage (a1,b1,c1....a2,b2,c2,d2,etc)
Every time to make a listener i have to write
Object(this).sopa.c1.btn.addEventListener(MouseEvent.CLICK, c1Click);
and create a function like this
function c1Click(event:MouseEvent):void
{
checkString += "c1";
var TFc1:TextFormat = Object(this).sopa.c1.letra.getTextFormat(0,1);
TFc1.color = 0xff0022;
Object(this).sopa.c1.letra.setTextFormat(TFc1);
check();
}
but whit that many buttons (more than 100) is to long writing them one by one.
So i think put the values (instance names) of the buttons in an array. Something like this
var casillas:Array = [a1, b1,c1];
for (var i:uint = 0; i < casillas.length; i++)
{
casillas[i].addEventListener(MouseEvent.CLICK, a1presion);
trace(casillas[i])
}
but i cant get the value of the array element just a [object SimpleButton].Have anyone any ideas how to do this: I'm new in as3 i worked all my life in as2 and this is way to hard to understand for me.
This is where Object Oriented Programming shines. You encapsulate all properties and methods into a single object. You can then create as many of these objects, and watch as they function individually with the behavior specified inside.
Here's a simple button class I sometimes use myself:
package buttons {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class SimpleButton extends MovieClip {
public function SimpleButton() {
addEventListener(MouseEvent.MOUSE_OVER, mOver);
addEventListener(MouseEvent.MOUSE_OUT, mOut);
addEventListener(MouseEvent.MOUSE_DOWN, mDown);
buttonMode = true;
}
protected function mOver(e:MouseEvent):void {
gotoAndStop(2);
}
protected function mOut(e:MouseEvent):void {
gotoAndStop(1);
}
protected function mDown(e:MouseEvent):void {}
}
}
Then create as many instances as you like, and store them in some container so that you can get rid of them at some point in the destruction of the program.
var buttons:Vector.<SimpleButton> = new Vector.<SimpleButton>();
buttons.push(new SimpleButton());
buttons.push(new SimpleButton());
buttons.push(new SimpleButton());
Firstly, I have to agree with Iggy, what you are trying to do will ultimately be more re-usable and easy to understand if it were written using Object Oriented code.
However, from what you have already written, I think you are saying is that you are struggling to create an event handler that is generic to all your buttons? So if you need to get the string name of the MovieClip as well as the actual clip reference maybe you could do something like this:
var casillas:Array = ["a1", "b1", "c1"]; //Have an array of the names of the buttons
for (var i:uint = 0; i < casillas.length; i++)
{
var mcReference:MovieClip = this.sopa[ casillasNames[i] ]; //Use the string reference to get hold of the button
mcReference.btn.addEventListener(MouseEvent.CLICK, _handleButtonClick); //Add a listener to the same "btn" child of the casilla as you did before.
}
you need a listener
function _handleButtonClick(e:Event)
{
var buttonReference:* = e.target;
So e.target in this instance should be the same object that you added to the array earlier (a1 or b1 or c1 depending on which one is clicked)
Now I'm going to make some leaps about how those MovieClips (a1,b1,c1) are structured (I'm guessing they are all the same just with different data in?)
function _handleButtonClick(event:MouseEvent):void
{
var clickedButtonReference:* = e.target;
for(var i:int = 0; i< casillas.length; i++)
{
if(this.sopa[ casillasNames[i] ].btn == clickedButtonReference) //Check each button on the stage to see if it is the one that has been clicked.
{
checkString += casillasNames[i];
//To find this bit "this.sopa.c1.letra" there are two options either
var selectedLetra = this.sopa[ casillasNames[i] ].letra; //Using the string name of the MC to find it.
//or
var selectedLetra = clickedButtonReference.parent.letra; //Or using the fact that we know that the original MC contains both the btn and the letra as children.
//Once we have it though the rest of your function should work ok.
var TFc1:TextFormat= selectedLetra.getTextFormat(0,1)
TFc1.color = 0xff0022;
selectedLetra.setTextFormat(TFc1);
check();
//Just add a break to stop searching for the button since we have found it.
break;
}
}
}

Giving each object that share the same class, their own individual variables that won't affect the other variables

Good Evening/ Morning.
This is a games related question.
I am facing an issue where I have three objects, (three goblins) data typed to the same class.
These three objects are in an array and data typed to that class, and initialized as the array.
private var goblin1:Goblin = new Goblin();
private var goblin2:Goblin = new Goblin();
private var goblin3:Goblin = new Goblin();
So the variables above have been then placed into an array.
private var aGoblinArray = new Array(container.goblin1, container.goblin2, container.goblin3);
After placing the objects into an array I have looped through all of my goblins.
for (var i:int = 0; i < aGoblinArray.length; i++)
{
var goblin:Goblin = aGoblinArray[i];
}
now I have a hitTest in the for loop and the hitTest is:
if (goblin.hitTestPoint(_character.x + 100, _character.y - 45, true))
{
goblinCanMove = false;
trace("lance hits");
//hitOnce
if (!hitOnce)
{
hitOnce = true;
trace("take on damage");
}
goblin.moveBack();
goblin.minusHealth();
}
This means if this player hits any of the goblins, they will do this function.
How ever in the goblin class.
public static var goblinLife; int;
goblinLife = 2;//put in main constructor
public function minusHealth():void
{
goblinLife --;
checkDeath();
}
private function checkDeath():void
{
if (goblinLife == 0)
{
parent.removeChild(this);
}
}
the problem is, if I hit goblin1, then goblinLife would = 1. This means all othet goblins(goblin2 and 3) will have 1 life. Since they share the same class.
if goblin1 dies, he is removed and the var goblinLife would = 0;
Now I can reset it back to 2, but this will fix half of the problem.
My question is, is there a way on how I can make sure each goblin has it's own individual life system. Thank you in advance.
Thank you very much Pan and Marty!
Static meant that it could be changed from any class and any function.
Private means that it will be protected to each individual goblin.
From changing
public static var goblinLife; int;
to
private var goblinLife; int;
it means that each individual goblin will have their own variable, that no other class or object of the same class can change.
Thank you Pan and Martyn. I guess I need to read AS3 101: Quick Tip – When to Use Static Properties and Methods and other coding books!

How to remove object from index in array AS3

Hey Everyone so I've been killing myself over this and this is probably the last thing I need help on to finally finish this project.
So I have a timer event that puts the Movie clip in the array onto the Stage. The MovieClip is named mSquare and from the timer event I add it like so:
private function addSquare(e:TimerEvent):void
{
mSquare = new mcSquare();
stage.addChild(mSquare);
mSquare.x = (stage.stageWidth / 2);
mSquare.y = (stage.stageHeight / 2) + 450;
aSquareArray.push(mSquare);
trace(aSquareArray.length);
}
Now what I am trying to Accomplish is when the user clicks or has its mouse down on the object, I want that object that the user clicked to be removed from the stage.
Now I can't get it to function properly when the user clicks on one of the MovieClips from the array thats added to the stage. Or if I do then MovieClip that was currently clicked doesnt get destroyed but rather another instance of it on the stage gets destroyed. Its just real bad.
So Here is how I have it set up so far...
In my Constructor:
stage.addEventListener(MouseEvent.MOUSE_DOWN, movieClipHandler);
Then the movieClipHandler MouseEvent:
private function movieClipHandler(e:MouseEvent):void //test
{
mSquare.addEventListener(MouseEvent.MOUSE_DOWN, squareIsBeingClicked);
}
Then in the squareIsBeingClicked Function:
private function squareIsBeingClicked(e:MouseEvent):void
{
var square:DisplayObject = e.target as DisplayObject; // clicked square
var i:int = aSquareArray.indexOf(square); // index in the array
if (i < 0) //THIS IS WHERE I GET CONFUSED
{
// the MC is out of the array
trace("Clicked");
mouseIsDown = true;
checkSquareIsClicked();
} else
{
// the MC is in the array
}
}
And finally i have a function called checkSquareIsClicked to do all the work:
private function checkPopIsBeingClicked():void
{
//Loop through all pops
for (var i:int = 0; i < aPopArray.length; i++)
{
//Get current pops in i loop
var currentpop:mcPop = aPopArray[i];
if (mouseIsDown)
{
trace("Current Pop Destroyed")
aPopArray.splice(i, 1);
currentpop.destroyPop();
nScore ++;
updateHighScore();
updateCurrentScore();
mouseIsDown = false;
//Add Explosion Effect
popExplode = new mcPopExplode();
stage.addChild(popExplode);
popExplode.y = currentpop.y;
popExplode.x = currentpop.x;
}
}
}
I know I am doing something really wrong because it shouldnt take this much functions to initiate this array of mouse event. Also someone on here helped me out with the display object and idex as shown above but not sure how to truly implement it. I've exhausted all ideas. Any Help would be appreciated or any pointers. Thank you!
As #Rajneesh answer indicates, adding your mouse event listener to your MovieClip instead of using the stage mouse event to add the listener, is the correct way to go. That means instead of doing this...:
stage.addEventListener(MouseEvent.MOUSE_DOWN, movieClipHandler);
private function movieClipHandler(e:MouseEvent):void {
mSquare.addEventListener(MouseEvent.MOUSE_DOWN, squareIsBeingClicked);
}
Would be replaced in your addSquare function:
private function addSquare(e:TimerEvent):void {
mSquare = new mcSquare();
stage.addChild(mSquare);
mSquare.x = (stage.stageWidth / 2);
mSquare.y = (stage.stageHeight / 2) + 450;
aSquareArray.push(mSquare);
//look here
mSquare.addEventListener(MouseEvent.MOUSE_DOWN, squareIsBeingClicked);
trace(aSquareArray.length);
}
Now you can change your removal functions. I'm going to alter some of this code to help you optimize it and still achieve the desired effect. Let's start with squareIsBeingClicked:
private function squareIsBeingClicked(e:MouseEvent):void {
var square:DisplayObject = e.target as DisplayObject; // clicked square
var i:int = aSquareArray.indexOf(square); // index in the array
//this is where you will no longer be confused :)
if (i != -1) {
trace("Clicked");
mouseIsDown = false;
onSquareIsClicked( square ); //this is in place of your checkSquareIsClicked
square.parent.removeChild( square );
aSquareArray.splice( i, 1 ); //remove element from the array
//remove the listener, very important
square.removeEventListener( MouseEvent.CLICK, squareIsBeingClicked );
square = null; //null it if we are not using it again, ready to be garbage collected
}
}
You now no longer need all the removal pieces in your previous checkSquareIsClicked. As you probably noticed I added a function onSquareIsClicked(), this is to help with any functionality you might need to do when this event is happening. Since you are adding an "explosion" where the object was selected, here's what onSquareIsClicked() looks like:
private function onSquareIsClicked( square:DisplayObject ):void {
popExplode = new mcPopExplode();
stage.addChild(popExplode);
popExplode.y = currentpop.y;
popExplode.x = currentpop.x;
//square.destroyPop(); //obviously this function will not work on a type displayObject
//in which case you just need to cast square to the object containing the method
nScore ++;
updateHighScore();
updateCurrentScore();
}
Add mouse click events to objects to be removed and get target and remove it like so:
(Note: Also, no need to add those MovieClips to array ( add only if necessary))
private function addSquare(e:TimerEvent):void
{
mSquare = new mcSquare();
mSquare.addEventListener(MouseEvent.CLICK, removeSquare);
stage.addChild(mSquare);
//Position here mSquare
}
private function removeSquare(e:MouseEvent):void
{
var tempObject:MovieClip = MovieClip(e.currentTarget); //get the square object
removeChild(tempObject);
tempObject = null;
}

Actionscript 3 eventlisteners, hittestobject and arrays of custom objects

Another desperately stuck first year student here. And I have to use FlashCS as my coding environment. And it sucks. So I'll try some well constructed and clear questions. There is:
public var object: symbol1;
public var objectarray: Array = new Array();
in my main. Then a function there that uses a timer and spawns a new object and pushes it onto the array:
object = new symbol1;
objectarray.push(object)
but then when I trace() the .length of the array it displays TWO numbers of the array length every timer period in the output. As in:
1 1 2 2 3 3
etc. This is my first mystery. Why two not one? because there is no way I'm calling the function that includes the trace () twice. Also I think I need to be able to remove my object from the objectarray when it goes off the stage, but the objectarray.pop() doesn't seem to work if I use it like so in a function:
if (object.y == stage.stageHeight)
objectarray.pop()
As in I try trace() the array.length before and after the .pop(), but it just keeps going up by one every timer period.
And the other, bigger issue is I want to know if you are allowed to put the .addEventListeners that you usually place right under the main function of any class into a statement loop. As in I've got
class extends Main {
class function() {
for (var i:Number = 0; i < objectarray.length; i++){
objectarray[i].addEventListener(Event.ENTER_FRAME, collision);}}
And then, if it is allowed, the program doesn't seem to enter the collision function of this same class anyway.
function collision (event:Event) : void{
if (this.hitTestObject(object)){
trace('hit');}}
so I searched and ended up adding a
var clip:MovieClip = MovieClip(e.target);
in the first line of the function, but then it didn't work and I realized I on't understand what's it meant to do, what's going on anymore and what is the syntax for this casting.
Thank you very much.
Edit/Update: adding more of my code eventhough I hate copypasting it like this. This is the symbol class that is going to change when an object of another class hits it
public class Head extends Main {
public function Head(){
this.stop();
for (var i:Number = 0; i < nicesnowflakearray.length; i++){
nicesnowflakearray[i].addEventListener(Event.ENTER_FRAME, snowhit);
}
}
public function snowhit(event:Event) : void {
if (this.hitTestObject(nicesnowflake)){
//I changed this line to (e.currentTarget.hitTestObject(nicesnowflake)) as Atriace suggested, but nothing changed, and I just don't understand why my version wouldn't work.
trace("hit");
}
}
And this is the class that spawns the objects that are supposed to hit the Head object:
public class Main extends MovieClip {
public var nicesnowflake: fallingsnow;
var nicesnowflakespawntimer: Timer = new Timer(1000);
public var nicesnowflakearray: Array = new Array();
public function Main() {
nicesnowflakespawntimer.addEventListener(TimerEvent.TIMER, nicesnowflakespawn);
nicesnowflakespawntimer.start();
}
public function nicesnowflakespawn(event:TimerEvent) : void {
nicesnowflake = new fallingsnow;
nicesnowflake.x = Math.random()* stage.stageWidth;
nicesnowflake.y = - stage.stageHeight + 100;
nicesnowflakearray.push(nicesnowflake);
stage.addChild(nicesnowflake);
trace(nicesnowflakearray.length);
}
Why two, not one?
Anytime you extend another class, it implicitly calls the parent class' constructor. We know this as super(), and can be quite handy. This is why you're getting doubles on your trace statement. Technically, you can choose not to call super().
.pop()
It should remove the last element from that array, however, I'm thinking that if an arbitrary object leaves the stage, you can't be gauranteed it'll be the last element. Ergo, you want splice()
if (object.y == stage.stageHeight) {
objectarray.splice(objectarray.indexOf(object), 1)
}
Event Listeners
I didn't follow your quandary, so I'll just try to rewrite what I think you were trying to do.
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
private var objectarray:Array = []; // Note, I haven't populated it with anything, I'm assuming you have.
private var theWall:MovieClip = new MovieClip(); // I haven't added this to the stage, or given it shape. You need to for hitTestObject to work.
public function Main() {
// This is your constructor.
for (var i:Number = 0; i < objectarray.length; i++) {
objectarray[i].addEventListener(Event.ENTER_FRAME, collision);
}
}
private function collision(e:Event):void {
if (e.currentTarget.hitTestObject(theWall)) {
trace('hit');
}
}
}
}
Of note, you may want to look at a guide to hitTestObject() if it's giving you issues.

Actionscript 3.0: making an array of button instance names

In Flash, I created a grid of 400 buttons with instance names c0 through c399.
In Actionscript, I'd like to create an array like this:
var myArray:Array = [c0,c1,c2,c3,c4,c5,c6];
all the way up to c399.
I wrote a for-loop to do the trick, but it doesn't seem to be working:
import flash.events.MouseEvent;
//create the array
var myArray:Array = [];
for (var i:int=0;i<399;i++){
var cletter:String = 'c';
var p:String = i.toString();
var newvalue:String = cletter + p;
var shizzle:Object = new SimpleButton();
myArray[i] = shizzle;
}
for each(var btn in myArray){
btn.addEventListener(MouseEvent.CLICK, onBtnClick);
}
function onBtnClick(event:MouseEvent):void{
cellinfo.gotoAndStop(event.target.name);
}
When I publish it, no errors show up and nothing happens when I click the buttons. However, if I use
var myArray:Array = [c0,c1,c2,c3,c4,c5,c6];
it does work! (for the first 7 buttons at least).
Also, when I put:
for (var i:int=1;i<6;i++){
var cletter:String = 'c';
var p:String = i.toString();
var newvalue:Object = cletter + p;
myArray[i] = newvalue;
}
it says:
TypeError: Error #1006: value is not a function. at
PVproject1_fla::MainTimeline/frame1()
I just started working with AS3 + Flash and spent hours looking for a solution. Please help!
Your code is broken in more than one way.
for (var i:int=0;i<399;i++){
var cletter:String = 'c';
var p:String = i.toString();
var newvalue:String = cletter + p; // => this is never used
var shizzle:Object = new SimpleButton(); // => this creates a new (!) button
myArray[i] = shizzle;
}
Each of the 400 newly created buttons is never added to the stage, therefore you can't see it. And since it has no skin or other visual properties, you wouldn't be able to see it if it were.
The second for-loop puts only the names into the array - which causes the "value is not a function" error when you try to access the array values as buttons, because the value is really a string:
for (var i:int=1;i<6;i++){
var cletter:String = 'c';
var p:String = i.toString();
var newvalue:Object = cletter + p; // <= this is a String!
myArray[i] = newvalue;
}
Now apart from a fundamental doubt whether you'd really want to create 400 button instances by hand (I'd think about doing it in ActionScript and using this actual creation to fill the array), you can do the following - but remember: only if the button instances are already on the stage, and the loop is located in a frame script!
for (var i:int=0;i<399;i++){
myArray[i] = this["c"+i]; // no need for all the p and .toString() stuff, btw
}
Another solution is to just watch for them to be added to the stage and capture them at that point, similar to one of the examples you can download here http://flexdiary.blogspot.com/2010/04/sample-code-for-oop-timeline-insideria.html

Resources