ActionScript 3 Event doesn't work - actionscript-3

I'm new in AS, and trying to make my first application. I have a class, that showld manage some events, like keyboard key pressing:
public class GameObjectController extends Sprite
{
var textField:TextField;
public function GameObjectController()
{
addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
private function onKeyDown(event: KeyboardEvent):void
{
trace("123");
}
}
but when I'm running it, and pressing any button, nothing happands. What am I doing wrong?

Try stage.addEventListener() for KeyboardEvents.
The reason for this is that whatever you add the event to needs focus, and the stage always has focus.
If GameObjectController isn't the document class, it will need to have stage parsed to its constructor for this to work, or it will need to be added to the stage first. The former will be less messy to implement.
public function GameObjectController(stage:Stage)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}

Add the keyboard event to the stage and import the KeyboardEvent class.
package
{
import flash.display.Sprite;
import flash.events.KeyboardEvent;
public class GameObjectController extends Sprite
{
public function GameObjectController()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownEventHandler);
}
private function keyDownEventHandler(event:KeyboardEvent):void
{
trace(event);
}
}
}

Related

Why removeEventListener on the new instance of the object is not working?

I am trying to create a new instance of a class within the same class and after creating the instance I try to remove the MouseDown listener.
package com.objects{
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class StickDragDrop extends NumButton {
public var duplicateObject:MovieClip;
public function StickDragDrop() {
init();
}
public function init() {
addEventListener(MouseEvent.MOUSE_DOWN,stick);
}
public function stick(e:MouseEvent) {
duplicateObject=new e.currentTarget.constructor
addChild(duplicateObject);
duplicateObject.startDrag();
duplicateObject.removeEventListener(MouseEvent.MOUSE_DOWN,stick);
duplicateObject.addEventListener(MouseEvent.MOUSE_DOWN,unStick);
}
public function unStick(e:MouseEvent) {
stopDrag();
}
}
}
You're trying to remove an Event Listener for duplicateObject that would call this.stick, not duplicateObject.stick and that event listener doesn't exist.
Try adding:
public function removeStick() {
removeEventListener(MouseEvent.MOUSE_DOWN,stick)
}
to your class, and instead of calling
duplicateObject.removeEventListener(MouseEvent.MOUSE_DOWN,stick);
call
duplicateObject.removeStick();
Alternatively, you probably could just change the call to
duplicateObject.removeEventListener(MouseEvent.MOUSE_DOWN,duplicateObject.stick);
But I prefer the first option.

Disabling Nested MovieClips After Removing Parent Movieclip

In some of the level MovieClips I have for my Flash game, there is a certain MovieClip that controls a custom-built camera that I've created. Both the camera and the MovieClip function correctly and smoothly. However, whenever a level is completed and removed from the game, I get an Error #1009 not recognizing the checkCameraZoom function. Also, this MovieClip is not added dynamically with code, but rather placed in the specified level MovieClips from the Library before run-time. Is there any possible way to fix this error?
ZoomOutArea Class:
package com.engine.assetHolders
{
import com.engine.documentClass.*;
import flash.display.*;
import flash.events.*;
public class ZoomOutArea extends MovieClip
{
public function ZoomOutArea():void
{
this.visible = false;
this.addEventListener(Event.ADDED_TO_STAGE, initZoomOutArea);
// constructor code
}
public function initZoomOutArea(event:Event):void
{
this.addEventListener(Event.ENTER_FRAME, checkCameraZoom);
}
public function checkCameraZoom(event:Event):void
{
if (Document.getInstance != null)
{
if (this.hitTestObject(MovieClip(parent.parent).player.playerHitArea))
{
this.hitTestZoom(0.6);
}
if (! this.hitTestObject(MovieClip(parent.parent).player.playerHitArea))
{
this.hitTestZoom(1);
}
}
}
public function hitTestZoom(zoomLevel):Number
{
MovieClip(parent.parent).cameraScale = zoomLevel;
return zoomLevel;
}
}
}
You register the class for ENTER_FRAME events when it's added to the stage, but you never unregister it. So that's why it keeps going even after it has been removed from the stage, and has no parent anymore.
You could add another listener for Event.REMOVED_FROM_STAGE and then remove the checkCameraZoom listener:
public function initZoomOutArea(event:Event):void
{
this.addEventListener(Event.ENTER_FRAME, checkCameraZoom);
this.addEventListener(Event.REMOVED_FROM_STAGE, onRemoved);
}
private function onRemoved(event:Event):void
{
this.removeEventListener(Event.ENTER_FRAME, checkCameraZoom);
}

AS3 Cannot access stage from custom class

