AS3 - Error - The supplied DisplayObject must be a child - actionscript-3

I'm using the following code to display an advertisement in a flash game. It works great except for one small issue. If the startButton function gets called before the ad is displayed I get an error saying:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at VirusDefender/clickStart()[VirusDefender::frame1:17]
There are no errors when the advert is on the stage. I tried wrapping the removeChild in a try catch but that did not work.
Could someone please tell me how to prevent the removeChild line from being called if the ad has not been displayed yet. Sometimes it takes up to 3 seconds for the ad to show so people may click before it gets on the stage.
stop();
//Start Button
startScreen.startButton.addEventListener(MouseEvent.CLICK,clickStart);
function clickStart(event:MouseEvent)
{
sndFire=new fire_sound();
sndFireChannel=sndFire.play();
removeChild(l);
gotoAndStop("play");
}
// Help Button
startScreen.helpButton.addEventListener(MouseEvent.CLICK,clickHelp);
function clickHelp(event:MouseEvent)
{
sndFire=new fire_sound();
sndFireChannel=sndFire.play();
removeChild(l);
gotoAndStop("help");
}
// SMAATO Advertising Code for Start Page
var request:URLRequest = new URLRequest("http://soma.smaato.com/oapi/reqAd.jsp");
var variables:URLVariables = new URLVariables();
variables.adspace = "0";
variables.pub = "0";
variables.devip = "127.0.0.1";
variables.format = "IMG";
variables.adcount = "1";
variables.response = "XML";
request.data = variables;
var loader:URLLoader = new URLLoader();
var l:Loader = new Loader();
loader.addEventListener(Event.COMPLETE, onComplete);
loader.load(request);
function onComplete(e:Event):void
{
var data:XML = new XML(loader.data as String);
var status:String = data.*::status.toString();
if(status == "success")
{
var ad:XMLList = data.*::ads.*::ad;
var link:String = ad.*::link.toString();
l.load(new URLRequest(link));
addChild(l);
l.x = 135;
l.y = 265;
var clickurl:String = ad.*::action.#target.toString();
l.addEventListener(MouseEvent.CLICK, onAdClick);
}
function onAdClick(e:MouseEvent):void
{
var request:URLRequest = new URLRequest(clickurl);
navigateToURL(request);
}
}
Thanks! Rich

Wrap the line into:
if (l != null && contains(l)) {
removeChild(l);
}
This will check if l is not null and a child, and only then removes it.

Alternatively, as Loader is a DisplayObject, you can simply add it to the stage before anything else (it need not have finished loading before you can add it to the stage) and remove it when start is pressed, that way you wont have it lingering or popping in later if you do in fact want it gone on press.

Related

ActionScript3 remove child error

