AS3 Newbie here... very confused, please be kind ;)
I have a MovieClip (rozette), which contains 7 instances of a MovieClip (circle). circle contains an animation and I would like to play each instance of it within rozette consecutively.
Questions - do I need to use an array? Is using eventListener the best way to do this? If so, how can I create an eventlistener for each item in the array? And what kind of event am I listening for?
Many thanks. Kat
You can see some options given as answers here:
Flash AS3 - Wait for MovieClip to complete
Basically I would think you want to have an array and a counter for which one you're on, each time the "playNext" function gets called, you should increment the counter and pull the next movie clip from the array. What this means is the order of elements in the array will dictate the order they play in. Something like:
private var myArray:Array = [mc1,mc2,mc3]; //list all the movieclip instance names here
private var counter:Number = 0; //start off on the first element, arrays in AS3 start at 0
//Play the next clip
private function playNext():void {
//Check that we're not at the end of the list, if so just return/stop
if(counter>myArray.length-1)
return;
//grab the next clip
var curClip:MovieClip = myArray[counter] as MovieClip;
//increment the counter for next time
counter++;
//when the last frame gets hit call this function again
curClip.addFrameScript(curClip.totalFrames-1, playNext);
//play the clip
curClip.play();
}
From your constructor of your Main class you would want to call playNext() once to get things rolling.
import com .greensock.*;
import com. greensock.easing.*;
var s1:b1=new b1();
var s2:b2=new b2();
var s3:b3=new b3();
var r1:Array = new Array();
r1.push(s1);
r1.push(s2);
r1.push(s3);
function ff (){
var i = 0;
while (i < r1.length) {
r1[i].visible=false
r1[0].visible=true
addChild(r1[i]);
i++;
}
TweenMax.staggerTo(r1, 0.4, {visible:true},0.2);
}
bb.addEventListener(MouseEvent.CLICK,cliki4x);
function cliki4x(e:Event):void{
ff ();
}
Related
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;
}
}
}
[AS3.0] I'm currently working on my graduation diploma and I have a problem with managing movieClips with the same instance name..sort of. I'm creating an array of objects with this Class an Arrays in frame 1:
package
{
import flash.display.MovieClip;
public class createFractionBuilding
{
public function createFractionBuilding(_fractionBuildingMovieClip:MovieClip, _fractionBuildingLevel:Number,_fractionBuildingCost:Number, _fractionBuildingFrame:Number)
{
fractionBuildingLevel = _fractionBuildingLevel;
fractionBuildingCost = _fractionBuildingCost;
fractionBuildingMovieClip = _fractionBuildingMovieClip
fractionBuildingFrame = -fractionBuildingFrame
}
public var fractionBuildingLevel:Number,fractionBuildingCost:Number,fractionBuildingFrame:Number;
public var fractionBuildingMovieClip:MovieClip
}
}
On main timeline I'm refering to this Class by creating an Array of objects:
var allHumanBuildingsList:Array = new Array();
var humanCapitolBuildingProperties:createFractionBuilding = new createFractionBuilding(humanCapitol_mc,1,1000,1);
var humanCastleBuildingProperties:createFractionBuilding = new createFractionBuilding(humanCastle_mc,2,1000,1);
allHumanBuildingsList.push(humanCapitolBuildingProperties);
allHumanBuildingsList.push(humanCastleBuildingProperties);
For this to work I have to have movieclip called "humanCapitol_mc" or "humanCastle_mc" in this frame (1).
But in frame (2) I want to refer to this movieClip with such function:
function humanBuildingLevelCheck()
{
for (var a:Number = 0; a < allHumanBuildingsList.length; a++)
{
trace (String(allHumanBuildingsList[a].fractionBuildingMovieClip))
if (allHumanBuildingsList[a].fractionBuildingLevel == 2){
allHumanBuildingsList[a].fractionBuildingMovieClip.gotoAndStop(3)
} else if (allHumanBuildingsList[a].fractionBuildingLevel == 1){
allHumanBuildingsList[a].fractionBuildingMovieClip.gotoAndStop(2)
}
}
}
humanBuildingLevelCheck()
(Each MovieClip on first frame is blank, on second is one picture, on third is different one)
Everything works, when the array creation code is in frame two, but it won't work the way I want: first I create variables and objects and then I change it's values dynamically. Do you have an idea, how could that work?
Make it global. If one variable is declared in keyframe 1, you can't see it in keyframe 2 but if you declare it in one layer that has only one keyframe then it will be visible anywhere within that timeline.
I have to add a list of objects into an Array so I can access them Later, but for some reason the object I have added plays before, I add them on to the display list. here is the code:
the Frame Where the list is Added:
sunny.addEventListener(MouseEvent.CLICK, sunny_choice);
function sunny_choice(E:MouseEvent)
{
var sunny_walkcycle: Sunny_Walkcycle = new Sunny_Walkcycle ();
var sunny_busstop : Sunny_BusStop = new Sunny_BusStop ();
var sunny_opening: Teacher_Opening_Sunny = new Teacher_Opening_Sunny ();
clothingArray.push( sunny_walkcycle);
clothingArray.push( sunny_busstop);
clothingArray.push( sunny_opening);
trace("Sunny");
cleaner();
//cleaner just removes the event listener and asks it to go to the next frame
}
Th next Frame:
clothingArray [0].scaleX = -1;
addChild (clothingArray [0]);
clothingArray[0].x = 633;
clothingArray[0].y = 174;
clothingArray [0].stop ();
clothingArray [0].addEventListener (MouseEvent.CLICK, transforming);
function transforming (e:MouseEvent) {
if (clothingArray [0].currentFrame == clothingArray [0].totalFrames) {
clearall2 ();
}
else{
clothingArray [0].nextFrame();
moving_background.nextFrame ();
}
}
function clearall2 () {
clothingArray [0].removeEventListener (MouseEvent.CLICK, transforming);
removeChild (clothingArray [0]);
gotoAndStop (3);
}
The problematic One:
addChild (clothingArray [1]);
clothingArray[1].addEventListener (Event.ENTER_FRAME , busstop);
trace ("The Current Frame is " + clothingArray [1].currentFrame);
function busstop (d:Event) {
if (clothingArray [1].currentFrame == clothingArray [1].totalFrames) {
clearall3 ();
}
}
function clearall3 () {
removeChild (clothingArray [1]);
clothingArray[1].removeEventListener (Event.ENTER_FRAME , busstop);
}
So what Exactly it does is the movieclip in Frame 3 starts playing before it's even added to the Display list and i am not sure what is causing it...I cannot separately add the variable at this frame because there are other options in frame 1 that leads to me making an array.
Assuming that Sunny_Walkcycle, Sunny_BusStop, Teacher_Opening_Sunny are MovieClip, why don't you use stop() directly after the memory allocation ?
var sunny_walkcycle:Sunny_Walkcycle = new Sunny_Walkcycle ();
var sunny_busstop:Sunny_BusStop = new Sunny_BusStop ();
var sunny_opening:Teacher_Opening_Sunny = new Teacher_Opening_Sunny ();
sunny_walkcycle.stop();
sunny_busstop.stop();
sunny_opening.stop();
Be sure there is no code in your MovieClip inner frames that will mess with your control code.
Like a play()... hidden somewhere.
You could also try (for sunny_busstop), just after pushing in the array :
clothingArray[1].stop();
or
clothingArray[1].gotoAndStop(1);
Yes, a MovieClip will start playing once it is created. It doesn't need to be added to the Display List to be activated. This is very important detail to understand.
The Display List only determines whether or not a Display Object is connected to the stage hierarchy.
solution... call the stop() method after creation and then the play() method when you add them to the Display List.
If you don't call the stop() method when removing from the Display List, it'll just keep on eating up cpu cycles. If you have numerous MovieClips with tweens etc, that can be quite significant.
In a game I'm making, I'm trying to have sprites put on top of a hit box. The best way I could think of accomplishing this is to make two arrays; one for the hit boxes, and one for the sprites, and then have the sprites stay on top of their respective hit-box via a for loop that will be in its own script.
Problem is, is that when I try to get the MovieClips in either of the arrays to do anything, it doesn't work. If I do a trace on the X or Y location of the sprites, I get "undefined" in my terminal. I'm going to explain this from the top down.
Here is an excerpt from my class that contains the for loop (Dasengine is my main class fyi)
for(var i:Number = 0; i < Dasengine.ovrcnt.length; i++){
trace(Dasengine.ovrcnt[i].x); //returns "undefined"
trace(Dasengine.ovrcnt[i]); //returns "object Onmea"
Dasengine.ovrcnt[i].x = Dasengine.enemycnt[i].x;//this isn't working
}
In another script when an enemy spawns, they go through this method.
if(ENEMY SPAWN CONDITION IS MET ){
Dasengine.baddie = new nme_spawn.Enemya(); //ENEMY HITBOX
Dasengine.Obaddie = new nme_overlay.Onmea(); //ENEMY's sprite
Dasengine.enemycnt[cntup] = [Dasengine.baddie]; //Enemy's Hit box movie clip is put in array meant for holding enemy movie clips
Dasengine.ovrcnt[cntup] = [Dasengine.Obaddie]; //Enemy sprites that go over the hit boxes are stored here
cntup++; //this is so movie clips are put in new parts of the array
}
in my main class, the movie clips are declared as follows also I have the addChild functionality in there.
public static var Obaddie:nme_overlay.Onmea;
//^variable for sprite
public static var baddie:nme_spawn.Enemya;
//^variable for hitbox
also Obaddie= Overlay baddie. Its the MovieClip that acts as what goes on top of the hitbox, this is what the player will see
badde = is simply the hitbox. This contains the "meat" of the enemy ai.
I talked about this with some friends and they thought I might need to define what 'X' is inside of the class of the object that is in the array. So I did the following
package nme_overlay {
import flash.display.*;
import flash.events.*;
import nme_spawn.*;
public class Onmea extends MovieClip{
// Constants:
// Public Properties:
// Private Properties:
public static var xloc:int = 0;
// Initialization:
public function Onmea() {
this.addEventListener(Event.ENTER_FRAME, overlaya);
}
private function overlaya(e:Event){
xloc = 55;
//trace(xloc);
}
}
}
and then for the looping class I did this
for(var i:Number = 0; i < Dasengine.enemycnt.length; i++){
trace(Dasengine.ovrcnt[i]);//returns "object Onmea"
trace(Dasengine.ovrcnt[i].xloc);//still returns "undefined"
}
Your xloc variable is static--it belongs to nme_overlay, the Class, not any particular instance. If you were to do this in your code AND you had strict mode on (which I suspect you do not, because there's a lot of stuff in your code that should be giving you at least warnings), you'd get an error that would tell you exactly that:
for(var i:Number = 0; i < Dasengine.enemycnt.length; i++){
trace(Dasengine.ovrcnt[i]);//returns "object Onmea"
trace(nme_overlay(Dasengine.ovrcnt[i]).xloc);//still returns "undefined"
}
I have a sprite called food which adds to the screen via the use of a timer. more food items are added to the screen over time. How would i hit test all these food sprites with another object?
(the makeItem function creates the sprite btw)
private function placeFood(event:TimerEvent = null):void{
var rndI:uint = Math.floor(Math.random() * DIM); //sets a random integer based on the the floor
var rndJ:uint = Math.floor(Math.random() * DIM);
var rndX:Number = grid[rndI][rndJ].x; // sets a grid position for the food item to go
var rndY:Number = grid[rndI][rndJ].y;
food = makeItem(Math.random() * 0xFFFFFF);// random color
food.x = rndX;
food.y = rndY;
var foodArray:Array = new Array();
foodArray.push(food);
trace(foodArray.length)
addChild(food); //adds the food to the board
for (var i:uint = 0; i < snake.length; i++){
if (rndY == snake[i].y && rndX == snake[i].x){
placeFood();
}
}
}
Add the food items to an array and loop through that array doing hitTestObject. Something like:
var foods:Array = new Array();
foods.push(makeItem(blah));
...
for each (food in foods) {
food.hitTestObject(object);
}
It looks like you're putting items on a fixed grid. Do the food items move around? Your food does not move, and your snake (or whatever collides with the food) does, you can greatly optimize your collision detection by figuring out what grid square(s) the moving object occupies and only checking against food in that local area.
Generally speaking, when you need to do collision detection between many objects, you do it in multiple passes. The first pass would consist of the least computationally expensive checks to cull things that could not possibly be colliding such as objects that are very far apart, moving away from each other, etc. Your next pass might be something like simple boundary box or circle tests. Lastly, when you're down to the few items that pass all the cheap tests, you can use more expensive and accurate hit tests like pixel-by-pixel ones between hit masks.
Another way avoiding arrays is to use a sprite that contains all food. Every sprite is a collection of sprites and therefore a tree. That's what I use for hit detection: 1 special sprite contains only enemies / food. Run through all children and you don't even need to check the types of them. Cast them if needed.
// begin
var foodCollection: Sprite = new Sprite();
// time passes, food is added
foodCollection.addChild(food);
// hit test
for (var i:int = 0; i < foodCollection.NumChildren; i++)
{
var food: Sprite = foodCollection.getChildAt(i);
// test
}