How to change cursor on Roll Over event - actionscript-3

I'm making a point and click game in AS3 with flash.
I've changed the skin of my cursor by creating a new class "Souris". It's working just fine. Now I'm trying to change the skin of the cursor when it's on an object on the scene.
I've read that the MouseEvent.ROLL_OVER is the good method but I can't figure out how to do it...
I've got my Souris class like that :
public class Souris extends MovieClip
{
private var engine:Engine;
private var stageRef:Stage;
private var p:Point = new Point();
public function Souris(stageRef:Stage)
{
Mouse.hide(); //make the mouse disappear
mouseEnabled = false; //don't let our cursor block anything
mouseChildren = false;
this.stageRef = stageRef;
x = stageRef.mouseX;
y = stageRef.mouseY;
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true);
stageRef.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler, false, 0, true);
stageRef.addEventListener(Event.ADDED, updateStack, false, 0, true);
stageRef.addEventListener(MouseEvent.ROLL_OVER,hover);
}
private function updateStack(e:Event) : void
{
stageRef.addChild(this);
}
private function hover(e:MouseEvent):void {
souris.visible = false;
}
private function mouseLeaveHandler(e:Event) : void
{
visible = false;
Mouse.show(); //in case of right click
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler, false, 0, true);
}
private function mouseReturnHandler(e:Event) : void
{
visible = true;
Mouse.hide(); //in case of right click
removeEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler);
}
private function updateMouse(e:MouseEvent) : void
{
x = stageRef.mouseX;
y = stageRef.mouseY;
e.updateAfterEvent();
}
}
}
}
In my main class (Engine class) I've got :
private var souris:Souris;
public function Engine(){
souris = new Souris(stage);
stage.addChild(souris);
}
private function startGame(e:Event):void{
....
..
I've tried to put in the "Souris" class
stageRef.addEventListener(MouseEvent.ROLL_OVER,hover);
private function hover(e:MouseEvent):void {
Engine.souris.visible = false;
handCursor.visible = true ;
}
But it seems wrong...
I don't know what to put in my hover function. (I've got the "handCursor" in my library).
Thank you very much for your help!

If you have "handCursor" in your library, then you need to assign a class to it, like 'HandCursor'. I advise that classes start with an uppercase letter.
So your code would need to create a new instance of it then show it, like
var handCursor:HandCursor = new HandCursor; handCursor.visible = false;
handCursor.visible = false; makes it not visible, then to make it visible, you would:
handCursor.visible = true;
Also, handCursor is a local variable if put in a function, to make it global to use in all functions, you would need to put it at the beginning of your Class.
Also, are you getting any errors? If so, please share them.

Related

Actionscript 3 Call to a possibly undefined method