How can I access the stage and especially the width and mouse position of the flash Movie from a custom class?
package classes
{
import flash.events.*;
import flash.display.*;
public class TableManager extends Sprite
{
public function TableManager() {
sayStage();
}
public function sayStage():void
{
trace(stage);
}
}
}
This will only return nill. I know that DisplayObjects don't have any stage until they have been initiated so you can't access the stage in your constructor but even if I call sayStage() later as an instance method it won't work.
What am I doing wrong?
If TableManager is on the stage you can access the stage with this.stage.
The trick is you have to wait for the instance to be added to the stage. You can listen for the ADDED_TO_STAGE event so you know when that's happened.
package classes {
import flash.events.*;
import flash.display.*;
public class TableManager extends Sprite {
public function TableManager() {
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
sayStage();
}
public function sayStage():void {
trace(this.stage);
}
}
}
The most defensive way to write this is:
public function TableManager() {
if(this.stage) init();
else this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
if(e != null) this.removeEventListener(Event.ADDED_TO_STAGE, init);
sayStage();
}
If the object is already on the stage at the time of initialization, then immediately call the init function with no arguments. If not wait until its been added to the stage. Then when the init function gets called, if it was called as the result of an event, then detach the event handler, and move along.
You can pass a reference of the root movieclip (i.e. the stage) to your custom class.
e.g.
package classes
{
import flash.events.*;
import flash.display.*;
public class TableManager extends Sprite
{
private var _rootMC:MovieClip;
public function TableManager(rootMC:MovieClip) {
_rootMC = rootMC;
sayStage();
}
public function sayStage():void
{
trace(_rootMC.stage);
trace(_rootMC.stage.stageWidth);
}
}
}
Then when instantiating your instance of TableManager from the root timeline:
//the keyword 'this' is the root movieclip.
var newTM:TableManager = new TableManager(this);
stage will be null as long as the Sprite hasn't been added to the display list - it's nothing to do with initiation. E.g.
var t:TableManager = new TableManager;
stage.addChild( t ); // or your root class, or any class that's already on the displaylist
trace( t.stage ); // [Stage stage]
t.parent.removeChild( t );
trace( t.stage ); // null
As #crooksy88 suggests, either pass in the stage to the constructor, or keep it as a static somewhere, say your main document class, so that you can access it everywhere.
i think usefull for You should be create static reference to stage :
in Your main class add line and set stage :
public static var stage:Stage;
...
public function Main():void { // constructor
Main.stage = stage;
...
and than in custom class :
public function sayStage():void
{
trace(Main.stage);
trace(Main.stage.stageWidth);
}
you may access this.stage when the current object(also a sprite) is already attached to the stage.
public class TableManager extends Sprite{
public function TableManager()
{
}
public function sayStage():void
{
trace(stage);
}
}
TableManager tm=new TableManager();
//tm.sayStage(); // no
addChild(tm);
tm.sayStage(); // fine
hope this could help
here is a pretty good solution you only need to reference the stage inside your class you just pass it as a simple object, here how to do that
package {
public class Eventhndl{
private var obj:Object;
public function Eventhndl(objStage:Object):void{
obj = objStage;
trace(obj); // now the obj variable is a reference to the stage and you can work as normal you do with stage (addChild, Events Etc..)
}
}
this is how you make instance to run it, i have used the constructor method but you can change it to any function as you wish and call it whenever you need it.
import Eventhndl;
var EH:Eventhndl = new Eventhndl(stage);
here is some few Examples how to access stage from class
https://stackoverflow.com/a/40691908/1640362
https://stackoverflow.com/a/40691325/1640362

make a preloader class instead of having it in the document class

I have built a basic preloader that runs in my document class. I'm having trouble with it. I'm guessing its due to what a class can and can not access from the stage?
theres 2 problems. the first is that I cant change the keyframe the stage is on from the class. the second is im getting an error 1009 if I comment that out.
package
{
import flash.display.MovieClip
import flash.events.Event;
import flash.events.ProgressEvent;
public class Pre extends MovieClip
{
public function Pre()
{
loaderInfo.addEventListener(Event.COMPLETE,downloadFin);
loaderInfo.addEventListener(ProgressEvent.PROGRESS,preloadProgress);
function preloadProgress(progressEvent:ProgressEvent):void
{
var floatLoaded:Number=loaderInfo.bytesLoaded/loaderInfo.bytesTotal;
var newW:Number=this.width*floatLoaded;
this.Fill.width=newW;
}
function downloadFin(event:Event):void
{
trace('fin')
//stage.gotoAndStop(3);//frame with game
}
}
}
}
I recommend you to dispatch an event when the preloader is ready, making yor preloader more generic. Then add a listener in the document class like this:
private function setupPreloader() : void
{
preloader.addEventListener(Event.COMPLETE , onPreloaderComplete);
preloader.start();
}
private function onPreloaderComplete(event : Event) : void
{
preloader.removeEventListener(Event.COMPLETE, onPreloaderComplete);
preloader.dispose();
gotoAndStop(3);
}

ActionScript - Keyboard Events Without Stage?

is it true that keyboard events can not be accessed outside of the stage on non display objects?
example:
package
{
//Imports
import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
//Class
public class TestClass extends EventDispatcher
{
//Constructor
public function TestClass()
{
init();
}
//Initialization
public function init():void
{
addEventListener(KeyboardEvent.KEY_UP, keyUpEventHandler);
}
//Key Up Event Handler
private function keyUpEventHandler(evt:KeyboardEvent):void
{
trace("Test Class: " + evt.keyCode);
}
}
}
here i would like to initialize a new TestClass() then press a on the keyboard to receive the output Test Class: a.
To my knowledge (and according to the livedocs example) you need to add a KeyboardEvent listener to a displayObject. I've done this in abstract and static classes by passing a reference to the stage (or any displayObject) to your class's init method or constructor.
So, for example, in your document class, you could do:
var testClass:TestClass = new TestClass();
testClass.init(stage);
and in TestClass.as do:
public function init(stageReference:DisplayObject):void
{
stageReference.addEventListener(KeyboardEvent.KEY_UP, keyUpEventHandler);
}
While I agree it's a little wonky, I don't think there's a way to do it without using a DisplayObject.