AS3 Mouse_Over Getting Stuck - actionscript-3

I have many buttons being populated on the stage. They are all movieclips with an on and off state on frame one and 2. The problem is when you mouse over the buttons quickly sometimes it gets stuck on the over state. Is there something i am missing?
public class SimpleRollOverButton extends MovieClip
{
private var _selected:Boolean;
public function SimpleRollOverButton()
{
// EVENTS
this.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
this.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
this.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
enable();
}
//
// PUblic functions
//
public function enable():void
{
this.selected = false;
this.gotoAndStop(1);
this.mouseEnabled = this.mouseChildren = true;
this.buttonMode = true;
}
public function disable():void
{
this.mouseEnabled = this.mouseChildren = false;
this.buttonMode = false;
}
public function onState():void
{
this.disable();
this.selected = true;
this.gotoAndStop(2);
}
public function offState():void
{
this.enable();
}
//
// Private Functions
//
protected function onClick(e:MouseEvent):void
{
onState();
}
protected function onMouseOver(e:MouseEvent):void
{
this.gotoAndStop(2);
}
protected function onMouseOut(e:MouseEvent):void
{
this.gotoAndStop(1);
}
//
// ACCESSORS
//
public function get selected():Boolean
{
return _selected;
}
public function set selected(value:Boolean):void
{
_selected = value;
}
}

You could add a listener to the stage or to the MovieClip, which contains the buttons (if it has a background, and its not transparent):
stage.addEventListener(MouseEvent.ROLL_OVER, turnThemOff);
function turnThemOff(evt:MouseEvent):void {
for (var i:int=0; i<yourButtons.length; i++) yourButtons[i].gotoAndStop(1);
}
If you move the mouse quickly away from the SWF movie, this could help:
stage.addEventListener(Event.MOUSE_LEAVE, turnThemOff);

Related

ActionScript 3.0 How to call SoundManager to all classes

i have 3 classes. the SoundManager.as, MainMenu.as, and OnGame.as.
How can I call SoundManager on MainMenu.as and OnGame.as properly?
I tried:
MainMenu.as:
var sound:SoundManager = new SoundManager();
OnGame.as:
var sound:SoundManager = new SoundManager();
but when i turn off the bgmusic on OnGame.as, the bgmusic on MainMenu doesn't turn off.
Sorry for my bad english and explanation. please help me.
//edited
When i call function 'MUTE' from the SoundManager in onGame.as and go back to mainmenu, the bgmusic in MainManu.as is not muted. help please me.
SoundManager.as
public static var mVolume:SoundTransform = new SoundTransform();
public static var mChannel:SoundChannel = new SoundChannel();
public static var mPosition:Number;
public static var music:Sound = new Sound();
public static var Music:Boolean = true;
public function LOADMUSIC():void {
if(Music){
UNMUTE();
}else {
MUTE();
}
music.addEventListener(Event.COMPLETE, LOADMUSIC);
mChannel = music.play();
mChannel.addEventListener(Event.SOUND_COMPLETE, ONCOMPLETE);
}
public function ONCOMPLETE(e:Event):void {
if(DataBase.music){
UNMUTE();
}else{
MUTE();
}
e.currentTarget.removeEventListener(Event.SOUND_COMPLETE, ONCOMPLETE);
LOADMUSIC();
}
public function REMOVE_MUSIC():void{
try{
mChannel.stop();
music = null;
}catch(e:Error) {}
}
public function MUTE():void {
mVolume.volume = 0;
mChannel.soundTransform = mVolume;
}
public function UNMUTE():void {
mVolume.volume = 1;
mChannel.soundTransform = mVolume;
}
MainMenu.as
var sound:SoundManager;
btn_music.addEventListener(TouchEvent:TOUCH_END, MUSIC);
public MainMenu(sound:SoundManager){
this.sound = sound;
sound.REMOVE_MUSIC();
SoundManager.music = new BackgroundMusic01();
sound.LOADMUSIC();
}
private function MUSIC(e:TouchEvent):void {
if(SoundManager.Music){
SoundManager.music = false;
sound.MUTE();
}else {
SoundManager.Music = true;
sound.UNMUTE();
}
}
OnGame.as
var sound:SoundManager;
btn_music.addEventListener(TouchEvent:TOUCH_END, MUSIC);
public OnGame(sound:SoundManager){
this.sound = sound;
sound.REMOVE_MUSIC();
SoundManager.music = new BackgroundMusic02();
sound.LOADMUSIC();
}
private function MUSIC(e:TouchEvent):void {
if(SoundManager.Music){
SoundManager.music = false;
sound.MUTE();
}else {
SoundManager.Music = true;
sound.UNMUTE();
}
}
There's no problem in changing the background music. When i mute the bgmusic in MainMenu using MainMenu btn_music it works, it works also in OnGame. But if it is from OnGame to MainMenu or MainMenu to Ongame, the bgmusic is not muted . I don't see what's wrong. please help me. sorry for my bad english.
Singleton or some other static (global) access is one easy way to do it. But just to add an alternative solution, according to some a "better way" is to use dependency injection. A simple example of this for your situation could look like this:
First, in your MainMenu and OnGame class you add a constructor argument (effectively declaring a dependency) of a SoundManager instance:
public class MainMenu {
private var sound:SoundManager;
public function MainMenu(sound:SoundManager){
this.sound = sound;
}
}
public class OnGame {
private var sound:SoundManager;
public function OnGame(sound:SoundManager){
this.sound = sound;
}
}
Then in a higher level class, you can create a single SoundManager and pass it into the classes that need it:
public class Main {
private var sound:SoundManager;
public function Main(){
sound = new SoundManager();
}
private function showMenu():void {
var menu:MainMenu = new MainMenu(sound);
addChild(menu);
}
private function showGame():void {
var game:OnGame = new OnGame(sound);
addChild(game);
}
}
The end result is that you have a single SoundManager instance being re-used between various classes.
There are several ways to do it, one of them is to use a Singleton class.
Follow an example:
package
{
public class CustomSoundManager
{
private static var _instance:CustomSoundManager;
public function CustomSoundManager()
{
if (_instance)
{
throw new Error('CustomSoundManager... use getInstance()');
}
_instance = this;
}
public static function getInstance():CustomSoundManager
{
if (!_instance)
{
new CustomSoundManager();
}
return _instance;
}
public function soundOn():void
{
// your logic to turn the sound on
}
public function soundOff():void
{
// your logic to turn the sound off
}
}
}
So, doesn't matter where (e.g. MainMenu.as, OnGame.as), you can use just these methods:
CustomSoundManager.getInstance().soundOn();
CustomSoundManager.getInstance().soundOff();
Because i can't see what's wrong in my code. Since I only got 1 channel in my game, i used SoundMixer to mute and unmute the music background.
import flash.media.SoundMixer;
...
...
public function MUTE():void {
mVolume.volume = 0;
SoundMixer.soundTransform = mVolume;
}
public function UNMUTE():void {
mVolume.volume = 1;
SoundMixer.soundTransform = mVolume;
}
thanks.

