AS3 ENTER_FRAME event still firing when frame changed - actionscript-3

Why won't this ENTER_FRAME event stop firing when I call view_stats_exit before going to view_start?
public function view_start (e:MouseEvent):void
{
gotoAndStop("start");
}
public function view_stats(e:MouseEvent):void
{
// Event
StatsUI.addEventListener(Event.ENTER_FRAME,stats_scroll);
}
public function view_stats_exit (e:MouseEvent):void
{
StatsUI.removeEventListener(Event.ENTER_FRAME,stats_scroll);
view_start(null);
}
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Snapshot/stats_scroll()

You can add an event listener to a MovieClip , but you shouldn't do it as a static function , like in your example. The following should work...
private var ui:StatsUI = new StatsUI();
public function view_stats(e:MouseEvent):void
{
// Event
ui.addEventListener(Event.ENTER_FRAME,stats_scroll);
}
public function view_stats_exit (e:MouseEvent):void
{
ui.removeEventListener(Event.ENTER_FRAME,stats_scroll);
view_start(null);
}

Related

object's stage reference lost when re-instantiated after being removed from memory & displaylist

I'm building a game. When you die or win a level you're prompted to continue or return to the main menu. If you chose to go to the main menu you can start a new game. When you start a new game, the game is object is created again & it's children have lost their reference to the stage. I'm not sure why this is happening and I've spent over a week trying to figure out why. Here's some code (and descriptions of the code) from the game that should hopefully provide enough insight as to why the problem may be occurring:
if the "new game" button is clicked on the startMenu the NavigationEvent.START event is dispatched. a LevelEvent.COMPLETE event is dispatched by WeeBeeGame when the level is completed.
public class DocumentClass extends MovieClip {
public var startMenu:StartMenuGenerator = new StartMenuGenerator();
public var weeBeeGame:WeeBeeGame;
public var youWonBox:YouWonBox = new YouWonBox();
public function DocumentClass() {
// constructor code
addChild(startMenu);
startMenu.addEventListener(NavigationEvent.START, startGameHandler);
}
public function startGameHandler(e:NavigationEvent) : void {
this.removeChild(startMenuBG);
removeChild(startMenu);
weeBeeGame = new WeeBeeGame();
this.addChild(weeBeeGame);
weeBeeGame.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler);
}
public function levelCompleteHandler(e:LevelEvent) : void {
youWonBox.x = this.stage.stageWidth/2;
youWonBox.y = this.stage.stageHeight/2;
addChild(youWonBox);
youWonBox.addEventListener(MouseEvent.CLICK, mouseClickHandler);
}
private function mouseClickHandler(e:MouseEvent) : void {
if(e.target.name === "mainmenubtn"){
mainmenuHandler();
}
}
private function continueHandler() : void {
youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
}
private function mainmenuHandler() : void {
youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
WeeBeeGame.collisionDOC.removeChildren();
removeChild(weeBeeGame);
weeBeeGame = null;
this.addChild(startMenuBG);
addChild(startMenu);
removeChild(youWonBox);
}
}
the code that dispatches a LevelEvent.COMPLETE event is not shown but it dispatches when the level is complete. collisionDOC needs to be static because it's needed in a lot of other classes and holds the display objects needed for a 3rd party pixel-level collision detection.
public class WeeBeeGame extends MovieClip {
public var bee: Bee;
public var beeHurt:BeeHurt;
public var spawningDaemon:SpawningDaemon;
public static var collisionDOC:DisplayObjectContainer;
public function WeeBeeGame() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);
}
private function addedToStageHandler(e:Event) : void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
collisionDOC = new MovieClip();
addChild(collisionDOC);
bee = new Bee();
collisionDOC.addChild(bee);
beeHurt = new BeeHurt(bee.x, bee.y);
addChild(beeHurt);
beeHurt.visible = false;
spawningDaemon = new SpawningDaemon(currentLevel);
this.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler, false, 0, true);
}
private function levelCompleteHandler(e:LevelEvent) : void {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
}
the first line to throw a 1009 error (Cannot access a property or method of a null object reference) is the line containing stage.mouseX because the stage reference is null.
public class Bee extends MovieClip {
public function Bee() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(e:Event) : void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
this.x = this.stage.stageWidth / 2;
this.y = this.stage.stageHeight - this.stage.stageHeight / 9;
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);
}
private function enterFrameHandler(e:Event) : void {
if(stage == null){
trace('stage is null' + stage.mouseX);
}
}
}
When the swf is first opened and a new WeeBeeGame is created its children have references to the stage. But when WeeBeeGame and it's children are removed from the display list and memory they lose reference and even if they're re-instantiated their references are still lost. How do I fix this? I'm very confused. Thank you all!!
ENTER_FRAME handlers continue to execute even when the display object is removed form the stage. So when you removeChild(weeBeeGame) those ENTER_FRAME handlers are still trying to access stage.mouseX each frame. You need to stop the ENTER_FRAME handlers.
Probably the easiest fix is to add an Event.REMOVED_FROM_STAGE handler to remove the Event.ENTER_FRAME handlers.
A better fix IMO is to not add any ENTER_FRAME handlers from your game objects, but rather expose a public function like update() which gets called from a single ENTER_FRAME handler in your WeeBeeGame when the game is running. Then to stop the game completely you can stop all updates by simply removing that single ENTER_FRAME handler. This is a common practice.

