Trying to remove child with mouseclick - actionscript-3

So, my question is as follows.
Why am I getting this error
(TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/removeChild()
at TargetMain/killTarget())
when trying to remove objects from the stage with a mouse click?
My code for the application is below.
package
{
import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.ui.Keyboard;
public class TargetMain extends MovieClip
{
public function TargetMain()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, spawner);//Spawning function listener
stage.addEventListener(MouseEvent.CLICK, killTarget);//Clicking function listener
}
public function spawner(k:KeyboardEvent):void
{
if(k.keyCode == 32)
{
trace ("spawned");
var theTarget:ParaspriteFull = new ParaspriteFull();
theTarget.x = Math.floor(Math.random() * stage.stageWidth);
theTarget.y = Math.floor(Math.random() * stage.stageHeight);
addChild(theTarget);
}
}
public function killTarget(toDie:MouseEvent):void
{
trace ("clicked")
var deadTarget:ParaspriteFull = (toDie.target as ParaspriteFull);
//Below is where I continually get an error and do not know how to fix it.
//This is also after searching the internet for hours trying to solve my issue.
//MovieClip(deadTarget).parent.removeChild(deadTarget);
removeChild(deadTarget);
}
}
}
Any help is greatly appreciated.

The error means deadTarget is null, so if you just want to remove deadTarget from stage, try this
var deadTarget:DisplayObject = toDie.target as DisplayObject;
if ( deadTarget && deadTarget.parent) {
deadTarget.parent.removeChild(deadTarget);
}
Or you should find out the actural type of deadTarget.

You are listening for click on stage. So, any clicks (whether it's on ParaspriteFull object or not) would fire killTarget. One way to avoid exception is to do as Pan has suggested in the answer to essentially do nothing in click killTarget if the clicked object isn't of type ParaspriteFull.
But, I'd suggest to listen for clicks on ParaspriteFull objects and not on stage. i.e. remove
stage.addEventListener(MouseEvent.CLICK, killTarget);//Clicking function listener
from your constructor and modify spawner function to add click listener as:
theTarget.addEventListener(MouseEvent.CLICK, killTarget);//Clicking function listener
Also, remove listener on ParaspriteFull object in killTarget as:
deadTarget.removeEventListener(MouseEvent.CLICK, killTarget);//Remove clicking function listener

Related

Custom events not working in AS3

I have an event called SelectEvent. Whenever I click the buyer, the select event should be launched. But that is not what is happening.
My code of base:
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
public class FashionFrenzy extends MovieClip
{
public var Buyer_mc:Buyer;
public var Buyers:Array;
private var BuyerNumber:Number;
public var xpositions:Array;
public var ypositions:Array;
public var SelectedBuyer:Number;
public function FashionFrenzy()
{
GameTimeController();
xpositions=new Array();
xpositions.push(523,563,603);
ypositions=new Array();
ypositions.push(377,377,377);
Buyers = new Array ;
BuyerNumber=0;
Time_mc.gameTimer.addEventListener(TimerEvent.TIMER,GenerateBuyers);
addEventListener(SelectEvent.BUYERSELECT,showselectbuyer);
}
public function GameTimeController()
{
Time_mc.StartGame();
}
public function showselectbuyer(event:SelectEvent):void
{
trace("Bamba");
}
public function GenerateBuyers(event:TimerEvent):void
{
if(BuyerNumber<6)
{
if (Math.random() < 0.01)
{
var position:Number = Math.floor(Math.random()*3);
var newBuyer_mc = new Buyer(xpositions[position],ypositions[position],BuyerNumber);
ypositions[position]-=40;
Buyers.push(newBuyer_mc);
addChild(newBuyer_mc);
BuyerNumber++;
}
}
for each (var buyer_mc:Buyer in Buyers)
{
if(buyer_mc.walking==true)
{
buyer_mc.Enter();
}
}
}
}
}
My code of the buyer:
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
public class Buyer extends MovieClip
{
public var buyerTimer:Timer;
public var walking:Boolean;
public var stopposition:Number;
public var buyerCode:Number;
public function Buyer(startx:Number, stopy:Number, code:Number)
{
x=startx;
stopposition=stopy;
walking=true;
buyerCode=code;
BuyerProperties();
}
public function Enter():void
{
if(y>stopposition)
{
walking=false;
StartFunction();
}
else
{
y= y+3;
}
}
public function BuyerProperties():void
{
buyerTimer = new Timer( 25 );
trace(" I am generated");
}
public function StartFunction():void
{
buyerTimer.start();
addEventListener(MouseEvent.CLICK,Select);
trace("My timer starts now within Buyer.as");
}
public function Select(event:MouseEvent):void
{
trace(buyerCode);
dispatchEvent( new SelectEvent(SelectEvent.BUYERSELECT));
}
}
}
Now that when I'm clicking the buyer, the MouseEvent.CLICK is activated and then in the buyer.as, buyercode is traced on the screen. But the event is not dispatched or else it is dispatched but the eventlistener is not executing the code. I'm not getting any runtime errors. the function "showselectbuyer" is never even launched.
How should I solve it?
The accepted answer is incorrect. The provided solution works but for the wrong reasons. It creates a direct dependency to the object supposed to listen to the custom event and then makes that object be the dispatcher. All together this makes the whole idea of using event/custom event unnecessary at best since in that case a simple callback would work just as well. Instead using the useCapture flag would make the whole system work as expected:
addEventListener(SelectEvent.BUYERSELECT,showselectbuyer, true);
The accepted solution is also the inverse way of dealing with non DisplayObject event propagation. The dispatcher should be the listener (no dependencies) and not the listener should be the dispatcher (dependency necessary).
The trouble with custom events is that they don't bubble up the display list, so in case your event to be registered you need to dispatch it to the class instance that has a listener to that event attached. In your case it's an instance of FashionFrenzy. Apparently buyers don't know about a fashion frenzy instance they are running in, so they dispatch the event to themselves and wonder why no one else listens. In order to resolve this, either attach the listener to the buyer, or in the buyer class dispatch the event to parent, which is apparently the instance you want to receive the event.