Here is the problem, the object is moved together with the clicked object. I want it to be moveable following the mouse pointer, but let the clicked object stays. so when an object is clicked, there will be 2 objects in the stage(the static and moving one).
I think I've figured it out by adding a new object to be moved. in function onClickHero I've tried movingHero = new heroes but it says "call to a possibly undefined method heroes". My question is there any other way how to make another clone of the clicked object since I made it in array? And why does movingHero = new heroes doesn't work?
I'm still amateur at classes. Sorry if it's messed up. Thanks for helping.
package {
import flash.display.MovieClip
import flash.events.MouseEvent
import flash.events.Event
import flash.display.Sprite
public class Hero {
private var heroesArray:Array;
private var heroContainer:Sprite = new Sprite;
private var hero1:MovieClip = new Hero1();
private var hero2:MovieClip = new Hero2();
private var moveHero:Boolean = false;
private var movingHero:MovieClip;
private var _money:Money = new Money();
private var _main:Main;
public function Hero(main:Main)
{ _main = main;
heroesArray = [hero1,hero2];
heroesArray.forEach(addHero);
}
public function addHero(heroes:MovieClip,index:int,array:Array):void
{
heroes.addEventListener(Event.ENTER_FRAME, playerMoving);
heroes.addEventListener(MouseEvent.CLICK, chooseHero);
}
public function playerMoving(e:Event):void
{
if (moveHero == true)
{
movingHero.x = _main.mouseX;
movingHero.y = _main.mouseY;
}
}
public function chooseHero(e:MouseEvent):void
{
var heroClicked:MovieClip = e.currentTarget as MovieClip;
var cost:int = _main._money.money ;
if(cost >= 10 && moveHero == false)
{
_main._money.money -= 10;
_main._money.addText(_main);
onClickHero(heroClicked);
moveHero = true;
}
}
public function onClickHero(heroes:MovieClip):void
{
movingHero = heroes;
heroContainer.addChild(movingHero);
}
public function displayHero(stage:Object):void
{
stage.addChild(heroContainer);
for (var i:int = 0; i<2;i++)
{
stage.addChild(heroesArray[i]);
heroesArray[i].x = 37;
heroesArray[i].y = 80+i*70;
heroesArray[i].width=60;
heroesArray[i].height=55;
heroesArray[i].buttonMode = true;
}
}
}
}
EDIT: I've tried to make movingHero = new Hero1(); but since I don't know which hero will be clicked so I can't just use Hero1 from library. and If I use movingHero = heroClicked I only get the value of hero1 which is a var from Hero1 movieclip. So, is there any way to call the movie clip from library the same as which hero was clicked in stage?
You seemingly want to clone an object while not knowing its type. If that object also containg game logic, it's not the best idea to say spawn new heroes of either type, this might make a mess of your code. But if not, you can get the exact class of the object given, and make an object of that class via the following code:
public function onClickHero(heroes:MovieClip):void
{
if (!heroes) {
trace('heroes is null!');
return;
}
var heroClass:Class = getDefinitionByName(getQualifiedClassName(heroes)) as Class;
movingHero = new heroClass(); // instantiate that class
heroContainer.addChild(movingHero);
// movingHero.startDrag(); if needed
}
Don't forget to clean up the movingHero once it's no longer needed.

remove or destroy child completely

I've got a child named "viseur" that appears on a particular scene and replace my actual cursor.
When the event "removeViseur" is called, I would like to completely remove the child "viseur" (and I'll use my previous cursor).
I did that :
stage.addEventListener("functionCalled", removeViseur, false, 0, true);
public function removeViseur(e:Event):void{
trace("removeViseur");
viseur.visible = false;
viseur.parent.removeChild(viseur);
viseur = null;
}
The child "viseur" is no longer here, but if do Alt+tab or changing window and came back, the child "viseur" come back...
Do you know how I can destroy it completely ? (I don't need it after this function is called)
Thx,
EDIT
Here is more of my code.
public static var viseur:Viseur;
var lookCocoDessous:Boolean = thisBack == "cocotierDessous";
if (lookCocoDessous) {
viseur = new Viseur(stage);
stage.addChild(viseur);
viseur.visible = true;
stage.addEventListener("functionCalled", removeViseur, false, 0, true);
public function removeViseur(e:Event):void{
trace("removeViseur");
viseur.visible = false;
viseur.parent.removeChild(viseur);
viseur = null;
}
And "viseur" has is own class like that
viseur.as :
public class Viseur extends MovieClip
{
private var engine:Engine;
private var stageRef:Stage;
private var p:Point = new Point();
public function Viseur(stageRef:Stage)
{
Mouse.hide(); //make the mouse disappear
mouseEnabled = false; //don't let our cursor block anything
mouseChildren = false;
this.stageRef = stageRef;
x = stageRef.mouseX;
y = stageRef.mouseY;
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true);
stageRef.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler, false, 0, true);
stageRef.addEventListener(Event.ADDED, updateStack, false, 0, true);
}
private function updateStack(e:Event) : void
{
stageRef.addChild(this);
}
private function mouseLeaveHandler(e:Event) : void
{
visible = false;
Mouse.show(); //in case of right click
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler, false, 0, true);
}
private function mouseReturnHandler(e:Event) : void
{
visible = true;
Mouse.hide(); //in case of right click
removeEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler);
}
private function updateMouse(e:MouseEvent) : void
{
x = stageRef.mouseX;
y = stageRef.mouseY;
e.updateAfterEvent();
}
}
}
}
Viseur is adding itself to the stage whenever Event.ADDED fires. This fires whenever anything is added to the stage (not just Viseur). You've also made Viseur a static property, thus ensuring it doesn't disappear from memory.
To be succinct: add Viseur only once, and from outside of itself (thereby removing the need to pass a stage reference). Be aware that once a DisplayObject is parented, it automatically gains stage & root properties which you can reference for mouseX and mouseY.
That said, if you're trying to replace the mouse cursor, I highly recommend taking a different tact: Native cursors.
See http://inflagrantedelicto.memoryspiral.com/2012/07/as3-quickie-native-mouse-cursors/