Constructor argument error

my english is poor because this is not my main language but i'll do my best.
I need help with the argument to the constructor because i dont know where to take all these information.
here my defaultitem class:
public class DefaultItem extends MovieClip
{
private var _id:String;
private var _lastX:int;
private var _lastY:int;
private var _isStackable:Boolean = false;
private var _type:String;
private var _isDragging:Boolean = false;
private var _currentContainer:DefaultContainer;
private var _lastContainer:DefaultContainer;
public function DefaultItem($id:String, $type:String, $x:int, $y:int)
{
stop();
id = $id;
type = $type;
x = $x;
y = $y;
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
init();
}
public function init():void
{
buttonMode = true;
mouseChildren = false;
_lastX = x;
_lastY = y;
addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
this.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
//resolve drag bugs
}
/**
* Mouse Event Handlers
*/
private function onMouseDownHandler(e:MouseEvent):void
{
isDragging = true;
this.mouseEnabled = false;
dispatchEvent(new ItemEvent(ItemEvent.ITEM_PICKED_UP, this));
}
private function onMouseUpHandler(e:MouseEvent):void
{
// check if item is being dragged
if (isDragging)
{
isDragging = false;
this.mouseEnabled = true;
dispatchEvent(new ItemEvent(ItemEvent.ITEM_DROPPED, this));
}
}
/**
* Getters & Setters
*/
public function get id():String { return _id; }
public function set id(value:String):void
{
_id = value;
}
public function get lastX():int { return _lastX; }
public function set lastX(value:int):void
{
_lastX = value;
}
public function get lastY():int { return _lastY; }
public function set lastY(value:int):void
{
_lastY = value;
}
public function get currentContainer():DefaultContainer { return _currentContainer; }
public function set currentContainer(value:DefaultContainer):void
{
_currentContainer = value;
}
public function get lastContainer():DefaultContainer { return _lastContainer; }
public function set lastContainer(value:DefaultContainer):void
{
_lastContainer = value;
}
public function get type():String
{
return _type;
}
public function set type(value:String):void
{
_type = value;
}
public function get isDragging():Boolean
{
return _isDragging;
}
public function set isDragging(value:Boolean):void
{
_isDragging = value;
}
/**
* Destroys item
*/
public function destroy():void
{
buttonMode = false;
removeEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
this.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
}
}
}
here my item class:
public class Slot extends DefaultContainer
{
// vars
private var _id:String;
private var _item:DefaultItem;
private var _type:DefaultItem;
//private var isdragging:DefaultItem;
public var defaultitem:DefaultItem = new DefaultItem(id, _type, x, y);
// trace(DefaultItem.getisDragging());
//trace(DefaultItem.getisDragging());
/**
* Constructor
*
* #param $id Slot id
*/
public function Slot($id:String)
{
addEventListener(MouseEvent.ROLL_OUT, onMouseOutHandler);
addEventListener(MouseEvent.ROLL_OVER, onMouseOverHandler);
id = $id;
setLabel($id);
stop();
}
/**
* Slot Methods
*/
public function getItem():DefaultItem { return _item; }
public override function addItem($item:DefaultItem):void
{
_item = $item;
addChild(_item);
//
this.gotoAndStop(2); //active slot
}
public override function removeItem($item:DefaultItem):void
{
removeChild(_item);
_item = null;
this.gotoAndStop(1); //default slot
}
public function hasItem():Boolean
{
if (_item == null)
{
return false;
}
else
{
return true;
}
}
private function onMouseOutHandler(e:MouseEvent):void {
trace("mouseOutHandler");
this.gotoAndPlay("out");
}
private function onMouseOverHandler(e:MouseEvent):void {
trace("mouseoverHandler");
// if (!isDragging)
//{
//trace("drag = "+ isDragging);
this.gotoAndPlay("over");
// }
//else {
//trace("drag = " + isDragging );
//this.gotoAndPlay("dragUp");
// }
}
/**
* Getters & Setters
*/
public function get id():String { return _id; }
public function set id(value:String):void
{
_id = value;
}
public function setLabel($label:String):void
{
this.label.text = $label;
}
/**
* Destroy
*/
public function destroy():void
{
removeItem(_item)
}
}
}
the problem is here public var defaultitem:DefaultItem = new DefaultItem(id, _type, x, y);
i'm not sure id and _type is working good. I wanna know where to get all these information because i need to call the function isdragging and if i use the var id he target the item and not the defaultcountainer id thanks guys
You are creating and instance of DefaultItem but passing wrong arguments.
public var defaultitem:DefaultItem = new DefaultItem(id, _type, x, y);
Since this is created prior to constructor running, id is null, _type is not a String and is null and x, y are out of scope.
It should be:
public var defaultitem:DefaultItem;
Then in Slot constructor:
id = $id;
defaultitem = new DefaultItem(id, _type, x, y);
//but _type is still not a String and is still null
It seems to me like you're dragging an item onto something, sorry if I've misunderstood.
But, in that case, you can use something like:
var itemID:String = e.target.id;
var itemType:String = e.target._type;
That's in case you have the item's id and type stored somewhere.
Also, as for the x and y, those depend on where you want to put them.
For example, if you had a character and you wanted to give him a sword, it would look something like:
//somewhere in your code:
weapon.id = "Iron Sword";
weapon._type = "Sword";
//And then when you get to the default item part...
var itemId:String = e.target.id;
var itemType:String = e.target._type;
var defaultitem:DefaultItem = new DefaultItem(itemID,itemType, character.x, character.y);
Again, sorry if I misunderstood. Best of luck with your program!