How to access class functions during events from currentTarget object in AS3

I have loaded movieClip to stage and was performing some events on that movieClip. Movie clip has own public functions and variables, and those are NOT accessible through currentTarget object in events.
Here is sample class:
package {
import flash.display.MovieClip;
import flash.display.Shape;
public class SampleClass extends MovieClip {
var str:String;
public function SampleClass() {
str="Some string";
/* draw just a sample rectangle to click on it */
var rectangle:Shape=new Shape ;
rectangle.graphics.beginFill(0x000000);
rectangle.graphics.drawRect(0,0,100,100);
rectangle.graphics.endFill();
}
public function getStr():String {
return str;
}
}
}
And here is loading on the stage and creating event:
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class MainClass extends MovieClip {
var a:SampleClass;
public function MainClass() {
a=new SampleClass();
addChild(a);
a.addEventListener(MouseEvent.CLICK,clickEvent);
}
function clickEvent(evt:MouseEvent):void {
var Obj=evt.currentTarget;
trace (Obj.getStr());
}
}
}
Tracing will return null instead of string value cause currentTarget is an Object, not a Class (movieClip). Any idea how to solve this?
//use this code it will work
function clickEvent(evt:MouseEvent):void {
var Obj:SampleClass = evt.currentTarget as SampleClass;
trace (Obj.getStr());
}
I dont know if your problem is solved now but the code you posted in your question worked okay for me..
What I did to test it..
In a new blank document, open Library (ctrl+L) and right-clicked to make symbol (MovieClip)
In linkage section, tick Export for Actionscript and call it SampleClass
Right click symbol item now added in Library list and choose Edit Class option
In that SampleClass I replace all with a paste of your code BUT NOTE: after that line rectangle.graphics.endFill();.. I also added the line addChild(rectangle);
Now when I test (Debug: Ctrl+Shift+Enter).. I see a black square that traces "Some string" everytime I click it..
Your MainClass.as was attached to the FLA as the Document Class (see Properties with Ctrl+F3)
I hope this is useful to you or anyone else trying this kind of code. Any issues just add a comment. Thanks.

