Unload MovieClip and RemoveChild AS3 - actionscript-3

I developed a code that is going to load a movie clip making a comparison with two dynamic text.
If dynamic text is greater than the other one, it will lunch a specific movie clip. I[m trying to develop a light sign system comparing numbers.
Action script is importing data from .txt files (exported using EXCEL and VBA). I created a code to reload all data using a timer. I create that so it's not necessary to reopen the .swf file.
Here is the automatically reload code:
// timer loading
var timer:Timer = new Timer(2500);
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
Now, the code is being applied to all actions, include an action to redownload the .txt files, here it is:
function onTimer(evt:TimerEvent):void { //primeiro indicador parte
var loader:URLLoader = new URLLoader(new URLRequest("bdaily.txt"));
loader.addEventListener(Event.COMPLETE, completeHandler);
function completeHandler(event:Event):void {
var loadedText:URLLoader = URLLoader(event.target); bdaily.text = loadedText.data;
}
Now, this code is comparing the .txt (dynamic text) and loading or not loading a new movie clip.
var clp_index = parseInt(bdaily.text) >= parseInt(basketdtarget.text) ? 1 : 2
var new_clp = clp_index == 1 ? new clp_01() : new clp_02()
addChild(new_clp)
The PROBLEM IS:
-> Everything is working fine, all data is being loaded and are shown in the dynamic text.
The real thing is that all movie clips are being loaded in an infinite loop due the loop timer set, a lot of ram memory is being consumed. The code is working but its loading movie clips above movie clip.
I need to implement my code and insert a code to erase the movie clips after calling the loop again.

There are a few ways you can accomplish this. I'll show a couple of them.
Make your new_clp var global to the current class or timeline (move it's declaration to the same place as your timer)
var timer:Timer = new Timer(2500);
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
var new_clp:DisplayObject;
Then, remove it before creating a new clip:
if(new_clp){ //if there is already something in this variable, then remove it
removeChild(new_clp);
}
var clp_index = parseInt(bdaily.text) >= parseInt(basketdtarget.text) ? 1 : 2
new_clp = clp_index == 1 ? new clp_01() : new clp_02()
addChild(new_clp)
Walk the current scopes display list and remove all clp_01 and clp_02 instances:
var i:int = numChildren;
while(i--){
if(getChildAt(i) is clp_01 || getChildAt(i) is clp_02){
removeChild(getChildAt(i));
//if you have any listeners attached to the object, remove them now
}
}
var clp_index = parseInt(bdaily.text) >= parseInt(basketdtarget.text) ? 1 : 2
var new_clp = clp_index == 1 ? new clp_01() : new clp_02()
addChild(new_clp)
Something else to consider for memory management, is if you only have the two clips, just keep them both loaded all the time, and change the visibility of them every timer tick:
var timer:Timer = new Timer(2500);
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
var clp1:clp_01 = new clp_01;
var clp2:clp_02 = new clp_02;
addChild(clp1);
addChild(clp2);
Then in your other block of code:
var clp_index = parseInt(bdaily.text) >= parseInt(basketdtarget.text) ? 1 : 2
clp1.visible = clp_index == 1;
clp2.visible = clp_index == 2;

Related

how to remove a child object by removeChild()?

I'm trying to make a custom animated/shooter, from this tutorial: http://flashadvanced.com/creating-small-shooting-game-as3/
By custom, I mean customized, ie, my own version of it.
In it's actionscript, there's a timer event listener with function: timerHandler()
This function adds and removes child "star" objects on the stage (which the user has to shoot at):
if(starAdded){
removeChild(star);
}
and :
addChild(star);
Code works great, but error occurs on scene 2.
The code works great, and I even added some code while learning via google and stackflow to this flash file. I added Scene 2 to it too, and had it called after 9 seconds of movie time. But when it goes to Scene 2, it still displays the star objects and I've been unable to remove these "star" object(s) from Scene 2.
Here's the code I added:
SCENE 1:
var my_timer = new Timer(5000,0); //in milliseconds
my_timer.addEventListener(TimerEvent.TIMER, catchTimer);
my_timer.start();
var myInt:int = getTimer() * 0.001;
var startTime:int = getTimer();
var currentTime:int = getTimer();
var timeRunning:int = (currentTime - startTime) * 0.001; // this is how many seconds the game has been running.
demo_txt.text = timeRunning.toString();
function catchTimer(e:TimerEvent)
{
gotoAndPlay(1, "Scene 2");
}
SCENE 2:
addEventListener(Event.ENTER_FRAME,myFunction);
function myFunction(event:Event) {
timer.stop();
timer.removeEventListener(TimerEvent.TIMER, timerHandler);
stage.removeChild(star);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, cursorMoveHandler);
my_timer.stop(); // you might need to cast this into Timer object
my_timer.removeEventListener(TimerEvent.TIMER, catchTimer);
Mouse.show();
}
stop();
=====================================================
I'm quite new as3, and have just created an account on StackOverflow... even though I've known and read many codes on it since quite some time.
Here's the Edited New Complete Code:
//importing tween classes
import fl.transitions.easing.*;
import fl.transitions.Tween;
//hiding the cursor
Mouse.hide();
//creating a new Star instance
var star:Star = new Star();
var game:Game = new Game();
//creating the timer
var timer:Timer = new Timer(1000);
//we create variables for random X and Y positions
var randomX:Number;
var randomY:Number;
var t:int = 0;
//variable for the alpha tween effect
var tween:Tween;
//we check if a star instance is already added to the stage
var starAdded:Boolean = false;
//we count the points
var points:int = 0;
//adding event handler on mouse move
stage.addEventListener(MouseEvent.MOUSE_MOVE, cursorMoveHandler);
//adding event handler to the timer
timer.addEventListener(TimerEvent.TIMER, timerHandler);
//starting the timer
timer.start();
addChild(game);
function cursorMoveHandler(e:Event):void{
//sight position matches the mouse position
game.Sight.x = mouseX;
game.Sight.y = mouseY;
}
function timerHandler(e:TimerEvent):void{
//first we need to remove the star from the stage if already added
if(starAdded){
removeChild(star);
}
//positioning the star on a random position
randomX = Math.random()*500;
randomY = Math.random()*300;
star.x = randomX;
star.y = randomY;
//adding the star to the stage
addChild(star);
//changing our boolean value to true
starAdded = true;
//adding a mouse click handler to the star
star.addEventListener(MouseEvent.CLICK, clickHandler);
//animating the star's appearance
tween = new Tween(star, "alpha", Strong.easeOut, 0, 1, 3, true);
t++;
if(t>=5) {
gotoAndPlay(5);
}
}
function clickHandler(e:Event):void{
//when we click/shoot a star we increment the points
points ++;
//showing the result in the text field
points_txt.text = points.toString();
}
And on Frame 5 :
//timer.stop();
//timer.removeEventListener(TimerEvent.TIMER, timerHandler);
// uncomment lines above if "timer" is something you've made
stage.removeChild(star);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, cursorMoveHandler);
timer.stop(); // you might need to cast this into Timer object
timer.removeEventListener(TimerEvent.TIMER, timerHandler);
Mouse.show();
stop();
There's no Scene 2 now, in this new .fla file...
Here's a screenshot of the library property of my flash file...: http://i.imgur.com/d2cPyOx.jpg
You'd better drop scenes altogether, they are pretty much deprecated in AS3. Instead, use Game object that contains all the cursor, stars and other stuff that's inside the game, and instead of going with gotoAndPlay() do removeChild(game); addChild(scoreboard); where "scoreboard" is another container class that will display your score.
Regarding your code, you stop having a valid handle to stage that actually contains that star of yours, because your have changed the scene. So do all of this before calling gotoAndPlay() in your catchTimer function.
function catchTimer(e:TimerEvent)
{
//timer.stop();
//timer.removeEventListener(TimerEvent.TIMER, timerHandler);
// uncomment lines above if "timer" is something you've made
stage.removeChild(star);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, cursorMoveHandler);
my_timer.stop(); // you might need to cast this into Timer object
my_timer.removeEventListener(TimerEvent.TIMER, catchTimer);
Mouse.show();
gotoAndPlay(1, "Scene 2");
}
And the code for Scene 2 will consist of a single stop() - until you'll add something there. Also, there should be no event listeners, especially enter-frame, without a code to remove that listener! You add an enter-frame listener on Scene 2 and never remove it, while you need that code to only run once.
Use getChildAt.
function catchTimer(e:TimerEvent)
{
var childCount:int = this.numChildren - 1;
var i:int;
var tempObj:DisplayObject;
for (i = 0; i < childCount; i++)
{
tempObj = this.getChildAt(i);
this.removeChild(tempObj);
}
gotoAndPlay(1, "Scene 2");
}
This will remove all the children you added on scene 1 before going to scene 2.

