targeting multiple movieclips of the same class to change frame number as3 - arrays

I'm having this issue with this memory match game. I want the cards to show face up so the user can memorize them, and after 3 seconds I want them to turn over and show their back face.
I got the entire game working perfectly, btw. I'm just missing this detail!
the code below is how my cards get created (they are all 1 movieclip (mcCartas) with 37 frames inside (36 types of card and back card))
const QUANT_CARTAS:int = 36; ///// number of cards (faces drawn, frame numbers)
const CARTAS_POR_LINHA:int = 6; /// number of lines (6x6 grid)
var cartas:Array = new Array(); // cards array
var cartasColetadas:Array = new Array(); // clicked cards array
////////gets the 36 cards into the array
for(var i:int=0;i<QUANT_CARTAS;i++)
{
cartas.push(i);
}
/////////shuffles the cards
for(var moeda:int = QUANT_CARTAS-1;moeda>0;moeda--)
{
var pos:int = Math.floor(Math.random() * moeda);
var carta:int = cartas[moeda];
cartas[moeda] = cartas[pos];
cartas[pos] = carta;
}
////////// puts them on the table
for(i=0;i<QUANT_CARTAS;i++)
{
var novaCarta:Carta = new Carta();
novaCarta.tipoCarta = cartas[i];
novaCarta.x = 5 + (novaCarta.width + 2.7) * (i % CARTAS_POR_LINHA);
novaCarta.y = 5 + (novaCarta.height + 2.7) * (Math.floor(i/CARTAS_POR_LINHA));
novaCarta.gotoAndStop(cartas[i]+1); // this line they all face their number OR
//novaCarta.gotoAndStop(QUANT_CARTAS + 1); // this line they all face back (last frame)
novaCarta.buttonMode = true;
novaCarta.addEventListener(MouseEvent.CLICK, cartaClicada);
addChild(novaCarta);
trace (cartas);
if(i == 35)
{
podeJogar = false;
mcContagem.x = 884;
mcContagem.y = 511;
addChild(mcContagem);
intervalo = setInterval(desviraCartas, 3000);
function desviraCartas()
{
for(var j:int = 0;j < QUANT_CARTAS; j++)
{
//here I'm trying to make them go back to their back (last frame)
//something????.gotoAndStop(QUANT_CARTAS + 1);
if(j == 35)
{
clearInterval(intervalo);
iniciaJogo();
}
}
}
}
}
this code IS working, but a couple lines up where I typed "something????.gotoAndStop etc" ... that's where I have tried everything... heeelppppp plzzzzz

You should store the new Cartas in an array when you add them. Then use that array to reference them: Push into array:
aCartasMCs.push(novaCarta);
Then you can reference like:
aCartasMCs[i].gotoAndStop(QUANT_CARTAS + 1);

Related

Performance of array reverse in ActionScript 3

