Keyboard AS3 detection - actionscript-3

I know there's a lot of questions on this but I'm really having troubles getting this to work.
I only have in the first frame this code:
var game = new Game(this);
In the game class I have a lot of stuff
package {
import flash.display.*;
import flash.ui.*;
import flash.events.*;
public class Game extends MovieClip {
public function Game(esc) {
var camp = new Camp(); //camp és l'escenari, el conjunt de celles
var player = new Player();
esc.addEventListener(KeyboardEvent.KEY_UP, controlTeclat);
camp.mostraInterficie(esc);
player.situaPlayer(esc);
}
public function controlTeclat(ev){
switch(ev.keyCode){
/*case 37: player.moveLeft();break;
case 38: player.moveUp();break;
case 39: player.moveRight();break;
case 40: player.moveDown();break;
case 32: player.dropBomb();break;*/
}
trace ("hi");
}
}
}
The problem is that the controlaTeclat() function's never called, the trace is no printed. No error displayed, dough.

The mc will need to be on the displayList to receive keyboard events.
var game = new Game(this);
addChild( game );

Without more code it's hard to say exactly what's going wrong here, however if the esc object doesn't have focus (hasn't been clicked by the mouse) then keyboard events won't propagate through it and so the handler won't fire.

You could just add the keyboard listener to the stage itself. You can also set the focus with 'stage.focus' so it will receive events without having to click on the stage first.
stage.addEventListener( KeyboardEvent.KEY_UP, keyupHandler );
//if you want to, you can set focus like this:
stage.focus = stage; //or some other object
private function keyupHandler(e:KeyboardEvent):void
{
trace("keyupHandler()");
}

if (esc.stage) esc.stage.addEventListener(KeyboardEvent.KEY_UP, controlTeclat);
else trace("Stage is inaccessible!");
The best practice is allocating your keyboard listeners to stage, so that they will always react to keyboard events. "esc" is your Document class seemingly, but it's not the stage, so we use "stage" property of "esc" to get access there.

Related

How to STOP looping sound when going into next frame/Errors

I have a flash project broken up into multiple frames, with a button on each frame that goes to play the next frame. (And a movieclip on each frame that plays until you hit next frame button)
On each frame, I want audio to play, and loop.
But, I want the audio from one frame to stop when I click the button to go to the next.
On frame 4, I have this code:
import flash.media.SoundChannel;
var sound:Sound = new firt2();
var soundChannel:SoundChannel;
sound.addEventListener(Event.COMPLETE, onSoundLoadComplete);
sound.play();
function onSoundLoadComplete(e:Event):void{
sound.removeEventListener(Event.COMPLETE, onSoundLoadComplete);
soundChannel = sound.play();
soundChannel.addEventListener(Event.SOUND_COMPLETE, onSoundChannelSoundComplete);
}
function onSoundChannelSoundComplete(e:Event):void{
e.currentTarget.removeEventListener(Event.SOUND_COMPLETE, onSoundChannelSoundComplete);
}
And it works. However, I want to stop it once I click the button to go to the next frame. I have tried:
soundChannel.stop();
On the next frame.
However, whenever I do that, the output reads:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at hhh4_fla::MainTimeline/frame5()
at flash.display::MovieClip/gotoAndPlay()
at hhh4_fla::MainTimeline/fl_ClickToGoToAndPlayFromFrame()
All of my buttons and movieclip have instance names.
Rather than figuring why it doesn't work with all these frames and timelines, I think it's better to compose a centralized sound manager class that handles these things.
Implementation. Keep in mind that I didn't test that so please excuse me for occasional typo if any. The logic of it all should be correct.
package
{
import flash.system.ApplicationDomain;
import flash.media.SoundChannel;
import flash.media.Sound;
import flash.events.Event;
public class Audio
{
// Container to cache Sound objects.
static private const cache:Object = new Object;
// Variables to hold the current values.
static private var currentChannel:SoundChannel;
static private var currentSound:String;
// Stops the current sound playing. If you pass the sound name, it
// will stop the audio track only if it is the exact one playing.
// Otherwise it will stop any one currently playing.
static public function stop(value:String = null):void
{
// Do nothing if nothing is playing right now,
// or if the specific sound requested to stop does not match.
if (currentSound == null) return;
if (value) if (value != currentSound) return;
// Unsubscribe from event and stop the audio.
currentChannel.removeEventListener(Event.SOUND_COMPLETE, onComplete);
currentChannel.stop();
// Final clean-up.
currentChannel = null;
currentSound = null;
}
// Plays the embedded sound by its class name.
static public function play(value:String):void
{
// Do nothing if the requested sound is already playing.
if (value == currentSound) return;
// Stop the current audio track playing.
stop();
// Check if that one sound is valid and/or was previously requested.
if (!cache[value])
{
try
{
// Obtain class definition from the project.
var aClass:Class = ApplicationDomain.currentDomain.getDefinition(value) as Class;
// Try instantiating the Sound.
if (aClass) cache[value] = new aClass as Sound;
}
catch (fail:Error)
{
// Well, do nothing, yet.
}
}
if (cache[value])
{
// Store the id of audio track that is going to be playing.
currentSound = value;
// Play the track and subscribe to it for the SOUND_COMPLETE event.
currentChannel = (cache[value] as Sound).play();
currentChannel.addEventListener(Event.SOUND_COMPLETE, onComplete);
}
else
{
// If there's no such class, or it is not a Sound,
trace("ERROR: there's no sound <<" + value + ">> is embedded into the project.");
}
}
// Event handler to clean up once the current audio track is complete.
static private function onComplete(e:Event):void
{
// Sanity check.
if (e.target != currentChannel) return;
stop();
}
}
}
Usage.
import Audio;
// Any time you want different sound to play.
// Pass the class name as Sting as an argument.
Audio.play("firt2");
// Any time you just want to stop the sound;
Audio.stop();