For loops, arrays and movie clips - how to achieve a dynamic system

I am working on a Flash scene that reads from an XML file to "build" up an animation itself.
Reading the XML is no problem, that works like a charm. My issue is when I come to placing the assets (images) on to the stage.
My code is below:
import flash.display.Sprite;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.MovieClip;
var xmlLoader:URLLoader;
var builderXml:XML;
var container:MovieClip = new MovieClip();
var assetsArray:Array = new Array();
var bg:Sprite;
stage.addChild(container);
init();
function init():void
{
xmlLoader = new URLLoader();
xmlLoader.load(new URLRequest("build_me.xml"));
xmlLoader.addEventListener(Event.COMPLETE, processXML);
}
function processXML(e:Event):void {
builderXml = new XML(e.target.data);
for (var i:int = 0; i < builderXml.assets.*.length(); i++){
var image:MovieClip = new MovieClip();
var assetArray:Array = new Array();
image.x = builderXml.assets.asset[i].start.position.x;
image.y = builderXml.assets.asset[i].start.position.y;
trace(image.x);
assetArray.push(builderXml.assets.asset[i].source);
assetArray.push(builderXml.assets.asset[i].start.scale);
assetArray.push(builderXml.assets.asset[i].start.position.x);
assetArray.push(builderXml.assets.asset[i].start.position.y);
assetArray.push(builderXml.assets.asset[i].start.rotation);
assetArray.push(image);
assetsArray.push(assetArray);
var lc:LoaderContext = new LoaderContext();
lc.checkPolicyFile = false;
var loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
var _myURLRequest = new URLRequest(builderXml.assets.asset[i].source);
loader.load(_myURLRequest, lc);
function onImageLoaded(e:Event):void
{
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onImageLoaded);
image.addChild(e.target.content);
}
container.addChild(assetsArray[i][5]);
}
trace(assetsArray);
}
My XML has 2 assets listed, one 1280 x 720 image for a backdrop and the other is a simple logo that I want to position, using set x and y coordinates.
The problem is that both assets are being added to the same movieclip, despite the fact I am creating a new MC instance inside the FOR loop.
How can I get the assets to adhere to separate movieclips that I can then store in the array (pretty sure I am storing the current MC properly in the array, just happens that the MC contains 2 images, not 1 a piece)
Also, why is it that I cannot access the variable "i" inside the "onImageLoaded" function? It sits inside the FOR loop...
You are using a global variable inside a listener, and expect it to not being changed when the listener would actually fire. Listeners are asynchronous, so you should track which of the loaders fired a Event.COMPLETE event so that you could retrieve a correct instance of image MC out of those prepared at the XML parsing step, and only then stuff the loader's content inside it. This my answer has a method of doing just that, the method you should use is similar to the one that's used to retrieve a corresponding progress bar over there.

