AS3 : EventListener won't be removed in an [IF] - actionscript-3

I have searched how to pass arguments through EventListeners, and I used the method without calling an anonymous function to remove the EventListener later.
The issue is that the EventListener will be removed if out the IF function, but not if it is in the IF function.
How could I do that ?
The code :
function dragShip(m:MouseEvent):void
{
var func:Function = dispositionShip(m.target);
if (isDragging == false)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, func);
m.target.startDrag(true);
isDragging = true;
}
else
{
stage.removeEventListener(KeyboardEvent.KEY_DOWN, func);
isDragging = false;
placeShip(m.target , mouseX , mouseY , m.target.rotation);
}
// if the EventListener is put here, it gets removed, but not if put just in the else
}
NOTE : dispositionShip()returns a function.
Edit : Here is the following part of the code :
function dispositionShip(shipTarg):Function
{
return function(k:KeyboardEvent):void
{
rotateShip(k,shipTarg);
};
}
function rotateShip(k:KeyboardEvent,ship:Object):void
{
if (k.keyCode == 39)
{
ship.rotation += 90;
}
else if (k.keyCode == 37)
{
ship.rotation -= 90;
}
}
Moreover, if I replace rotateShip(k,shipTarg); by a simple trace, it also does not work.

Everytime you call
function dispositionShip(shipTarg):Function
{
return function(k:KeyboardEvent):void
{
rotateShip(k,shipTarg);
};
}
You're creating a new anonymous Object of type Function that calls rotateShip(), so when you call stage.removeEventListener(KeyboardEvent.KEY_DOWN, func); your func is a different Object to the func you passed into addEventListener(), so it doesn't match the orginal listener and doesn't get removed.
A better way to do this would be to store the current mouse target in a member var. IE:
var currentShip:Object;
function dragShip(m:MouseEvent):void
{
if (isDragging == false)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPress);
m.target.startDrag(true);
isDragging = true;
currentShip = m.target;
}
else
{
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyPress);
isDragging = false;
placeShip(m.target , mouseX , mouseY , m.target.rotation);
currentShip = null;
}
}
function keyPress(k:KeyboardEvent):void
{
rotateShip(k,currentShip);
}

Related

What is the error causing my character delay its response when press a key?

I have some problems with my character's walking command. It delays its movement for a bit before it actually moves. And then at times it completely ignores the command to stop walking when I released the key.
Code:
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
hero.gotoAndStop(1);
var rightPressed: Boolean = new Boolean(false);
var leftPressed: Boolean = new Boolean(false);
var upPressed: Boolean = new Boolean(false);
var downPressed: Boolean = new Boolean(false)
var heroSpeed: Number = 10;
var keys: Array = [];
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
stage.addEventListener(Event.ENTER_FRAME, gameLoop);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
function keyDownHandler(KeyEvent: KeyboardEvent): void {
if (keys[Keyboard.RIGHT]) {
rightPressed = true;
} else if (keys[Keyboard.LEFT]) {
leftPressed = true;
} else if (keys[Keyboard.DOWN]) {
downPressed = true;
} else if (keys[Keyboard.UP]) {
upPressed = true;
}
}
function keyUpHandler(KeyEvent: KeyboardEvent): void {
if (keys[Keyboard.RIGHT]) {
rightPressed = false;
hero.gotoAndStop(4)
} else if (keys[Keyboard.LEFT]) {
leftPressed = false;
hero.gotoAndStop(2)
} else if (keys[Keyboard.DOWN]) {
downPressed = false;
hero.gotoAndStop(1);
} else if (keys[Keyboard.UP]) {
upPressed = false;
hero.gotoAndStop(3);
}
}
function gameLoop(loopEvent: Event): void {
if (rightPressed) {
hero.x += heroSpeed;
hero.gotoAndStop(8)
}
if (leftPressed) {
hero.x -= heroSpeed;
hero.gotoAndStop(6)
}
if (downPressed) {
hero.y += heroSpeed;
hero.gotoAndStop(5);
}
if (upPressed) {
hero.y -= heroSpeed;
hero.gotoAndStop(7);
}
}
function onKeyDown(e: KeyboardEvent): void {
keys[e.keyCode] = true;
}
function onKeyUp(e: KeyboardEvent): void {
keys[e.keyCode] = false;
}
Warnings:
Scene 1, Layer 'Actions', Frame 1, Line 68, Column 10 Warning: 1090: Migration issue: The onKeyDown event handler is not triggered automatically by Flash Player at run time in ActionScript 3.0. You must first register this handler for the event using addEventListener ( 'keyDown', callback_handler).
Scene 1, Layer 'Actions', Frame 1, Line 72, Column 10 Warning: 1090: Migration issue: The onKeyUp event handler is not triggered automatically by Flash Player at run time in ActionScript 3.0. You must first register this handler for the event using addEventListener ( 'keyUp', callback_handler).
You should get rid of the two extra KeyboardEvent handlers (onKeyUp and onKeyDown), and move the code you have there into keyUpHandler and keyDownHandler. That will solve those migration warnings (because onKeyUp and onKeyDown were special methods in AS2), and it may be the solution to your other problem: I guess sometimes the onKeyDown handler gets executed after keyDownHandler, which means the boolean values in your array are not set yet and no movement will start.
Even better: also get rid of the array with booleans (and keys! you're abusing an Array for Dictionary use) and do it like this:
function keyDownHandler(KeyEvent: KeyboardEvent): void {
if (event.keyCode==Keyboard.RIGHT]) {
rightPressed = true;
}
//etc
}