event.bytesLoaded - Access of undefined property event

1120: Access of undeined property event.
...is thrown for both event.bytesLoaded and event.bytesTotal
public class Main extends MovieClip {
public function Main() {
system_load.bar.scaleX = 0;
this.stage.addEventListener(Event.ENTER_FRAME, this._loadUpdate);
}
private function _loadUpdate( e:Event ):void {
var bl:int = event.bytesLoaded;
var bt:int = event.bytesTotal;
system_load.bar.scaleX = (bl/bt);
}
}
I'm unsure of what to import to make this work. Currently has the following imported:
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
Just ask and I'll provide with more details.
The reason you are getting this error is because the listener you added is using an Event type and not a ProgressEvent. The ProgressEvent class has the properties bytesLoaded and bytesTotal, whereas the Event class does not. What you are looking for is usage of the ProgressEvent.PROGRESS. An example would be:
myLoader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, loadUpdate );
Although your current implementation is not actually loading anything because you added the listener to the stage and not a loader, so the progress would not be displayed. For relevant examples check out the ProgressEvent class here:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/ProgressEvent.html#includeExamplesSummary
Here's a quick and dirty example I put together loading an image:
var myLoader:Loader = new Loader();
myLoader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, loadUpdate );
myLoader.load( new URLRequest("path/to/image.png") );
Then you could just use your loadUpdate() as is.
your event variable is called e and not event. Try:
private function _loadUpdate( event:ProgressEvent ):void {
var bl:Number = event.bytesLoaded;
var bt:Number = event.bytesTotal;
system_load.bar.scaleX = (bl/bt);
}
Edit: i suggest you to use ProgressEvent if you want to access to bytesLoaded and bytesTotal

TypeError: Error #1009 with loading external SWF file