Refreshing every XX seconds

I am new to actionscript and flash, but i managed to make code that gets data from php file and refresh result every 30 seconds:
var timerRefreshRate:Number = 30000;
var fatherTime:Timer = new Timer(timerRefreshRate, 0);
fatherTime.addEventListener(TimerEvent.TIMER, testaa);
fatherTime.start();
function testaa(event:Event):void{
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE,varsLoaded);
loader.load(new URLRequest("data.php"));
function varsLoaded (event:Event):void {
this.opaqueBackground = loader.data.color;
title.text=loader.data.title;
banner_text.text=loader.data.text;
}
}
But now i am facing 2 problems:
1.) User must wait 30 seconds for movie to load first time
2.) Setting background color does not work any more.
What am i doing wrong?
You can call your function once to load immediately without waiting 30 seconds. Just change the parameters of the function to default to a null event:
function testaa(event:Event = null):void{
//...
}
Now you can call the function like so:
//...
fatherTime.start();
testaa();
So you start the timer but immediately run the function once.
For your second problem, the issue is most likely that you are using a nested function, so this does not refer to your class but rather the testaa function. Nested functions are bad practice in general and you should avoid them if possible. Move the function and loader reference outside and it should work. Final result should be something like this:
var loader:URLLoader;
var timerRefreshRate:Number = 30000;
var fatherTime:Timer = new Timer(timerRefreshRate, 0);
fatherTime.addEventListener(TimerEvent.TIMER, testaa);
fatherTime.start();
testaa();
function testaa(event:Event = null):void{
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE,varsLoaded);
loader.load(new URLRequest("data.php"));
}
function varsLoaded (event:Event):void {
this.opaqueBackground = loader.data.color;
title.text=loader.data.title;
banner_text.text=loader.data.text;
}

AS3 - Timer not showing

I'm using Flash Pro CS6 to make an easy game where some cubes drop. I added a text field (instance name is timerText) where I wat the time to display. Here is the code:
var time:int =0;
var timer:Timer = new Timer(1000,0);
timer.start();
timer.addEventListener(TimerEvent.TIMER, cubeFall);
function cubeFall(t:TimerEvent) {
time++;
timerText.text = time.toString();
if (time == 3) {
cube_1.play();
}
}
My problem is that the text field, when the game starts, after 1 second the number 1 appears, but it doesn't continue. Any Ideas why?
Your code works fine for me? (Flash CS5.5 output to Flash Plater 10.2).
Try setting the textfield font to _sans. If that works it might be due to you needing to embed the font.
var time:int =0;
var timer:Timer = new Timer(1000,0);
timer.addEventListener(TimerEvent.TIMER, cubeFall);
timer.start();
function cubeFall(t:TimerEvent) {
time++;
timerText.text = time.toString();
if (time == 3) {
cube_1.play();
}
}
//try this one you set the event and then start