I have two code snippets . which one is better.
var texts:Array = new Array(1,2,3,4,5,6,7,8,9,10);
texts.reverse();
for(var index:int=0; index < texts.length; index++) {
trace(texts[index]);
}
Or
var texts:Array = new Array(1,2,3,4,5,6,7,8,9,10);
for( var index:int = texts.length; --index;) {
trace(texts[index]);
}
In former we have reverse operation and then print it and in latter we start from the length and start printing the array. The goal is to traverse the array from last.
I wrote a script which evaluates time elapsed between for loops. After running the application numerous of times, it appears that the 2nd for loop is fastest.
Averaging: 4.168000000000001 | 4.163000000000002 seconds respectively for 100 iterations of each for loop.
The script is as follows:
import flash.events.Event;
var _t:int = getTimer();
var dt:Number;
var started:Boolean = false;
var iteration:int = 0;
var timer1:Number = 0;
var timer2:Number = 0;
var numberOfIterations = 100;
var texts1:Array = new Array(1,2,3,4,5,6,7,8,9,10);
var texts2:Array = new Array(1,2,3,4,5,6,7,8,9,10);
texts2.reverse();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
addEventListener(Event.EXIT_FRAME, onExitFrame);
function onEnterFrame(e:Event):void {
var t:int = getTimer();
dt = (t - _t) * 0.001;
_t = t;
iteration++;
// small FLA load buffer
if(iteration == 50 && !started)
{
iteration = 0;
started = true;
}
}
function onExitFrame(e:Event):void {
if(started)
{
if(iteration < numberOfIterations)
{
for(var index:int=0; index < texts1.length; index++) {}
timer2 += dt;
trace("Time Elapsed Alg 2: " + (timer2));
}
else
{
for( var index:int = texts2.length; --index;) {}
timer1 += dt;
trace("Time Elapsed Alg 1: " + (timer1));
}
if(iteration == ((numberOfIterations*2)-1))
{
trace("________________________________________");
trace("FINAL: " + timer1 + " | " + timer2);
removeEventListener(Event.EXIT_FRAME, onExitFrame);
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
}
I am interested to see what others get using the following script, as it seems reliable on my PC as if I switch the for loop positions, the results still indicate that the fastest is:
var texts:Array = new Array(1,2,3,4,5,6,7,8,9,10);
for( var index:int = texts.length; --index;) {
trace(texts[index]);
}
The first one doesn't trace the last item in the array ie 1
The second one does.
So I say the second is better.
I'm curious though - what's the correct way to code the first one so that it traces all the items in the array?

as3: how to access a MovieClip as unique Object/MovieClip from Array which loaded from same MovieClip from the Library

I'm trying to add multiple copies of the same movieclip to the stage at once
I have the loop which fills the array and generate the movieclips to the stage
and the loop to add The click EventListener for each movieClip
but I miss the magical code to access every MovieClip separately
to have it removed from the stage by clicking on it
var numOfClips:Number = 5;
var mcArray:Array = new Array();
for(var i=0; i<numOfClips; i++)
{
var usd:mcUSD = new mcUSD();
//genrate random x , y position----------------------------
var randY:Number = Math.floor(Math.random()*460) + 120;
var randX:Number = Math.floor(Math.random()*350) + 60;
usd.x = randX;
usd.y = randY;
//---------------------------------------------------------
mcArray.push(usd);
addChild(usd);
}
for(var m:int = 0; m<mcArray.length; m++){
usd.addEventListener(MouseEvent.CLICK, colectmoney);
}
function colectmoney(e:MouseEvent): void {
removeChild(usd);
}
Try this:
import flash.events.MouseEvent;
var numOfClips:Number = 5;
var mcArray:Array = new Array();
for(var i=0; i<numOfClips; i++)
{
var usd:mcUSD = new mcUSD();
//genrate random x , y position----------------------------
var randY:Number = Math.floor(Math.random()*460) + 120;
var randX:Number = Math.floor(Math.random()*350) + 60;
usd.x = randX;
usd.y = randY;
//---------------------------------------------------------
mcArray.push(usd);
addChild(usd);
}
addEventListener(MouseEvent.CLICK, mouseClickHandler);
function mouseClickHandler(e:MouseEvent) : void {
removeChild(mcArray[mcArray.indexOf(e.target)]);
}
Important things to note: 1) you do not need to call a mouse.click event listener for each mcUSD object. It's more efficient to call it once. 2) removeChild(usd) won't work because you need to tell AS3 which mcUSD object to remove. 3) try to keep function nomenclature consistent - eg colectMoney instead of colectmoney. it will save you confusing times once your program gets bigger. hope this helps! :)

Actionscript 3.0 : Controlling child movieclips added with an array