I recently have been converting an as2 fla to as3 (new to AS3) and have the entire thing working on export, but I am getting an error when I try to remove previously loaded swf's before a new swf is loaded
ArgumentError: Error #2025: The supplied DisplayObject
must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at MethodInfo-11()
I know the error relates to my removeChild code here:
`stage.addEventListener(MouseEvent.CLICK, removeSWF);
function removeSWF (e:MouseEvent):void
{
if(vBox.numChildren !=0){
// swfLoader.unloadAndStop();
vBox.removeChild(swfLoader);// empty the movieClip memory
}
}`
However, I cannot seem to find a suitable rewrite for this code that will work and not have an error. This code IS working, so I'm not sure if it would be worth my time to fix this error, or just leave it. I've already messed with it for a couple days, so at this point it's just frustrating me that I cannot fix it.
The stage mouse click listener is useful in this case because I have a back button not shown in this code that clears the loaded swf's before moving to another scene.
Does anyone see a simple solution for this, or do you think it is unnecessary to pursue since the code does what I require?
ENTIRE CODE:
function launchSWF(vBox, vFile):void {
var swfLoader:Loader = new Loader();
var swfURL:URLRequest = new URLRequest(vFile);
swfLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadProdComplete);
swfLoader.load(swfURL);
function loadProdComplete(e:Event):void {
trace("swf file loaded");
vBox.removeChild(preLoader);
vBox.addChild(swfLoader);
currentSWF = MovieClip(swfLoader.content);
currentSWF.gotoAndPlay(1);
currentSWF.addEventListener(Event.ENTER_FRAME , checkLastFrame);
swfLoader.x = 165;
swfLoader.y = 15;
function checkLastFrame(e:Event):void {
if (currentSWF.currentFrame == currentSWF.totalFrames) {
currentSWF.stop();
// trace("DONE");
}
}
}
var preLoader:loader = new loader();
preLoader.x = 450;
preLoader.y = 280;
vBox.addChild(preLoader);
function onProgressHandler(event:ProgressEvent){
var dataAmountLoaded:Number=event.bytesLoaded/event.bytesTotal*100;
//preLoader.bar.scaleX = dataAmountLoaded/100;
preLoader.lpc.text= int(dataAmountLoaded)+"%";
//trace(preLoader.bar.scaleX );
}
//NEW ERRORS BUT WORKING
stage.addEventListener(MouseEvent.CLICK, removeSWF);
function removeSWF (e:MouseEvent):void
{
if(vBox.numChildren !=0){
// swfLoader.unloadAndStop();
vBox.removeChild(swfLoader);// empty the movieClip memory
}
}
}
var container:MovieClip = new MovieClip();
var currentSWF:MovieClip = new MovieClip();
fall_b.addEventListener(MouseEvent.CLICK, fall_bClick);
function fall_bClick(e:MouseEvent):void {
var swfFile:String = 'load/fall.swf';
launchSWF(container, swfFile);
addChild(container);
}
face_b.addEventListener(MouseEvent.CLICK, face_bClick);
function face_bClick(e:MouseEvent):void {
var swfFile:String = 'load/face.swf';
launchSWF(container, swfFile);
addChild(container);
}
rott_b.addEventListener(MouseEvent.CLICK, rott_bClick);
function rott_bClick(e:MouseEvent):void {
var swfFile:String = 'load/rottgut.swf';
launchSWF(container, swfFile);
addChild(container);
}
//MORE SWFS...
Any advice anyone has is appreciated
First of all function launchSWF(vBox, vFile):void { isn't closed. You've also got function inside functions which is easy enough for you to solve if you click the lines the curly brackets start and end on to track them.
I can't see anything wrong with the code you said has an error but I'm guessing this isn't all the code. If you using Flash Professisonal you can use permit debugging to show the line the error is on.
EDIT: Please note this hasn't been tested as I'm on my mobile writing out code. That being said this should now work:
var container:MovieClip;
var currentSWF:MovieClip;
var swfFile:String;
var swfLoader:Loader;
var preLoader:Loader;
var swfURL:URLRequest;
init();
function init():void {
preLoader = new Loader();
preLoader.x = 450;
preLoader.y = 280;
vBox.addChild(preLoader);
container = new MovieClip();
currentSWF = new MovieClip();
fall_b.addEventListener(MouseEvent.CLICK, fall_bClick);
face_b.addEventListener(MouseEvent.CLICK, face_bClick);
rott_b.addEventListener(MouseEvent.CLICK, rott_bClick);
stage.addEventListener(MouseEvent.CLICK, removeSWF);
}
function launchSWF(vBox, vFile):void {
swfLoader = new Loader();
swfURL = new URLRequest(vFile);
swfLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadProdComplete);
swfLoader.load(swfURL);
}
function loadProdComplete(e:Event):void {
trace("swf file loaded");
vBox.removeChild(preLoader);
vBox.addChild(swfLoader);
currentSWF = MovieClip(swfLoader.content);
currentSWF.gotoAndPlay(1);
currentSWF.addEventListener(Event.ENTER_FRAME , checkLastFrame);
swfLoader.x = 165;
swfLoader.y = 15;
}
function checkLastFrame(e:Event):void {
if (currentSWF.currentFrame == currentSWF.totalFrames) {
currentSWF.stop();
// trace("DONE");
}
}
function onProgressHandler(event:ProgressEvent) {
var dataAmountLoaded:Number = (event.bytesLoaded / event.bytesTotal * 100);
//preLoader.bar.scaleX = dataAmountLoaded/100;
preLoader.lpc.text = int(dataAmountLoaded)+"%";
//trace(preLoader.bar.scaleX );
}
function removeSWF (e:MouseEvent):void {
if(vBox.numChildren !=0){
//swfLoader.unloadAndStop();
vBox.removeChild(swfLoader);// empty the movieClip memory
}
}
function fall_bClick(e:MouseEvent):void {
swfFile = 'load/fall.swf';
launchSWF(container, swfFile);
addChild(container);
}
function face_bClick(e:MouseEvent):void {
swfFile = 'load/face.swf';
launchSWF(container, swfFile);
addChild(container);
}
function rott_bClick(e:MouseEvent):void {
swfFile = 'load/rottgut.swf';
launchSWF(container, swfFile);
addChild(container);
}
I have this rewritten. I could not get the vBox errors cleared in the original code, and I was getting many other errors with what was posted. The vBox code was seen on a tutorial. I think it was supposed to reference the loader for the preloader and the swf, and vFile was for the actual .swf. The following code preloads multiple swfs and clears them with no errors. I appreciate your help AntBirch. I'm beginning to understand loaders in as3 a little more now.
//LOAD FIRST PIECE ON OPEN (required to removeChild later)
var swfLoader:Loader = new Loader();
var defaultSWF:URLRequest = new URLRequest("load/fall.swf");
swfLoader.load(defaultSWF);
swfLoader.x = 165;
swfLoader.y = 15;
addChild(swfLoader);
//PRELOADER
var preLoader:loader = new loader();
preLoader.x = 450;
preLoader.y = 280;
function loadProdComplete(e:Event):void {
trace("swf file loaded");
removeChild(preLoader);
addChild(swfLoader);
}
function onProgressHandler(event:ProgressEvent){
var dataAmountLoaded:Number=event.bytesLoaded/event.bytesTotal*100;
preLoader.lpc.text= int(dataAmountLoaded)+"%";
}
//BUTTONS
function btnClick(event:MouseEvent):void {
swfLoader.unloadAndStop();
removeChild(swfLoader);
swfLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadProdComplete);
addChild(preLoader);
var newSWFRequest:URLRequest = new URLRequest("load/" + event.target.name + ".swf");
swfLoader.load(newSWFRequest);
swfLoader.x = 165;
swfLoader.y = 15;;
addChild(swfLoader);
}
// BUTTON LISTENERS
fall.addEventListener(MouseEvent.CLICK, btnClick);
face.addEventListener(MouseEvent.CLICK, btnClick);
rott.addEventListener(MouseEvent.CLICK, btnClick);
angel.addEventListener(MouseEvent.CLICK, btnClick);
ratts.addEventListener(MouseEvent.CLICK, btnClick);
metal.addEventListener(MouseEvent.CLICK, btnClick);
//etc...
//BACK BUTTON
BB3.addEventListener(MouseEvent.CLICK, BB3Click);
function BB3Click(e:MouseEvent):void {
swfLoader.unloadAndStop();
removeChild(swfLoader);
this.gotoAndPlay(1 ,"Scene 2")
}