FLVPlayback component and Actionscript. Random Flv playback with Arrays.

I have come a little closer with my project, and still need some help please. I have 5 Flvs which i want to play randomly on this page www.music-puppets.com/
The .fla file I have created contains this code:
var files:Array = [ "Sz01Puppet.flv", "Sz02Puppet.flv", "Sz03Puppet.flv", "Sz04Puppet.flv", "Sz05Puppet.flv" ];
var shuffledFiles:Array = shuffleArray(files);
//quick test
var testTimer:Timer = new Timer(1000);
testTimer.addEventListener(TimerEvent.TIMER,updateFile);
testTimer.start();
function updateFile(event:TimerEvent):void{
if(shuffledFiles.length == 0) shuffledFiles = shuffleArray(files); //all files played, repeat process
trace('play file',shuffledFiles[0]);
shuffledFiles.shift();
}
function shuffleArray(source:Array,clone:Boolean = true):Array {
var output:Array = [];
var input:Array = clone ? [].concat(source) : source; //clone ? preserve orignal items by making a copy for shuffling, or not
while(input.length) output.push(input.splice(int(Math.random() * input.length-1),1) [0]);
return output;
}
This script works. In the Output every flv is listed randomly, and then repeated. Next up i want this AS Script to work with an FLV Component.
But how to I get that to work?
In my library I have the 5 flvs, and flvplayback component.
I dragged the FLVPlayback component to the stage, but I can only add one flv in the source. How do I get my working actionscript to work with the FLVPlayback component.
Here you can see how my screen looks like.
capture01.jpg
capture02.jpg
Would be great to get some feedback :)
First of all you need to give your FLVPlayback component an instance name using the properties panel. That will let you talk to it from the code.
Next you will need to add a listener to the FLVPlayback component to detect when each video finishes. Let's assume you've given it an instance name of myVideo:
myVideo.addEventListener(VideoEvent.COMPLETE,onVideoComplete);
You will need a handler function for this, and that will look similar to the function you currently use for each iteration of your timer:
function onVideoComplete(event:VideoEvent):void {
if(shuffledFiles.length == 0) shuffledFiles = shuffleArray(files); //all files played, repeat process
myVideo.source = shuffledFiles.shift(); //grab the first array item to play in the FLVPlayback component
}
Finally, make sure that your FLVPlayback component is set to play a new source automatically, then assign the first video to get things going:
myVideo.autoPlay = true;
myVideo.source = shuffledFiles.shift();
If anyone is interested. I have got the running code :)
import flash.events.Event;
import fl.video.*;
var files:Array;
var shuffledFiles:Array;
loaderInfo.addEventListener(Event.COMPLETE,ready);
function ready(event:Event):void{
loaderInfo.removeEventListener(Event.COMPLETE,ready);
//swf rescale setup
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.addEventListener(Event.RESIZE,stageResized);
//get FlashVars - a string converted into an Array by spliting it on the , character
//if the files FlashVar is setup correctly use the data, else use default values
if(loaderInfo.parameters.files != undefined) files = loaderInfo.parameters.files.indexOf(',') > 0 ? loaderInfo.parameters.files.split(",") : [loaderInfo.parameters.files];
else files = [ "Sz01Puppet.flv", "Sz02Puppet.flv", "Sz03Puppet.flv", "Sz04Puppet.flv", "Sz05Puppet.flv" ];
shuffledFiles = shuffleArray(files);
//play the 1st video
videoPlayer.source = shuffledFiles[0];
shuffledFiles.shift();
//see when the video finished playing
videoPlayer.addEventListener(VideoEvent.COMPLETE,videoFinished);
}
function videoFinished(event:VideoEvent):void{
if(shuffledFiles.length == 0) shuffledFiles = shuffleArray(files);//all files played, repeat process
videoPlayer.source = shuffledFiles[0];//play the first video in the random list
videoPlayer.play();
trace('playing',shuffledFiles[0]);
shuffledFiles.shift();//remove the first video from the random list (e.g. [2,0,1].shift() becomes [0,1])
}
function stageResized(event:Event):void{
videoPlayer.width = stage.stageWidth;
videoPlayer.height = stage.stageHeight;
}
function shuffleArray(source:Array,clone:Boolean = true):Array {
var output:Array = [];
var input:Array = clone ? [].concat(source) : source;//clone ? preserve orignal items by making a copy for shuffling, or not
while(input.length) output.push(input.splice(int(Math.random() * input.length-1),1)[0]);
return output;
}