I'm trying to build a generic slide show flash file controlled with key presses... right and left arrow to go to next / previous slide, down and up to call / uncall the single animations / bullet points / whatever on a single slide.
So far I managed to get a file that can load all the pages from a movieclip and flick through them with right and left arrow and a nice fade out and fade in effect, even when flicking very fast.
What I do not get at all after several hours and lots of google searches is how to now control the single page movieclips. I uploaded the file so far:
http://www.broesel-brzelius.de/zeug/slide.zip
You can see that my (as of yet crude) attempt to control the pageHolder.Pages.page1 movieclip to gotoAndStop(2) just results in the pageHolder.Pages movieclip that was loaded to position 0 in the array to go to frame 2 and thus display the second page.
Code so far:
import flash.display.Sprite;
import flash.events.MouseEvent;
import com.greensock.*;
import flash.display.MovieClip;
// instantiate a variable to find number of pages
var numberOfPages:Pages = new Pages();
// instantiate an array to hold the page movieclips
var pageArray:Array = new Array();
// instantiate a container to hold the pages
var pageHolder:Sprite = new Sprite();
// declare variables that will hold reference to the current page IDs
var targetIDold:int = 0;
var targetIDnew:int = 0;
// declare a variable that will hold the current direction of slide movement
var movement:int = -1;
// call a function that builds the application
// pass in the number of pages in fl_prevSlide
buildApp(numberOfPages.totalFrames);
// this function builds the application
function buildApp(n:int):void
{
// declare variables for the pages
var p:Pages;
// instantiate a new Page, send its playhead to the current value of i+1
// it is necessary to add 1 to the value of i, since i starts at 0, while the timeline starts at 1
for (var i:int = 0; i < n; i++)
{
p = new Pages();
p.gotoAndStop(i + 1);
pageArray.push(p);
}
// set the position of the pageHolder relative to the buttonHolder
pageHolder.x = pageHolder.y = 0;
// add the first page (at index 0) from pageArray to pageHolder
pageHolder.addChild(pageArray[targetIDnew]);
// add pageHolder and buttonHolder to the stage
addChild(pageHolder);
}
//Adding Listener and corresponding function to change between slides
stage.addEventListener(KeyboardEvent.KEY_DOWN, f_changeSlide);
function f_changeSlide(evt:KeyboardEvent):void
{
if(evt.keyCode == 37) // left arrow
{
f_prevSlide();
}
else if (evt.keyCode == 39 || evt.keyCode == 32) // right arrow or space
{
f_nextSlide();
}
}
function f_prevSlide():void
{
if(targetIDnew > 0)
{
movement = -1;
targetIDnew -= 1;
f_addPage();
}
}
function f_nextSlide():void
{
if(targetIDnew < (numberOfPages.totalFrames - 1))
{
movement = 1;
targetIDnew += 1;
f_addPage();
}
}
function f_addPage():void
{
// use the targetID variable to access the corresponding index in the pageArray and assign it to a temporary variable
targetIDold = targetIDnew - movement;
var _mcOld:MovieClip = MovieClip(pageArray[targetIDold]);
var _mcNew:MovieClip = MovieClip(pageArray[targetIDnew]);
//avoid flickering
if (_mcNew.alpha == 1) {
_mcNew.alpha = 0;
}
// add the temp variable to pageHolder
pageHolder.addChild(_mcNew);
// tween the temp variable to the specified properties, then call a function to remove the previous page
// new page gets faded in, old page gets faded out
TweenMax.to(_mcNew, 1.5, {alpha:1});
TweenMax.to(_mcOld, 1.5, {alpha:0, onComplete:f_removePage});
}
function f_removePage():void
{
// previous page will always be at index 0; remove it
// the new page just added will drop down to index 0 when the previous page is removed
pageHolder.removeChildAt(0);
}
//Trying to advance / decrease the timeline in the movieclips of the single pages by pressing down / up
stage.addEventListener(KeyboardEvent.KEY_DOWN, f_changeFrame);
function f_changeFrame(evt:KeyboardEvent):void
{
if(evt.keyCode == 40) // down arrow
{
f_nextFrame();
}
else if (evt.keyCode == 38) // up arrow
{
f_prevFrame();
}
}
function f_nextFrame():void
{
var w:uint = pageHolder.numChildren - 1 ;
(pageHolder.getChildAt(w) as MovieClip).gotoAndStop(currentFrame + 1);
// for (var i:uint = 0; i < pageHolder.numChildren; i++)
// {
// trace (+i+'.\t name:' + pageHolder.getChildAt(i).name + '\t type:' + typeof (pageHolder.getChildAt(i)));
// }
trace ("down!");
}
function f_prevFrame():void
{
var w:uint = pageHolder.numChildren - 1 ;
(pageHolder.getChildAt(w) as MovieClip).gotoAndStop(currentFrame - 1);
// for (var i:uint = 0; i < pageHolder.numChildren; i++)
// {
// trace (+i+'.\t name:' + pageHolder.getChildAt(i).name + '\t type:' + typeof (pageHolder.getChildAt(i)));
// }
trace ("up!");
}
Edit: clarified code a bit
Edit2: TL;DR: Problem is the last bit of code with the three functions that fail to control the timeline of mc page1, which is a child of mc pages, which is pushed frame by frame into an array and loaded at runtime into the sprite pageHolder. How to control the timeline of the single page movieclips?
Finally got it to work. This will work as a perfect powerpoint replacement :D
You will need to name the single slides (one movieclip on each frame of the mc pages) as page0, page1 etc. and then can control their timeline with this code (just replace the functions listed in the question above):
function f_nextFrame():void
{
var temp:uint = pageHolder.numChildren - 1;
var frame:uint = ((pageHolder.getChildAt(temp) as MovieClip)["page" + targetIDnew].currentFrame);
(pageHolder.getChildAt(temp) as MovieClip)["page" + targetIDnew].gotoAndStop(frame + 1);
}
function f_prevFrame():void
{
var temp:uint = pageHolder.numChildren - 1;
var frame:uint = ((pageHolder.getChildAt(temp) as MovieClip)["page" + targetIDnew].currentFrame);
(pageHolder.getChildAt(temp) as MovieClip)["page" + targetIDnew].gotoAndStop(frame - 1);
}