actionscript 3.0 function calling using button click

im creating a simple flash playlist using buttons, in my stage i have 4 buttons which is button for song1,song2, stop and play. i have a working code for this one, but i decided to revise it because my previous code is like, per song they have each stop and play button,so i created this one to have a dynamic stop and play, i created a function for each song, the function will change the filename of the song to be loaded,
heres the catch, so i first pick a song, (either song1 or song2) then i click stop, then when i select a new song this error appears
Error: Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.
at flash.media::Sound/_load()
at flash.media::Sound/load()
at playlist_fla::MainTimeline/songSelect1()
i think its not calling the second function because i cant see the trace i put inside it,anyway heres my code, sorry for the long post,
THANKS IN ADVANCE
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var myTransform = new SoundTransform();
var lastPosition:Number = 0;
var song;
song1.addEventListener(MouseEvent.CLICK,songSelect1);
function songSelect1(e:MouseEvent):void{
song = "<filenameofthe1stsong>";
mySound.load(new URLRequest(song));
myTransform.volume = 0.5;
myChannel.soundTransform = myTransform;
lastPosition=0;
trace(1);
}
song2.addEventListener(MouseEvent.CLICK,songSelect2);
function songSelect2(e:MouseEvent):void{
song = "<filenameofthe2ndsong>";
mySound.load(new URLRequest(song));
myTransform.volume = 0.5;
myChannel.soundTransform = myTransform;
lastPosition=0;
trace(2);
}
btnStop.addEventListener(MouseEvent.CLICK,onClickStop);
function onClickStop(e:MouseEvent):void{
lastPosition = myChannel.position;
myChannel.stop();
}
btnPlay.addEventListener(MouseEvent.CLICK,onClickPlay);
function onClickPlay(e:MouseEvent):void{
myChannel = mySound.play(lastPosition);
myChannel.soundTransform = myTransform();
}
Correction:
According to Adobe:
Once load() is called on a Sound object, you can't later load a
different sound file into that Sound object. To load a different sound
file, create a new Sound object.
So, creating a new sound object would be the only way to fix it.
- - - Original Post - - -
If you enable debugging in your flash settings, it'd be easier to determine exactly what line is causing issues. That said, your code doesn't look incorrect apart from defining your sound transform twice. Try this:
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var myTransform = new SoundTransform();
myChannel.soundTransform = myTransform;
var lastPosition:Number = 0;
var song;
song1.addEventListener(MouseEvent.CLICK,songHandler);
song2.addEventListener(MouseEvent.CLICK,songHandler);
btnStop.addEventListener(MouseEvent.CLICK,onClickStop);
btnPlay.addEventListener(MouseEvent.CLICK,onClickPlay);
function songHandler(e:MouseEvent):void {
switch (e.currentTarget.name) {
case "song1":
songSelect("<filenameofthe1stsong>")
break;
case "song2":
songSelect("<filenameofthe2ndsong>")
break;
}
}
function songSelect(songPath:String):void {
mySound.load(new URLRequest(songPath));
myChannel.soundTransform.volume = 0.5;
lastPosition = 0;
trace("Loading " + songPath);
}
function onClickStop(e:MouseEvent):void {
lastPosition = myChannel.position;
myChannel.stop();
}
function onClickPlay(e:MouseEvent):void {
myChannel = mySound.play(lastPosition);
myChannel.soundTransform = myTransform();
}