In ActionScript3, how to catch ErrorEvent that I've dispatched?

At some points in my application, I've a try-catch block such as:
This happens inside classes that are not in the display list (not Sprites, nor any kind of DisplayObject), but extend EventDispatcher.
Those classes reside in externally loaded SWF (in case that matters).
try {
... some logic that may throw Error
} catch (e:Error) {
var errorEvent:ErrorEvent = new ErrorEvent(ErrorEvent.ERROR, true);
errorEvent.text = e.getStackTrace();
dispatchEvent(errorEvent);
}
In the root class, this is what I have:
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtErrorHandler);
loaderInfo.uncaughtErrorEvents.addEventListener(ErrorEvent.ERROR, onErrorEventHandler);
stage.addEventListener(ErrorEvent.ERROR, onErrorEventHandler);
protected function onUncaughtErrorHandler(event:UncaughtErrorEvent):void
{
var message:String;
if (event.error is Error) {
message = event.error.getStackTrace();
} else if (event.error is ErrorEvent) {
message = ErrorEvent(event.error).text;
} else {
message = event.error.toString();
}
trace(message);
}
protected function onErrorEventHandler(event:ErrorEvent):void
{
trace(event.text);
}
Neither handlers are called, but those error events bubble up and I see them in console, and as popups in debug mode, but how do I listen to them in a root class?
I do this because I don't want the error to interrupt execution of the main thread or the particular business logic.
I think what you are looking for is a listener to uncaught error events. Here is an example of adding it in your root class:
this.loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onGlobalErrors);
EDIT BY LDMS
The following works in FlashPro:
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,function(e:Event){
trace("I Caught an Error");
});
var err:ErrorEvent = new ErrorEvent(ErrorEvent.ERROR,true);
var obj:EventDispatcher = new EventDispatcher();
obj.dispatchEvent(err);
If your class is on stage you can add event listener for ErrorEvent.ERROR to stage. Any dispatched event will go up to the stage through all its parents.
Example of code:
// some initialize
stage.addEventListener("lol", lolHandler);
// dispatching
private function button1_clickHandler(event:MouseEvent):void
{
// second parameter responsible for bubbling and MUST be true
dispatchEvent(new Event("lol", true)); // on mouseClick we dispatch custom event
}
private function lolHandler(event:Event):void
{
trace("We got it! Lol!);
}
P.S. Article in the comment is really useful. Recommend it to read.
// UPDATE
Alternative variant can be in dispatching event from some singleton. For example:
public class ErrorHandler extends EventDispatcher {
private static var _instance:ErrorHandler;
public static function get instance():ErrorHandler {
if (!_instance)
_instance = new ErrorHandler(new PrivateConstructor());
return _instance;
}
public function ErrorHandler(value:PrivateConstructor) {
addEventListener(ErrorEvent.ERROR, errorHandler);
}
private function errorHandler(event:ErrorEvent):void {
// some code
}
}
}
class PrivateConstructor {}
.... and dispatching
ErrorHandler.instance.dispatchEvent(new ErrorEvent());