Custom Mouse Cursor dropping duplicate symbols after its been removed

first of all, I'm a total noob to as3 and coding in general, I barely operate outside of code snippets.
I'm working on a project, and part of which is a scene where you get a custom mouse cursor upon entering the scene, and when you leave the scene, the custom mouse cursor is removed. The code I'm using to start the custom cursor is:
stage.addChild(crsTemple);
crsTemple.mouseEnabled = false;
crsTemple.addEventListener(Event.ENTER_FRAME, fl_CustomMouseCursor);
function fl_CustomMouseCursor(event:Event)
{
crsTemple.x = stage.mouseX;
crsTemple.y = stage.mouseY;
}
Mouse.hide();
with crsTemple being the instance name for the custom cursor. Then, when a new scene is entered (via rolling over an object), i have the following code in the new scene:
stage.addChild(crsTemple);
crsTemple.mouseEnabled = false;
crsTemple.addEventListener(Event.ENTER_FRAME, fl_CustomMouseCursor_4);
function fl_CustomMouseCursor_4(event:Event)
{
crsTemple.x = stage.mouseX;
crsTemple.y = stage.mouseY;
}
Mouse.hide();
crsTemple.removeEventListener(Event.ENTER_FRAME, fl_CustomMouseCursor_4);
stage.removeChild(crsTemple);
Mouse.show();
Unfortunately, whenever I go into the second scene, I get the regular mouse again, but it drops the crsTemple wherever the mouse was when the scene change happened, and it stays there for the rest of the time the file is running.
Any help is greatly appreciated, much thanks in advance for helping a noob like me!
No need to write the same code in new Scene. You can actually use all declarations form the first Scene. In the following code snippet MOUSE_MOVE handler (fl_CustomMouseCursor) from scene 1 will be called in scene 2 either. Custom cursor will also be accessible by its name crsTemple.
import flash.display.MovieClip;
import flash.events.MouseEvent;
var crsTemple:Sprite = new CrsTemple();
crsTemple.mouseEnabled = false;
addChild(crsTemple);
// for smooth cursor movement MOUSE_MOVE instead of ENTER_FRAME
stage.addEventListener(MouseEvent.MOUSE_MOVE, fl_CustomMouseCursor);
stage.addEventListener(MouseEvent.CLICK, nextStage); // for test purpose, just to switch the stage
function fl_CustomMouseCursor(event:Event):void
{
crsTemple.x = stage.mouseX;
crsTemple.y = stage.mouseY;
trace(crsTemple.x);
}
function nextStage(e:Event):void {
gotoAndStop(1,"Scene 2");
}
Mouse.hide();
stop();
here is a link to fla sample