actionscript 3 Timer class and callback problems

I have a timer class in actionscript that looks like this:
public class AGTimer {
public var myTimer:Timer ;
public var done:Boolean = false;
public var timer_disable:Boolean = false;
public var started:Boolean = false;
public function AGTimer(num:Number = 0) {
this.timer_disable = false;
if (num != 0 ) timerStart(num);
// constructor code
}
public function timerStart(num:Number):void {
myTimer = new Timer(num * 1000, 1);
myTimer.addEventListener(TimerEvent.TIMER, runOnce);
myTimer.start();
started = true;
done = false;
}
public function runOnce(e:TimerEvent):void {
done = true;
}
public function timerDone():Boolean {
if (done && ! timer_disable) return true;
else if (!started ) return true;
else return false;
}
}
I have several of these in an array. I reference them with their index number. sometimes I start a timer and let it go, then before I have a chance to check it, I delete it by calling 'new AGTimer()' and creating a new one. Could it happen that the callback from the actionscript Timer object is still called somehow after the timer itself is deleted? What would I do about it if it did happen? I am trying to find a bug and am considering this sort of problem. What kind of error would I see?
Yes, a timer will continue to run callbacks even if it is not referenced somewhere. You have to remove event listener for the timer for it in order to remove it.
Basically something like this:
private function destroyTimer():void {
if(myTimer) {
myTimer.removeEventListener(runOnce);
myTimer.stop();
myTimer = null;
}
}

Register some properties in event handling

I want to show several images to my application
sourceAudioFile =(event.target as File);
sourceAudioFile.data;
var myLoader:Loader = new Loader();
var url :URLRequest = new URLRequest("file:///" + sourceAudioFile.nativePath);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
myLoader.load(url);
Registration Listener
private function onImageLoaded(e:Event):void
{
var image : Bitmap= new Bitmap(e.target.content.bitmapData);
image.scaleX = 0.5 ;
image.scaleY = 0.5 ;
}
Is there any way by which i can add some custom values to Event.COMPLETE to know what type of image is being loaded.
like e.imageName , e.noOfImage which i can access in complete handler & provide values to it when i register this event.
Thanks in advance
Yes you can, try registering event like:
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event){
dispatchEvent(new CustomEvent(CustomEvent.COMPLETE, "<imageType>"));
}, false, 0, true);
And Add new Class, extending the Event class:
public class CustomEvent extends Event {
public static const COMPLETE:String = "CustomEventComplete";
public var imageType:String = "";
public function CustomEvent(type:String, imageType:String = "", bubbles:Boolean = false, cancelable:Boolean = false){
super(type, bubbles, cancelable);
this.imageType = imageType;
}
override public function clone():Event {
return new CustomEvent(type, customTarget, bubbles, cancelable);
}
}
Now you can register for CustomEvent.COMPLETE & get the image type in the listener.
You can find out what ahs been loaded by checking LoaderInfo's url property
private function onImageLoaded(e:Event):void
{
var cli:LoaderInfo = e.target as LoaderInfo;//you added listener to the contentLoaderInfo property
trace(cli.url);//url of the media being loaded
//do something with it
}
also in this SO question you can get more sophisticated asnwer to your problem:)
pass arguments to event listener
Yes, there's a simple way:
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded(imageName, noOfImage));
myLoader.load(url);
function onImageLoaded(imageName:String, noOfImage:int):Function {
return function(e:Event):void {
// Respective "e", "imageName" and "noOfImage" are available for you here.
}
}
If you need to remove it later, change the first line to:
var functionOnImageLoaded:Function = onImageLoaded(imageName, noOfImage);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, functionOnImageLoaded);
Then later just do it like this:
myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, functionOnImageLoaded);
I've answered this before. See it here.