How can I prevent this arbitrary text truncation in AS3

Below is code that populates a menu. Everything seems to work great, with no errors thrown, except for one crucial part. My megaPages array has the values ["HOME","BABIES","BRIDALS","MISC","WEDDINGS","ABOUT"], but the actual text that displays on screen (which is produced by megaPages) is like this:
As you can see, some of the text is arbitrarily being truncated. I've traced the text strings as they get passed through the various functions at various stages of the menu-build, and they are always right, but somehow when each DisplayObject make it on screen, letters get ommitted (notice though that 'HOME' abd 'ABOUT' are fine). I don't even know where to start with this problem.
function buildMenu() {
var itemMCs = new Array();
for (var i = 0; i < megaPages.length; i++) {
megaPages[i] = megaPages[i].toUpperCase();
trace(megaPages[i]); // at each iteration, traces as follows "HOME","BABIES","BRIDALS","MISC","WEDDINGS","ABOUT"
var textMC = createText(megaPages[i]);
var itemMC = new MovieClip();
if (i!=0) {
var newLink = new PlateLink();
newLink.y = 0;
itemMC.addChild(newLink);
}
var newPlate = new Plate();
if (i==0) {
newPlate.y = 0;
} else {
newPlate.y = newLink.height - 2;
}
newPlate.x = 0;
newPlate.width = textMC.width + (plateMargin*2);
itemMC.addChild(newPlate);
if (i!=0) {
newLink.x = (newPlate.width/2) - (newLink.width/2);
}
textMC.x = plateMargin;
textMC.y = newPlate.y + .5;
itemMC.addChild(textMC);
itemMCs.push(itemMC);
itemMC.x = (homeplateref.x + (homeplateref.width/2)) - (itemMC.width/2);
if (i==0) {
itemMC.y = homeplateref.y;
} else {
itemMC.y = itemMCs[i-1].y + (itemMCs[i-1].height - 6);
}
menuRef.addChild(itemMC);
}
}
function createText(menuTitle) {
trace(menuTitle);
var textContainer : MovieClip = new MovieClip();
var myFont = new Font1();
var backText = instantText(menuTitle, 0x000000);
backText.x = 1;
backText.y = 1;
var frontText = instantText(menuTitle, 0xFFFFFF);
frontText.x = 0;
frontText.y = 0;
textContainer.addChild(backText);
textContainer.addChild(frontText);
return textContainer;
}
function instantText(textContent, color) {
trace(textContent); // again, traces the right text each time it is fired
var myFont = new Font1();
var myFormat:TextFormat = new TextFormat();
myFormat.size = 18;
myFormat.align = TextFormatAlign.CENTER;
myFormat.font = myFont.fontName;
var myText:TextField = new TextField();
myText.defaultTextFormat = myFormat;
myText.embedFonts = true;
myText.antiAliasType = AntiAliasType.ADVANCED;
myText.text = textContent;
myText.textColor = color;
myText.autoSize = TextFieldAutoSize.LEFT;
trace(myText.text);
return myText;
}
You need to embed all the necessary characters for the font you're using.
For textfields created in Flash:
Select the TextField, and hit the 'Embed' button in the properties panel.
For dynamically created textfields:
When you set the font to export (Font1 in your case) make sure to include all the characters you need.
You can choose to embed all uppercase characters, or just type in the ones you need for those specific menu items.