Actionscript3 clearInterval is not working on TouchEvent.TOUCH_BEGIN

I have called a setInterval on TouchEvent.TOUCH_END and I want to clear it when ever screen is touched.
Here is my code:
import fl.motion.MotionEvent;
import flash.display.MovieClip;
import flash.utils.*;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
stage.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
function onTouchBegin(evt:TouchEvent)
{
clearInterval(MovieClip(root).myInterval);
}
function onTouchEnd(evt:TouchEvent)
{
MovieClip(root).myInterval = setInterval(showTimer,1000);
}
function showTimer()
{
trace("interval working");
}
Your provided code doesn't really explain everything so there will be a fair bit of speculation in this answer:
Possiblity No. 1:
Your way of casting root to MovieClip is not working. Try changing to following:
function onTouchBegin(evt:TouchEvent)
{
var intervalRef:int = (root as MovieClip).myInterval;
clearInterval(intervalRef);
}
Possiblity No. 2:
It seems that your code is written in a frame. And although if you define something in a previous frame it should work, but if you have the code on a different (lower) layer on the same keyframe it could define the variable later and your MovieClip(root).myInterval variable is undefined or null is the value is not defined. So check if your variable even exists:
function onTouchBegin(evt:TouchEvent)
{
trace(MovieClip(root) == null); // see if the root is defined
trace(MovieClip(root).myInterval); // see if the myInterval is defined
}
Possiblity No. 3:
You're cycling through frames. When I had 2 frames: one blank and one with your code, the code didn't work properly. Tested in Flash CC.
Possibility No. 4:
You have a run-time error somewhere else and your whole frame's code is not being executed. Do you use the debug version of Flash Player?
Possible solution for less headache:
Use a Timer. It's easy to control, easy to manage and dispose of. I've edited your code to work with Timer and tested. Feel free to use it for your project.
import fl.motion.MotionEvent;
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
var timer:Timer = (timer == null) ? new Timer(1000) : timer;
timer.addEventListener(TimerEvent.TIMER, onTick);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onTouchBegin); // you can change back to TouchEvent, but since you're using TOUCH_POINT it's pointless so I'd just use MouseEvent
stage.addEventListener(MouseEvent.MOUSE_UP, onTouchEnd);
function onTouchBegin(evt:Event)
{
timer.stop();
}
function onTouchEnd(evt:Event)
{
timer.start();
}
function showTimer()
{
trace("interval working");
}
function onTick(e:TimerEvent):void
{
showTimer();
}
I do want to note that your code works if I just copy-paste it in a single frame Flash file. But still, it's encouraged by Adobe to use Timer instead.

MOUSE_DOWN and MOUSE_UP not dispatching for custom Sprite