Force to refresh movie clip?

I have a really simple code piece like that;
loadingMc.visible = true;
trace("ok");
// send photo to server
loadingMc.visible = false;
Sending photo takes 3-5 seconds but movie clip becomes visible only for last second of process. I can see "ok" message in output at start of the process. So i assume problem is not redrawing movie clip. Is there any option to force redraw before process starts?
UPDATE:
Sending to server part;
upload.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void{
loadingText.visible = true;
trace("ok");
var bmd:BitmapData = new BitmapData(1024,768,true,0);
bmd.draw(imageArea);
savePicToServer(bmd);
});
function savePicToServer(bmd:BitmapData):void
{
var jpgEncoder:JPGEncoder = new JPGEncoder(85);
var jpgStream:ByteArray = jpgEncoder.encode(bmd);
var loader:URLLoader = new URLLoader();
configureListeners(loader);
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var request:URLRequest = new URLRequest("http://localhost/test/upload.php?key=prvkey");
request.requestHeaders.push(header);
request.method = URLRequestMethod.POST;
request.data = jpgStream;
loader.load(request);
}
In the COMPLETE event;
loadingText.visible = false;
EDIT
Just from reading your code, I don't see why this should not be working - but FP does strange things sometimes.
In similar cases, I used setTimeout() to force the player to delay the subsequent actions and allow the screen to refresh:
upload.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void{
loadingText.visible = true;
trace("ok");
setTimeout( doSave, 10 );
});
private function doSave() : void {
var bmd:BitmapData = new BitmapData(1024,768,true,0);
bmd.draw(imageArea);
savePicToServer(bmd);
}
If this still doesn't work, perhaps a longer timeout will do the trick - but 10ms usually should be enough to refresh the screen.
EDIT
Another way would be to add and remove an ENTER_FRAME listener to make sure the frame really was refreshed:
upload.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void{
loadingText.visible = true;
trace("ok");
addEventListener( Event.ENTER_FRAME, onNextFrame );
});
private function onNextFrame( ev:Event ) : void {
removeEventListener( Event.ENTER_FRAME, onNextFrame );
doSave();
}
private function doSave() : void {
var bmd:BitmapData = new BitmapData(1024,768,true,0);
bmd.draw(imageArea);
savePicToServer(bmd);
}

action script 3.0 .I had tried a program that should move the dragger as well as the content movieclip,