set array to hold images verses text, flash actionscript

the following flash actionscript below stores letters and numbers into an array and displays them randomly in a flash movie as "falling text" down the screen. I'd like to modify this script so I can have the array store multiple images verses letters and numbers.
source:
http://www.flashcomponents.net/tutorials/letter_and_number_rain_flash_tutorial/page_1.html
--- layer script
var letter_array = new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0");
var i = 0;
setInterval(nLetter, 70);
function nLetter()
{
duplicateMovieClip(letterMC, "letter" + i, 10 + i);
i++
}
-------- symbol script
onClipEvent(load)
{
var index = Math.round(Math.random() * _root.letter_array.length - 1)
this.letter.text = _root.letter_array[index];
_x = Math.round(Math.random() * 540) + 5
_y = Math.round(Math.random() * -20) - 10;
var gravity = 0.2;
var ran = Math.round(Math.random() * 50) + 50;
_alpha = ran + 10;
_xscale = _yscale = ran;
speed = Math.round(Math.random() * 5) + 10;
rotSpeed = Math.round(Math.random() * 6) - 3;
//this.letter.textColor = Math.random() * 0xFFFFFF
}
onClipEvent(enterFrame)
{
_y += speed;
_rotation += rotSpeed
speed += gravity;
if(_y > 410)
{
this.removeMovieClip();
}
}
You need to add this at the top of your code:
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.*;
In the layer script you need to have an array of images, so the first thing would be to load all your images and store them in an array when the loading is complete.
in the following code , replace i "inferior to" totalNumImages with
i < totalNumImages , I can't use the "<" character in the code.
//your images location
var url1:String = "images/image1.jpg";
var url2:String = "images/image2.jpg";
var urls:Array = [ url1 , url2 ];
var images:Array = [];
//the total number of images
var totalNumImages:int = 2;
for(var i:int ;i "inferior to" totalNumImages ; ++i )
{
loadImage(images[i] );
}
function loadImage(url:String):void
{
var loader:Loader = new Loader();
var info:LoaderInfo = loader.contentLoaderInfo;
info.addEventListener(Event.COMPLETE , loadComplete );
info.addEventListener(IOErrorEvent.IO_ERROR , errorHandler );
loader.load ( new URLRequest(url ));
}
function errorHandler(event:IOErrorEvent):void
{
trace( event );
}
function loadComplete(event:Event):void
{
//assuming the order doesn't matter
images.push(event.currentTarget.loader.content );
//all images are loaded, let's start...
if(images.length == totalNumImages )
nLetter();
}
After all your images have loaded you can start the nLetter() function. Each time a MovieClip is added to the stage, it will load its image from the array of images that you've created.
change this:
this.letter.text = _root.letter_array[index];
to this:
//assumes that you have an array of DisplayObject
addChild( _root.images[index]);

Resources