I have created a custom Sprite object which is not dispatching the MouseEvent.MOUSE_DOWN or MouseEvent.MOUSE_UP events. It is properly dispatching MouseEvent.MOUSE_MOVE events.
All event listeners are verified to be registered.
I apologize if this is a common or excessively simple question, but I have spent the last hour Googling and reading StackOverflow for questions or answers that fit my situation and simply have not found one. As far as I know, Sprite is an InteractiveObject and therefore should be dispatching all three of these events rather than only the MouseEvent.MOUSE_MOVE events.
Class Declaration:
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class CustomSprite extends Sprite {
Object Initialization in main.as
var circle:CustomSprite = new CustomSprite();
circle.graphics.lineStyle(3,0x00FF00);
circle.graphics.beginFill(0x0000FF,.5);
circle.graphics.drawCircle(0,0,50);
circle.graphics.endFill();
circle.x = 100;
circle.y = 100;
Event Listener Registration in Constructor:
addEventListener(MouseEvent.MOUSE_DOWN,mouseDownListener);
if (hasEventListener(MouseEvent.MOUSE_DOWN)) trace("MOUSE_DOWN listener exists");
addEventListener(MouseEvent.MOUSE_UP,mouseUpListener);
if (hasEventListener(MouseEvent.MOUSE_UP)) trace("MOUSE_UP listener exists");
addEventListener(MouseEvent.MOUSE_MOVE,mouseMoveListener);
if (hasEventListener(MouseEvent.MOUSE_MOVE)) trace("MOUSE_MOVE listener exists");
Event Listener Registration Output:
MOUSE_DOWN listener exists
MOUSE_UP listener exists
MOUSE_MOVE listener exists
Listener Functions as Part of CustomSprite Class:
private function mouseDownListener(e:MouseEvent):void {
trace("mouseDownListener");
}
private function mouseUpListener(e:MouseEvent):void {
trace("mouseUpListener");
}
private function mouseMoveListener(e:MouseEvent):void {
trace("mouseMoveListener");
}
Output after hovering over object and clicking several times:
mouseMoveListener
mouseMoveListener
mouseMoveListener
mouseMoveListener
Thanks in advance for any help you can offer - it is greatly appreciated!
What is looks like from the source you have provided is that you aren't adding the event listeners to the circle itself. This snippet I tested worked, provided I don't have your CustomSprite, but just the Sprite.
var circle:CustomSprite = new CustomSprite();
circle.graphics.lineStyle(3,0x00FF00);
circle.graphics.beginFill(0x0000FF,.5);
circle.graphics.drawCircle(0,0,50);
circle.graphics.endFill();
circle.x = 100;
circle.y = 100;
circle.addEventListener(MouseEvent.MOUSE_DOWN, function(event:MouseEvent):void{
trace("mouseDown");
});
circle.addEventListener(MouseEvent.MOUSE_UP, function(event:MouseEvent):void{
trace("mouseUp");
});
circle.addEventListener(MouseEvent.MOUSE_MOVE, function(event:MouseEvent):void{
trace("mouseMove");
});

AS3 - Error #1009: Cannot access a property or method of a null object reference

I'm making a game where if the enemy's bullet hits the user, the bullet disappears. Everything works fine except that I keep getting,
'Error #1009: Cannot access a property or method of a null object
reference'
Once the bullet hits the user (bullet disappears though). It confuses me because I've used almost exact the same code in another class where it works perfect.
package classes.enemy
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
import classes.Main;
public class Bullet extends MovieClip
{
var speed:Number;
public function initialize()
{
var stageReff:Stage = this.stage as Stage;
stage.addEventListener("enterFrame", enterFrame);
}
//code
function enterFrame(e:Event):void
{
this.x += speed;
if(this.hitTestObject(Main.user))
{
removeEventListener("enterFrame", enterFrame);
this.parent.removeChild(this);
// line above gives the error.
}
}
}
}
I have no clue what could be wrong.
Thanks in advance.
My guess is it has to do with the fact that you're adding an enter frame event listener to the stage, yet try to remove it from the listening object itself.
Try changing
var stageReff:Stage = this.stage as Stage;
stage.addEventListener("enterFrame", enterFrame);
to
addEventListener("enterFrame", enterFrame);
you're not removing the event listener from the stage, but the object itself :)
I would not recommend doing it like this, create one listener in your main game class, and call an update function on all objects!
The reason why it fails is because you're removing your Bullet from it's parent. So when you're referencing this.parent it returns null because there simply isn't a parent anymore. You're trying to remove the ENTER_FRAME event but because you set it on the stage the original ENTER_FRAME event keeps running. You can simply fix it like so:
if(this.x > 30)
{
stage.removeEventListener("enterFrame", enterFrame);
this.parent.removeChild(this);
}
But like #RasmusWriedtLarsen already pointed out, it's better to handle these events more globally. And also let the parent handle the removing of the Bullet.