AS3 Mouse Over Change Image

Currently I'm trying to change image loaded in a sprite with mouseover event and change it back with mouseout. But it's not working correctly, am i missing something?
public class Tab extends Sprite
{
var imageLoader:Loader = new Loader();
var TabSprite:Sprite = new Sprite();
var SkinImages:Array = [Skin.TAB_ACTIVE,Skin.TAB_DISABLED,Skin.TAB_HOVER,Skin.TAB_VIEW];
public function Tab()
{
for each (var Image:String in SkinImages){
imageLoader.load(new URLRequest(Image));
}
TabSprite.buttonMode = true;
addChild(TabSprite);
TabSprite.addChild(imageLoader);
TabSprite.addEventListener(MouseEvent.MOUSE_OVER, onTabHover);
}
private function onTabHover(e:MouseEvent){
trace("HOVER");
TabSprite.removeEventListener(MouseEvent.MOUSE_OVER, onTabHover);
imageLoader.load(new URLRequest(Skin.TAB_HOVER));
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
TabSprite.addEventListener(MouseEvent.MOUSE_OUT, onTabOut);
});
}
private function onTabOut(e:MouseEvent){
trace("OUT");
TabSprite.removeEventListener(MouseEvent.MOUSE_OUT, onTabOut);
imageLoader.load(new URLRequest(Skin.TAB_VIEW));
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
TabSprite.addEventListener(MouseEvent.MOUSE_OVER, onTabHover);
});
}
}
You shouldn't nest listeners that way. Just add two in the constructor:
TabSprite.addEventListener(MouseEvent.ROLL_OVER, onTabHover);
TabSprite.addEventListener(MouseEvent.ROLL_OUT, onTabOut);
Note changing MOUSE_OVER to ROLL_OVER it's better in most cases. You shouldn't also load images at every mouse event. Preload them, and then use. Also using anonymous functions in listeners is bad practice as you are not able to remove that listener:
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
TabSprite.addEventListener(MouseEvent.MOUSE_OUT, onTabOut);
});
And in fact you are not removing it - this is bad.
for each (var Image:String in SkinImages){
imageLoader.load(new URLRequest(Image));
}
I doubt it works, I think you cannot load many images at once by using one loader.
Try this:
public class Tab extends Sprite
{
var imageOverLoader:Loader = new Loader();
var imageOutLoader:Loader = new Loader();
var TabSprite:Sprite = new Sprite();
var SkinImages:Array = Skin.TAB_ACTIVE,Skin.TAB_DISABLED,Skin.TAB_HOVER,Skin.TAB_VIEW];
public function Tab()
{
TabSprite.buttonMode = true;
this.addChild(TabSprite); // you also need to add as a Child "Tab" object in the Main Class
imageOutLoader.load(new URLRequest(Skin.TAB_VIEW));
imageOverLoader.load(new URLRequest(Skin.TAB_HOVER));
TabSprite.addChild(imageOutLoader);
TabSprite.addEventListener(MouseEvent.ROLL_OVER, onTabHover);
TabSprite.addEventListener(MouseEvent.ROLL_OUT, onTabOut);
}
private function onTabHover(e:MouseEvent){
TabSprite.removeChild(imageOutLoader);
TabSprite.addChild(imageOverLoader);
trace("HOVER");
}
private function onTabOut(e:MouseEvent){
TabSprite.removeChild(imageOverLoader);
TabSprite.addChild(imageOutLoader);
trace("OUT");
}
}
Try this.