In this code i need a progressbar to progress through while the imported .swf file is playing, meanwhile i should able to drag the dragger in the progress bar (i.e the rate of movement of dragger should sync with rate of .swf file playing). I got Argument error: #2109 Frame label 459.99 not found in scene1.
var loader:Loader = new Loader();
playBtn.visible = true;
pauseBtn.visible = false;
btn_00.addEventListener(MouseEvent.CLICK, fileLoaded);
btn_01.addEventListener(MouseEvent.CLICK, fileLoaded);
btn_02.addEventListener(MouseEvent.CLICK, fileLoaded);
function fileLoaded(evt:MouseEvent):void
{
var fileName:String = evt.currentTarget.name;
var fileNumber:String = fileName.split("_")[1];
var urlPath:String = "assets/file_" + fileNumber + ".swf";
loader.load(new URLRequest(urlPath));
addChild(loader);
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);
function swfLoaded(event:Event):void
{
addEventListener(Event.ENTER_FRAME, trackPlayback);
}
function trackPlayback(event:Event):void
{
var perPlayed:Number = MovieClip(loader.content).currentFrame / MovieClip(loader.content).totalFrames;
progressbar.drag.x = (progressbar.bar.width - progressbar.drag.width) * perPlayed;
}
progressbar.drag.buttonMode = true;
var dragClicked:Boolean = false;
var xpos:Number = progressbar.bar.x * progressbar.drag.width;
progressbar.drag.addEventListener(MouseEvent.MOUSE_DOWN,dragMouseDown);
function dragMouseDown(evt:MouseEvent):void
{
trace(" inside mouse down ");
dragClicked = true;
progressbar.drag.startDrag(false,new Rectangle(xpos,0,progressbar.width-progressbar.drag.width,0));
}
progressbar.drag.addEventListener(MouseEvent.MOUSE_UP,dragMouseUp);
function dragMouseUp(evt:MouseEvent):void
{
dragClicked = false;
progressbar.drag.stopDrag();
var cnt:Number = (progressbar.drag.x/(progressbar.width-progressbar.drag.width))*MovieClip(loader.content).totalFrames;
MovieClip(loader.content).gotoAndPlay(cnt);
}
Pls solve my issue.
Thanks in advance.
To access a specific frame, you need to provide an integer value where at the moment you are using a floating-point value.
A simple fix would be to cast the Number to an int:
MovieClip(loader.content).gotoAndPlay(int(cnt));

as3 moving image from one mc to another

With the code below I created some imgMcA and some imgMcB then I loaded images into imgMcA ones. ImgMcBs have no image at that moment. So if one of imgMcA is clicked the image should be transferred to one of the empty imgMcBs (may be randomly) and if imgmcB is clicked later the image should move back to its imgMcA back. I could not find out how I can accomplish this.
Thanks in advance
function imageList(mcname, img, index){
var imgMcA:MovieClip=new MovieClip();
imgMcA.graphics.beginFill(0x000000);
imgMcA.graphics.drawRect(0,0,imgWidth,imgHeight);
imgMcA.graphics.endFill();
imgMcA.name=lemma;
imgMcA.addEventListener(MouseEvent.CLICK, moveImage);
var imgMcB:MovieClip=new MovieClip();
imgMcB.graphics.beginFill(0x000000);
imgMcB.graphics.drawRect(0,0,imgWidth,imgHeight);
imgMcB.graphics.endFill();
imgMcB.name=index;
addChild(imgMcB);
var imgLoader:Loader = new Loader();
imgLoader.load(new URLRequest(img));
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, changeProperties);
imgLoader.mouseEnabled=false;
imgMcA.addChild(imgLoader);
}
function moveImage(evnt:MouseEvent){
}
You could linked mcA & mcB by adding them to the same parent.
function createBlock():void
{
var imgLoader:Loader = new Loader();
//add the loading code here...
var mcA:Sprite = new Sprite();
var mcB:Sprite = new Sprite();
// add Click event listeners for both Mcs here...
var parent:Sprite = new Sprite();
//add Children
parent.addChild(mcA);
parent.addChild(mcB);
addChild(parent);
}
function mouseClickHandler(event:MouseEvent)
{
var dispatcher:Sprite = event.currentTarget as Sprite;
//if you added a Loader to it
if( dispatcher.numChildren > 0)
{
//retrieve the image
var img:Loader = dispatcher.getChildAt(0);
//identify the parent
var parent:Sprite = dispatcher.parent;
var index:int = parent.getChildIndex(dispatcher);
//identify the receiving MC
//of course this only works with two children!!!
if(index > 0)
var receiver:Sprite = parent.getChildAt(0) as Sprite;
else
receiver = parent.getChildAt(1) as Sprite;
//add the image to the other MC
receiver.addChild(img);
}
}
The rest is not too complicated to achieve. You will need to use a Boolean and add a TextField. If the TextField contains text, set the Boolean to true.
It may be worth looking at Classes or you could use an Object as a container for the MovieClips, the TextField and the Boolean, although a Class will give you more flexibility...
With a Class, you wouldn't have to iterate in order to find what does what. Your Click listener would look something like this:
private function mouseClickHandler(event:MouseEvent)
{
receiver.addChild( image );
if( hasText)
imageReturn();
}