Can multiple mouse actions be added to a button? How?

So i have a ton of button on stage and id like to assign the same function to all the buttons.
I want the function itself to evaluate whether ot not the event received was a MOUSE_CLICK or a MOUSE_HOVER and based on the event do something...
What i have is something like this....
btn1.addEventListener(MouseEvent.CLICK, makeListener('option1'));
btn2.addEventListener(MouseEvent.CLICK, makeListener('option2'));
btn3.addEventListener(MouseEvent.CLICK, makeListener('option3'));
btn4.addEventListener(MouseEvent.CLICK, makeListener('option4'));
btn5.addEventListener(MouseEvent.CLICK, makeListener('option5')); // and so on for about 100 buttons
btn1.addEventListener(MouseEvent.MOUSE_HOVER, makeListener('option1'));
btn2.addEventListener(MouseEvent.MOUSE_HOVER, makeListener('option2'));
btn3.addEventListener(MouseEvent.MOUSE_HOVER, makeListener('option3'));
btn4.addEventListener(MouseEvent.MOUSE_HOVER, makeListener('option4'));
btn5.addEventListener(MouseEvent.MOUSE_HOVER, makeListener('option5')); // and so on for about the same 100 buttons
function makeListener(option: String): Function {
return function (event: Event): void {
// DO something
}
}
What I would like is something like this... (obviously it doesnt work)
btn1.addEventListener(MouseEvent.CLICK || MouseEvent.CLICK, makeListener('option1'));
btn2.addEventListener(MouseEvent.CLICK || MouseEvent.CLICK, makeListener('option2'));
btn3.addEventListener(MouseEvent.CLICK || MouseEvent.CLICK, makeListener('option3'));
btn4.addEventListener(MouseEvent.CLICK || MouseEvent.CLICK, makeListener('option4'));
btn5.addEventListener(MouseEvent.CLICK || MouseEvent.CLICK, makeListener('option5')); // and so on for about 100 buttons
function makeListener(option: String): Function {
return function (event: Event): void {
if (event = MOUSE_CLICK){
// DO something
} else if(event = MOUSE_HOVER){
// Do Something else
}
}
}
Any ideas?
I'd add CLICK and MOUSE_HOVER listeners in button class and in event handler for them dispatch CustomEvent.
Next on the stage where you are listening for all this CLICK and HOVER events I'll addEventListener for this custom Event and in one of the parameters pass which action you want to do.
So 1st you need ButtonCustomEvent class with const and extra param:
public class ButtonCustomEvent extends Event
{
public static const CUSTOM_EVENT:String = "ButtonCustomEvent::CUSTOM_EVENT";
private var _customParam:String;
public function ButtonCustomEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
public function get customParam():String
{
return _customParam;
}
public function set customParam(value:String):void
{
_customParam = value;
}
}
Next in your button class:
public class MyButtonClass extends Sprite
{
public function MyButtonClass ()
{
super();
addEventListener(MouseEvent.CLICK, handleEvent);
addEventListener(MouseEvent.MOUSE_OVER, handleEvent);
}
public function handleEvent(event:MouseEvent):void
{
var myEvent:ButtonCustomEvent = new ButtonCustomEvent(ButtonCustomEvent.CUSTOM_EVENT, true);
myEvent.customParam = event.type;
dispatchEvent(myEvent);
}
}
And then if class where you are adding listeners for ~100 buttons you can do now:
addEventListener(ButtonCustomEvent.CUSTOM_EVENT, handleEvent);
public function handleEvent(event:ButtonCustomEvent):void
{
if(event.customParam == MouseEvent.CLICK)
{
//DO something
}
else if(event.customParam = MouseEvent.MOUSE_OVER)
{
//Do Something else
}
}