AS3: Cannot access a property of a null object reference

I'm trying to trace the mouse X position with a movieclip.
What I have done so far:
public class LuckyHitBeta extends MovieClip {
var ballReady:ballReady_mc;
private function liveIcon():void {
ballReady=new ballReady_mc();
addChild(ballReady);
ballReady.y=1;
}
private function onEnterFrm(e:Event):void
{
ballReady.x=mouseX;
}
}
Runtime error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at LuckyHitBeta/onEnterFrm()
I don't see you calling the function liveIcon(). It seems like the enterFrame event happens before ballready is initialized.
I think it means ballReady is NULL
I would do something like
private function onEnterFrm(e:Event):void
{
if (ballReady) {
ballReady.x=mouseX;
}
}

Custom Event not working

I have created a Custom Event, that is fired from a custom component. It should be catched in the main application to change the selectedindex of the viewstack.
But this doesn't work, and I can't figure out why.
This is my Custom Event:
package events
{
import flash.events.Event;
public class ChangeSelectedIndex extends Event
{
public static var index_passed:String = "Index passed";
private var index:int;
public function ChangeSelectedIndex(i:int, type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type,bubbles, cancelable);
index = i;
}
public function get getIndex():int
{
return index;
}
}
}
This is how I fire the event:
protected function checkUsernameExistsDbSucces(event:ResultEvent):void
{
dispatchEvent( new ChangeSelectedIndex(1,ChangeSelectedIndex.index_passed,false,false));
}
And this is my function to catch the event:
private function changeSelectedIndexHandler(event:ChangeSelectedIndex):void
{
mainViewStack.selectedIndex = event.getIndex;
}
In order for your handler to be called when the event is dispatched, you need to add an event listener to your custom component.
myCustomComponent.addEventListener ( ChangeSelectedIndex.index_passed, changeSelectedIndexHandler);
Make sure this line is within the same scope as both your handler function and myCustomComponent, otherwise there will be an error.

How do I handle a custom event in ActionScript 3?

I've created an Event Handler/Listener like so:
import flash.events.Event;
public class DanielEvent extends Event {
public var data:*;
public static const APP_STARTED:String = "APP_STARTED";
public function DanielEvent(n:String, data:*){
this.data = data;
super(n)
}
}
Listening to an event using:
addEventListener(DanielEvent.APP_STARTED, appStarted);
Dispatching an event by:
dispatchEvent(new DanielEvent("APP_STARTED", "test"))
And receiving the data by:
private function appStarted(e:Event){
trace(e.data)
}
But I get the error:
Access of possibly undefined property
data through a reference with static
type flash.events:Event.
You have to use your custom event type in the event handler, if you want to access the data property:
private function appStarted(e:DanielEvent): void {
trace(e.data);
}
your event handler is passed a DanielEvent, not an Event:
private function appStarted(e:DanielEvent):void
{
trace(e.data);
}
also. you should also use your constant for your dispatch instead of passing a string, like you've done for your listener:
dispatchEvent(new DanielEvent(DanielEvent.APP_STARTED, "test"));
and don't forget to override clone() if you are planning on dispatching that event more than once.
public override function clone():Event
{
return new DanielEvent(n, data);
}