I was making 3D File Viewer in Flash Player with AS3.0
and i found AWD Viewer from Away3D Example File.
(http://awaytools.com/awaybuilder/tutorial-01/AwayBuilderTutorial01_SampleFiles.zip)
it works fine.
and i loaded it in my 'Main' swf file. but it's not work. it kept showing error to me.
error message is below
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AWDViewer/initEngine()[C:\Users\wintec\Desktop\Flash3DViewer\source\AWDViewer.as:74]
at AWDViewer/init()[C:\Users\wintec\Desktop\Flash3DViewer\source\AWDViewer.as:57]
at AWDViewer()[C:\Users\wintec\Desktop\Flash3DViewer\source\AWDViewer.as:49]
and that error line is just this
line 74 : stage.scaleMode = StageScaleMode.NO_SCALE;
line 57 : initEngine();
line 49 : init();
and I know that error message mean there's no properties that name.
I checked that, there's nothing wrong.
also, when I loading another swf file in my 'Main'swf, that's works. weird...
I don't understand why this error kept showing.
please help me.
below code is from Main.as
package
{
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
public class Flash3DViewer extends MovieClip
{
private var _request:URLRequest = new URLRequest("AWDViewer.swf");
private var _loader:Loader = new Loader()
public function Flash3DViewer()
{
init();
}
private function init():void
{
stop();
_loader.load(_request);
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, initLoaded);
}
private function initLoaded():void
{
_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, initLoaded);
var extSwf = _loader.content as MovieClip;
swfContainer.addChild(extSwf);
trace("contents loaded");
}
}
}
I found the issue with your application based on the code you provided via DropBox. And just as I suspected, the stage property was being referenced before the object's addition to the stage was completed, which is why the null reference error was being generated.
The AWDViewer class was prematurely calling the stage property from one of the functions that is being called when the init function is called. I've updated the Flash3DViewer.as and AWDViewer.as files with the proper usage of the ADDED_TO_STAGE event so that this does not occur. I have also added comments to the code for you to follow along. Also, I had to modify the init function in the AWDViewer class to take a parameter of type Event to account for the fact that the function is now called when the ADDED_TO_STAGE event fires.
Flash3DViewer.as:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
public class Flash3DViewer extends MovieClip
{
private var loader:Loader;
public function Flash3DViewer():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
loadSWF("AWDViewer.swf");
}
private function loadSWF(url:String):void
{
var urlRequest:URLRequest = new URLRequest(url);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
loader.load(urlRequest);
addChild(loader);
}
private function onLoaded(e:Event):void
{
var target:AWDViewer = e.currentTarget.loader.content as AWDViewer;
trace(target);
//target.init(); // no longer need to call the init function manually as the AWDViewer calls it when it 'knows' it has been added to the stage. This line can be deleted.
addChild(target);
}
}
}
AWDViewer.as:
public function AWDViewer()
{
/* Used ADDED_TO_STAGE event to know when to trigger the init
function call to avoid the null reference errors when accessing
the 'stage' property */
addEventListener(Event.ADDED_TO_STAGE,init);
// init(); // no longer need to manually call the init function as the ADDED_TO_STAGE event listener will take care of this. This line can be deleted.
}
/**
* Global initialise function
*/
public function init(e:Event):void
{
initEngine();
initListeners();
AssetLibrary.enableParser(AWD2Parser);
//kickoff asset loading
var loader:Loader3D = new Loader3D();
loader.load(new URLRequest("assets/monkey.awd"));
_view.scene.addChild(loader);
}
While I did attempt to compile the code above, and the null reference errors ceased to generate with my corrected code, there were some compiler errors on my machine because of the different configurations of our computers. You'll just need to ensure that these compiler errors do not appear on your machine.
Warning: Library path "C:\Users\wintec\Desktop\3D_VR\source\libs" does not resolve to a valid directory.
Warning: Library path "$(FlexSDK)/frameworks/libs/flex.swc" does not resolve to a valid file.
If you have any other questions, just let me know.
Cheers.
That error means that you are trying to access something which has not been instantiated. You should put some breakpoints and run your app in debug mode when you are not sure what exactly is null.
It's very likely that stage is null in your case. Stage property of DisplayObject is set to the instance of app's stage when this display object is added to stage. However, all parents of this display object should be added to the stage too. Thus, make sure that the instance of Flash3DViewer has the stage before loading AWDViewer.

Writing an 'if' statement in ActionScript

Is there a way of writing an if statement that involves the following?
if (MovieClip1 reaches last frame)
{
addChild(MovieClip2)
removeChild(MovieClip1)
}
Basically, all I want to happen is when my MovieClip finishes, it will change to another MovieClip or image. I know it is probably very simple, but how can I do it?
All code runs on command. So your conditional will run immediately and never run again.
Instead, you use events. You attach a listener to an event and when that event fires (is "dispatched" to use correct vocabulary), your code is called again.
var movieClip:MovieClip = new MovieClip();
movieClip.addEventLister( Event.ENTER_FRAME, this.enterFrameHandler ); //will be called on every frame enter
function enterFrameHandler( e:Event ):void {
if ( movieClip.currentFrame == movieClip.totalFrames ) {
// do something
}
}
So you listen for each new frame and in that handler, you check if it is the last frame or not.
As an extra tidbit, the standard naming convention for AS3 is to use lowercase, camelcase (thisIsAnExampleOfthat) for all objects. Package names should be in all lowercase and only Class names should be capitalized.
package
{
import flash.display.MovieClip;
import flash.events.KeyboardEvent;
import flash.events.Event;
public class Main extends MovieClip
{
var firstScene:FirstScene = new FirstScene;
var movement:Movement = new Movement;
var green:Green = new Green;
public function Main()
{
addChild(firstScene);
firstScene.addEventListener(KeyboardEvent.KEY_DOWN, mClick);
movement.addEventListener(Event.ENTER_FRAME, endChange);
}
function mClick(event:KeyboardEvent):void
{
if (event.keyCode == 77);
{
addChild(movement);
removeChild(firstScene);
}
}
function endChange(event:Event):void
{
if (movement.currentFrame == movement.totalFrames)
{
addChild(green);
removeChild(movement);
}
}
}
}