AS3 TypeError: Error #2007: Parameter hitTestObject must be non-null

TypeError: Error #2007: Parameter hitTestObject must be non-null.
I am working on a game right now and trying to get it so the player will collide with the ground (he already collides with table)
It says the problem is happening in playerOneCollisions
table and ground are just classes with the basic class code linked to movieclips,
they are extended movieclips (if that matters), and they have imported stage and movieclip (again, if that matters)
(the parts I think are important)
Player.as
public var main:Main;
public var table:Table;
public var player:Player;
public var ground:Ground;
public function playerOneCollisions(table, ground)
{
if(this.hitTestObject(table))
{
trace("tabled");
animation = "kong";
}
if(this.hitTestObject(ground))
{
trace("grounded");
animation = "idle";
}
}
The function playerOneCollisions is called in Main.as
public function GameClock(timerEvent:TimerEvent):void
{
player.playerOnePress();
player.playerOneKeyResults();
player.playerOneCollisions(table, ground);
player.playerAnimaitons();
}
The rest of the code incase I was wrong about the important parts
Player.as
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import KeyObject;
import Table;
public class Player extends MovieClip
{
public var stageRef:Stage;
public var key:KeyObject;
public var main:Main;
public var table:Table;
public var player:Player;
public var ground:Ground;
public var leftPressed:Boolean = false;
public var rightPressed:Boolean = false;
public var upPressed:Boolean = false;
public var downPressed:Boolean = false;
public var grounded:Boolean = false;
public var animation:String = "idle";
public var runSpeed:Number = 5;
public var animationState:String = "idle";
public function Player (stageRef:Stage, X:int, Y:int):void
{
this.stageRef = stageRef;
this.x = X;
this.y = Y;
key = new KeyObject(stageRef);
}
public function playerOnePress()
{
if(key.isDown(37) || key.isDown(65)){ // if left arrow or A is pressed
leftPressed = true;
//trace("left pressed");
} else {
leftPressed = false;
}
if(key.isDown(38) || key.isDown(87)){ // if up arrow or W is pressed
upPressed = true;
//trace("up pressed");
} else {
upPressed = false;
}
if(key.isDown(39) || key.isDown(68)){ //if right arrow or D is pressed
rightPressed = true;
//trace("right pressed");
} else {
rightPressed = false;
}
if(key.isDown(40) || key.isDown(83)){ //if down arrow or S is pressed
downPressed = true;
//trace("down pressed");
} else {
downPressed = false;
}
}
public function playerOneKeyResults()
{
if(leftPressed)
{
// trace("left");
this.x -= runSpeed;
}else if(rightPressed)
{
// trace("right");
this.x += runSpeed;
}
}
public function playerOneCollisions(table, ground)
{
if(this.hitTestObject(table))
{
trace("tabled");
animation = "kong";
}
if(this.hitTestObject(ground))
{
trace("grounded");
animation = "idle";
}
}
public function playerAnimaitons()
{
if(animation == "kong")
{
this.gotoAndStop(2);
}
if(animation == "idle")
{
this.gotoAndStop(1);
}
}
}
}
Main.as
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Main extends MovieClip
{
public var gameTimer:Timer;
public var player:Player;
public var table:Table;
public var ground:Ground;
public function Main():void
{
gameTimer = new Timer (30);
gameTimer.addEventListener(TimerEvent.TIMER, GameClock);
gameTimer.start();
player = new Player(stage, 80, 420);
stage.addChild(player);
}
public function GameClock(timerEvent:TimerEvent):void
{
player.playerOnePress();
player.playerOneKeyResults();
player.playerOneCollisions(table, ground);
player.playerAnimaitons();
}
}
}
One thing I notice is that you have table and ground as class properties of Player, and they are also parameters for the method you are having trouble with.
The table and/or ground properties of your Player class are likely null as I don't see code that sets them.
It's not good practice to have method parameters named the same as your class properties.
Try removing the properties in your Player class. (I don't see them being set or used)
If you still get the error, trace out their values at the beginning of the playerOneCollisions method and ensure they are not null.
If they are null, the problem exists outside this class and you are passing in a null value.
I should also note that I don't see anywhere in the Main class where you set the table or ground properties, so they are null unless you have not shown us all the code. If they are null, then that will certainly cause the issue you are experiencing.

How to correctly use KeyboardEvent on Flash

I have a problem making a KeyboardEvent work in the game I'm starting. I have three classes, one for handling the levels, one that is the actual level and one to represent the avatar:
Level
import flash.display.MovieClip;
import flash.events.Event;
public class Fase extends Cena
{
var avatar:Avatar;
public function Fase()
{
// constructor code
this.addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
public function onAdded(e:Event)
{
avatar = new Avatar();
this.addChild(avatar);
avatar.x = stage.width/2;
avatar.y = 30;
}
public function die()
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAdded);
(this.parent as ScreenHandler).removeChild(this);
}
}
Avatar
public class Avatar extends MovieClip
{
public function Avatar()
{
// constructor code
this.addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
public function onAdded(e:Event)
{
//stage.focus=this;
this.addEventListener(KeyboardEvent.KEY_DOWN, apertou);
}
public function apertou(event:KeyboardEvent)
{
trace("o");
if(event.keyCode == Keyboard.LEFT)
{
this.x++;
}
}
}
I have all the packages on both classes an all works if I use the stage.focus=this on the Avatar, but if I click somewhere else during game excecution the focus is lost and it doesn't work anymore. Please can anyone help me?
Thanks in advance
Keyboard events only trigger when the object they're assigned to are the current focus.
Fortunately, the stage always has focus by default. This means you can add your event listeners to the stage to always have the keyboard events trigger as expected:
stage.addEventListener(KeyboardEvent.KEY_DOWN, apertou);
You can move the key handler from the avatar to the level or stage and then move your avatar in there.
public class Fase extends Cena
{
var avatar:Avatar;
public function Fase()
{
// constructor code
this.addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
public function onAdded(e:Event)
{
avatar = new Avatar();
this.addChild(avatar);
avatar.x = stage.width/2;
avatar.y = 30;
addEventListener(KeyboardEvent.KEY_DOWN, apertou);
}
public function die()
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAdded);
(this.parent as ScreenHandler).removeChild(this);
}
public function apertou(event:KeyboardEvent)
{
if(event.keyCode == Keyboard.LEFT)
{
avatar.x++;
}
}
}