My Character Won't Move :( Multiple .as files AS3

I have a few .as files. They are: MainClass.as, FrontEnd.as, Levels.as, and Hero.as. My problem (as far as I know) is in my Hero.as file. Let me descibe how I have it all set up thusfar because I have been a bit concerned that there are better ways of doing things in AS3.
MainClass.as makes a variable of FrontEnd (menus, namely the main menu) and calls it up (addChild).
FrontEnd.as are my menus. buttons and whatnot...
Levels.as right now just calls up level 1 when the start new game button is pressed on the main menu. Had one hell of a time figuring out how to use functions from a different .as file. Hero.as I will add my code for. I'm posting the whole thing because I don't know where my problem is.
public class Hero extends MovieClip
{
public var roger:player = new player();
private var animationState:String = "down";
public var facing:String = "down";
private var isLeft:Boolean = false;
private var isRight:Boolean = false;
private var isUp:Boolean = false;
private var isDown:Boolean = false;
public var currentPlayer:MovieClip = roger;
public function Hero()
{
addEventListener(Event.ENTER_FRAME, loop);
addEventListener(Event.ADDED_TO_STAGE, onStage);
trace(currentPlayer);
}
public function onStage( event:Event ):void
{
removeEventListener( Event.ADDED_TO_STAGE, onStage );
}
public function addCurrentPlayer():void
{
roger.x = stage.stageWidth * .5;
roger.y = stage.stageHeight * .5;
addChild(roger);
currentPlayer = roger;
setBoundaries();
}
public function keyDownHandler(event:KeyboardEvent)
{
if (event.keyCode == 39)//right press
{
isRight = true;
}
if (event.keyCode == 37)//left pressed
{
isLeft = true;
}
if (event.keyCode == 38)//up pressed
{
isUp = true;
}
if (event.keyCode == 40)//down pressed
{
isDown = true;
}
}
public function keyUpHandler(event:KeyboardEvent)
{
if (event.keyCode == 39)//right released
{
isRight = false;
}
if (event.keyCode == 37)//left released
{
isLeft = false;
}
if (event.keyCode == 38)//up released
{
isUp = false;
}
if (event.keyCode == 40)//down released
{
isDown = false;
}
}
public function loop(Event):void
{
if (currentPlayer == null)
{
addCurrentPlayer();//make sure at least roger is on the screen
}
currentPlayer.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
currentPlayer.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
//----------------------------------0
//Animation States
//----------------------------------0
if (isDown == true)
{
currentPlayer.y += 5;
animationState = "walk_down";
facing = "down";
currentPlayer.gotoAndStop(animationState);
}
else if (isUp == true)
{
currentPlayer.y -= 5;
animationState = "walk_up";
facing = "up";
currentPlayer.gotoAndStop(animationState);
}
else if (isRight == true)
{
currentPlayer.x += 5;
animationState = "walk_right";
facing = "right";
currentPlayer.gotoAndStop(animationState);
}
else if (isLeft == true)
{
currentPlayer.x -= 5;
animationState = "walk_left";
facing = "left";
currentPlayer.gotoAndStop(animationState);
}
//----------------------------------0;
//IDLE STATES
//----------------------------------0
else if (isDown == false)
{
currentPlayer.gotoAndStop(facing);
}
else if (isUp == false)
{
currentPlayer.gotoAndStop(facing);
}
else if (isRight == false)
{
currentPlayer.gotoAndStop(facing);
}
else if (isLeft == false)
{
currentPlayer.gotoAndStop(facing);
}
}
public function setBoundaries():void
{
var halfHeight:int = currentPlayer.height * .5;
var halfWidth:int = currentPlayer.width * .5;
if(currentPlayer.y <= 1)
{
currentPlayer.y += halfHeight;
}
else if(currentPlayer.y > stage.stageHeight)
{
currentPlayer.y -= halfHeight;
}
else if(currentPlayer.x <= 1)
{
currentPlayer.x += halfWidth;
}
else if(currentPlayer.x > stage.stageWidth)
{
currentPlayer.x -= halfWidth;
}
}
}
}
trace(currentPlayer); is giving me [object player] instead of the instance name "roger". (Later on I want more playable characters.) I'm not sure if the problem is there or in my levels file, which I'll post here. (not as long as Hero.as)
public class Levels extends MovieClip
{
var currentLevel:MovieClip;
public function Levels()
{
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, gotoLevelOne);
}
public function gotoLevelOne():void
{
var levelOne:LevelOne = new LevelOne();
var hero:Hero = new Hero();
addChild(hero);
levelOne.x = stage.stageWidth * .5;
levelOne.y = stage.stageHeight * .5;
addChild(levelOne);
currentLevel = levelOne;
hero.currentPlayer.x = 100;
hero.currentPlayer.y = 100;
addChild(hero.currentPlayer);
}
}
}
If I remove = roger; from var currentPlayer:MovieClip = roger; it gives me #1009 null object even though I told it in addCurrentPlayer() to change currentPlayer to roger. On level 1, everything shows up but I can't move my character. I know that it worked when I was working on his animations and I would call him to the main menu. Everything worked on him. What's the problem now?
Firstly, there's a lot of things wrong with your code:
In your Hero Class, the 'onStage' Event handler doesn't actually do anything other than remove the event listener that triggers it. While it's good practice to remove the event listener, there should be some other purpose to the Event handler. If there isn't you can remove it and not bother listening for the ADDED_TO_STAGE Event.
Similarly, in your Levels Class 'onStage' Event handler you attempt to remove the event, but name the wrong handler. I assume you want to remove the event handler and then run the 'gotoLevelOne' method. If so, just have the Event.ADDED_TO_STAGE listener call 'gotoLevelOne' and then remove the Event listener there:
public function Levels()
{
addEventListener(Event.ADDED_TO_STAGE, gotoLevelOne);
}
public function gotoLevelOne():void
{
removeEventListener(Event.ADDED_TO_STAGE, gotoLevelOne);
// class continues....
OK, so to your question:
You will be getting the null error because you are referring to currentPlayer from outside the Hero Class, before calling addCurrentPlayer (where it is set).
If you temporarily define currentPlayer as a private variable, the compiler should give you a line number where you first refer to currentPlayer from OUTSIDE the Hero Class (the error will be something like 'Class X is trying to access a private (or non-existent) property of Y Class').
You can then sort out WHY you are accessing currentPlayer before calling addCurrentPlayer. You may also want to think about if currentPlayer NEEDS to be public (if so, then what is 'addCurrentPlayer' for? That function effectively works as a setter for currentPlayer).
EDIT:
At the moment you are adding new KEY_DOWN and KEY_UP event listeners EVERY frame of your game loop. This is unnecessary. Add them both ONCE in the initialisation of your game (perhaps in your Hero's onStage handler), and count on them to trigger the appropriate handlers.
You will want to add the KEY_DOWN and KEY_UP listeners to 'stage', not currentPlayer, so:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
You will need to add the listeners AFTER your Hero instance has been added to the Stage though, so it has access to 'stage'. That's why it makes sense to add the listeners in the Hero's onstage handler.

Sprite movement basically right but

This is basically just drag and double click to set (so drag is temporarily disabled) but the sprite doesn't keep with the mouse- can someone point me to better code- otherwise I'll with go with this- so much more to do.
//The initial event performed when the button is first clicked;
internal var m_nDoubleClickSpeed:Number = 300;
internal var m_toMouse:Number;
internal var moveready:Boolean = false;
internal var initalx:uint;
internal var initialy:uint;
internal var move:Boolean;
internal function clickDoubleClick(e:MouseEvent):void {
if (isSet == false) {
this.startDrag();
}
if (isNaN(m_toMouse)==false) {
clearTimeout(m_toMouse);
HandleDoubleClick();
} else {
m_toMouse = setTimeout(HandleSingleClick, m_nDoubleClickSpeed);
}
}
internal function HandleSingleClick():void {
trace("HandleSingleClick");
trace("isSet");
trace(isSet);
this.stopDrag();
m_toMouse = NaN;
}
internal function HandleDoubleClick():void {
if (isSet == false) {
isSet = true;
this.stopDrag()
} else {
isSet = false;
}
trace("HandleDoubleClick");
m_toMouse = NaN;
}
internal function goodX(inX:Number):Number {
if (inX < 0) {
return 0;
}
if (inX > (stage.stageWidth) ) {
return (stage.stageWidth);
}
return inX;
}
internal function goodY(inY:Number):Number {
if (inY < 0) {
return 0;
}
if (inY > stage.stageHeight) {
return stage.stageHeight;
}
return inY;
}
I'm not sure if I understood you correctly. So you want to start drag on single click and drag until doubleclicked right? If so you can try something like that:
public class ClickAndDrag extends Sprite
{
private var clickTimeout:uint;
private var doubleClickSpeed:int = 500;
private var clickedOnce:Boolean;
private var mouseOnClick:Point;
private var isDragging:Boolean;
public function ClickAndDrag()
{
graphics.beginFill(Math.random()*0xffffff, 1);
graphics.drawCircle(0, 0, 20);
graphics.endFill();
this.buttonMode = true;
addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
}
private function handleMouseDown(e:MouseEvent):void
{
if (isDragging)
{
if (clickedOnce)
handleDoubleClicked();
else
{
//if it's not clicket within next doubleClickSpeed ms then doubleClickSpeed will be set to false;
clickedOnce = true;
clickTimeout = setTimeout( handleClickTimeout, doubleClickSpeed );
}
}
else
{
handleClickAndDrag();
}
}
//clicked once when dragging
private function handleClickOnce():void
{
graphics.clear();
graphics.beginFill(Math.random()*0xffffff, 1);
graphics.drawCircle(0, 0, 20);
graphics.endFill();
}
//clicked once when not dragging
private function handleClickAndDrag():void
{
isDragging = true;
this.addEventListener(Event.ENTER_FRAME, handleFrame);
mouseOnClick = new Point(this.mouseX, this.mouseY);
}
//doubleclicked when dragging
private function handleDoubleClicked():void
{
clearTimeout(clickTimeout);
clickedOnce = false;
this.removeEventListener(Event.ENTER_FRAME, handleFrame);
isDragging = false;
}
private function handleClickTimeout():void
{
clickedOnce = false;
handleClickOnce();
}
private function handleFrame(e:Event):void
{
this.x = stage.mouseX - mouseOnClick.x;
this.y = stage.mouseY - mouseOnClick.y;
}
}
It basically waits for mousedown and if it's already dragging it checks if you clicked once (changes color) ot twice (stops dragging). Or if it's not dragging yet then it starts dragging. You may also want to handle leaving the stage (Event.MOUSE_LEAVE).

removeEventListener not working

function Drag(event:MouseEvent):void {
if ((event.target.parent == InventoryMenu) && (event.target is item)) {
var picked:item = item(event.target);
stage.addEventListener(MouseEvent.MOUSE_UP, Drop);
InventoryArrowDown.addEventListener(MouseEvent.MOUSE_OVER, InventoryNav("down"));
InventoryArrowUp.addEventListener(MouseEvent.MOUSE_OVER, InventoryNav("up"));
function Drop(event:MouseEvent):void {
if ((event.target.parent == InventoryMenu) && (event.target is item)) {
var dropped:item = item(event.target);
if ((event.target is item) && (event.target.parent == InventoryMenu)) {
if (picked.itemdata("workswith") == dropped.name) {
var itemname:item = item(FetchResult(picked, dropped));
itemname.addChild(itemname.itemdata("filename"));
InventoryMenu.removeChild(picked);
InventoryMenu.removeChild(dropped);
InventoryMenu.addChild(itemname);
InventoryUpdate();
} else if (picked.name != dropped.name) {
trace("No son compatibles");
}
stage.removeEventListener(MouseEvent.MOUSE_UP, Drop);
InventoryArrowDown.removeEventListener(MouseEvent.MOUSE_OVER, InventoryNav("down"));
InventoryArrowUp.removeEventListener(MouseEvent.MOUSE_OVER, InventoryNav("up"));
}
}
}
}
}
For some reason the removeEventListener on InventoryArrowDown and InventoryArrowUp isn't working. I'm fairly sure the route is correct as it's a direct copy paste from the addEventListener and it uses no variables.
Any clue what's wrong?
Hard to help you without seeing the code of InventoryNav but maybe the issue is that you should remove the event listeners before your tests.
Also, you should write two different handlers instead of using one and passing an argument like you do.
Here is a modified version of your code that might help:
private function drag(event:MouseEvent):void {
if ((event.target.parent == inventoryMenu) && (event.target is Item)) {
var picked:Item = Item(event.target);
stage.addEventListener(MouseEvent.MOUSE_UP, drop);
inventoryArrowDown.addEventListener(MouseEvent.MOUSE_OVER, inventoryNavDown);
inventoryArrowUp.addEventListener(MouseEvent.MOUSE_OVER, inventoryNavUp);
}
}
private function drop(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, drop);
inventoryArrowDown.removeEventListener(MouseEvent.MOUSE_OVER, inventoryNavDown);
inventoryArrowUp.removeEventListener(MouseEvent.MOUSE_OVER, inventoryNavUp);
if ((event.target.parent == inventoryMenu) && (event.target is Item)) {
var dropped:Item = Item(event.target);
if ((event.target is Item) && (event.target.parent == inventoryMenu)) {
if (picked.itemdata("workswith") == dropped.name) {
var itemname:Item = Item(fetchResult(picked, dropped));
itemname.addChild(itemname.itemdata("filename"));
inventoryMenu.removeChild(picked);
inventoryMenu.removeChild(dropped);
inventoryMenu.addChild(itemname);
inventoryUpdate();
} else if (picked.name != dropped.name) {
trace("No compatible sons");
}
}
}
}

to create quiz using StartDrag and stopDrag

Actually i have a quiz.fla. In the file ,two of them fill inthe blank questions and others are
multiple questions.
square1_mc must run only once not twice. İf user correct selected, doesnt run it again.
However,if mybadscoretext is 1 not increase 2,3,4. :S
how i can do all?
stop();
var myScore:Number = 0;
var myBadScore:Number=0;
square1_mc.addEventListener(MouseEvent.MOUSE_DOWN, drag);
stage.addEventListener(MouseEvent.MOUSE_UP, drop);
function drag(e:MouseEvent):void
{
e.target.startDrag();
}
function drop(e:MouseEvent):void
{
square1_mc.stopDrag();
if (square1_mc.hitTestObject(square2_mc)== true)
{
square1_mc.x=129;
square1_mc.y=133;
this.graphics.clear();
this.graphics.lineStyle(2, 000000);
this.graphics.moveTo(square1_mc.x, square1_mc.y);
this.graphics.lineTo(square2_mc.x, square2_mc.y);
this.graphics.endFill();
myScore += 1;
score_txt.text=String(myScore);
square1_mc.removeEventListener(MouseEvent.MOUSE_DOWN, drag);
}
else
{
square1_mc.x=129;
square1_mc.y=133;
myBadScore += 1;
mybadscore_txt.text=String(myBadScore);
}
}
Add a variable to keep track of whether the bad score has been added:
var badMarked:Boolean = false;
function drag(e:MouseEvent):void
{
e.target.startDrag();
badMarked = false;
}
[...]
function drop(e:MouseEvent):void
{
if (square1_mc.hitTestObject(square2_mc)== true)
{
[...]
}
else if ( !badMarked )
{
square1_mc.x=129;
square1_mc.y=133;
myBadScore += 1;
mybadscore_txt.text=String(myBadScore);
badMarked = true;
}
}