Tutorials

March 26, 2009

An Even Better AS3 OOP Flash Custom Cursor

More articles by »
Written by: Par
Tags: , , , , , , , , , ,
cc-tn2

Share on TwitterShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit

You are reading AS3 Flash Custom Cursor Read more from this series of articles.

Okay so Attila K. made a few good points over in the original tutorial on building a custom cursor. Now I’m going to take those points and build a much better, more versatile custom cursor.  So if you haven’t read the original tutorial, you need to go read it first, so click here and start from the beginning.

What was wrong with the first one? Well the points Attila K. made are as follows:

  • When you move the mouse out of the flash content window… make the cursor disappear.
  • When you right Click make the cursor disappear.
  • And when new things are added to the stage… they appear on top of the cursor.

Excellent points. So let’s make it happen. If you did the previous tutorial grab your final source code and let’s get started. If not, you can download the end source from the previous tutorial here.

Okay so let’s address all these issues one at a time.

Problem 1: Mouse moves off flash screen, how do I make the cursor disappear?

Alright, so moving the mouse out of the flash window doesn’t get rid of the cursor.  But to make the cursor feel like a cursor and not just some random movieclip following the mouse, we have to make our cursor disappear when we leave the window.

It’s our lucky day because the solution is simple. We just need to listen for one event, Event.MOUSE_LEAVE. Now to add it all we need to do is go into our Cursor class constructor function and add the new listener. Here’s our new constructor function and the mouse leave handler function, just update your class with them:

		public function Cursor(stageRef:Stage)
		{
			Mouse.hide(); //make the mouse disappear
			mouseEnabled = false;
			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);
		}
 
		private function mouseLeaveHandler(e:Event) : void
		{
			visible = false;
		}

Okay let me explain:

  • stageRef.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler, false, 0, true); So we add this to our constructor… now when the mouse leaves the flash window we know it… and we’re going to call mouseLeaveHandler to fix it.
  • visible = false; Yeah… so the mouse left… let’s make our custom cursor lose visiblity. Problem solved?

Here’s our swf.

Hmm…. well it does work. When we leave the stage the cursor disappears, but when we come back on the stage it doesn’t reappear. So what’s a good solution. We could just add Mouse.show(); every time the mouse moves. But that’s useless code 90% of the time. Let’s avoid that if we can. And the good thing is, we can.

So to solve the issue, we are simply going to add an event listener that checks when the mouse moves. Wait, we already did that right? Right. But here’s the cool thing, you can listen for the same event twice and call two different functions.  So in mouseLeaveHandler we’re going to add another MOUSE_MOVE listener.

Here’s our new mouseLeaveHandler and our completely new mouseReturnHandler.

		private function mouseLeaveHandler(e:Event) : void
		{
			visible = false;
			Mouse.show();
			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);
		}

Sweet… nothing really to break down here. When our mouse leaves the window we call mouseLeaveHandler which turns off our custom cursor and sets an event listener that waits on the mouse to move. When the mouse moves again (inside the flash player) mouseReturnHandler is called. As a result mouseReturnHandler sets our cursor back to visible and removes our listener that calls mouseReturnHandler so it isn’t called every time the mouse moves.

Also I went ahead and added Mouse.hide() and Mouse.show() to solve an issue with right click.  To elaborate on the issue,  When you right click in Flash, the mouse leave event fires. So our cursor will disappear, which is great. The problem is, at a right click, the actual mouse cursor needs to reappear and we have to make it disappear again on the return. So Mouse.show() and Mouse.hide() fixes the issue.

Here’s it working now :D

Problem 2: When I add a new MovieClip to the stage it covers up my mouse cursor.

So, if you are wondering what I’m talking about here. Let’s write up a quick example so I can show you. Goto your Main class and replace it’s code with this… it’s not really important to the tutorial but I’ll explain what’s happening after the code.

package com.asgamer.cursor
{
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	public class Main extends Sprite
	{
 
		private var cursor:Cursor;
		private var timer:Timer;
 
		public function Main() : void
		{
			cursor = new Cursor(stage);
			stage.addChild(cursor);
 
			timer = new Timer(1000);
			timer.start();
			timer.addEventListener(TimerEvent.TIMER, createNewMc);
		}
 
		private function createNewMc(e:TimerEvent) : void
		{
			var mc:MovieClip = new MovieClip();
 
			mc.graphics.beginFill(0xFFAA00);
			mc.graphics.drawCircle(0,0, Math.random() * 50);
			mc.graphics.endFill();
 
			mc.x = Math.random() * 550;
			mc.y = Math.random() * 400;
			stage.addChild(mc);
		}
 
	}
 
}

You got it, source code breakdown time:

  • This is very simple.  I create a new timer, I explain them in much more detail here,  with a second delay that runs createNewMc every time it fires.
  • createNewMc then creates a new MovieClip and using Flash’s graphics class. I draw an orange circle of random size and position it randomly then add it to the stage.

Now I know that’s not very detailed, but this tutorial isn’t about the graphics class, if you want more info on that let me know and I’ll write some tutorials on it as well. Our ultimate goal here was to create MovieClips and add them to the stage so you can see what happens to our cursor. So compile your script. [you may want to refresh the page if the orange balls have taken over : ) ]

Great… see the problem. Our mouse goes beneath all the newly added graphics. That isn’t cool but we can solve it… and there’s many ways to do it. So let’s brainstorm a minute.  We could always add our new movieclips using addChildAt which allows us to select the place in the display stack that we want to drop the new MovieClip. We could write something like this.

stage.addChildAt(mc, stage.numChildren-2);

This way our mouse, which is on top, will always stay on top. But it would be a lot more awesome if we could just write stage.addChild(mc) and our mouse would stay on top.  Another option is to write a function called updateStack in our Cursor that we could call every time we add a new child to the stage.  I like this idea… but I’d rather automate it than have to call it every time myself.  Guess what, we can automate :D Let me show you the code and then we’ll explain it.

Here’s our new Cursor.as file:

package com.asgamer.cursor
{
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.ui.Mouse;
 
	public class Cursor extends MovieClip
	{
 
		private var stageRef:Stage;
		private var p:Point = new Point(); //keeps up with last known mouse position
 
		public function Cursor(stageRef:Stage)
		{
			Mouse.hide(); //make the mouse disappear
			mouseEnabled = false;
			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;
 
			var newRotation:Number = Math.atan2(y - p.y, x - p.x) * 180 / Math.PI;
			if (newRotation - rotation > 180)
					newRotation -= 360;
			else if (rotation - newRotation > 180)
					newRotation += 360;
 
			rotation -= (rotation - newRotation) / 10;
 
			p.x = x;
			p.y = y;
 
			e.updateAfterEvent();
		}
 
	}
 
}

Okay. Nothing too big really. here’s what we added:

  • stageRef.addEventListener(Event.ADDED, updateStack, false, 0, true); So everytime something is added to stage we call updateStack! Simple and it works, can’t beat that.
  • updateStack. What is there to explain in this function? It’s super simple, each time it’s called we just readd our cursor to the top of the stage’s display stack. (Because addChild automatically drops whatever we add to the top of the stack)

Alright. here’s our final swf and new cursor that is even more awesome than the last one.

Okay so there you have it.  We’re one step closer to a perfect flash custom cursor.  Here’s the final source code:

An Even Better AS3 OOP Flash Custom Cursor Source Code Archive

Similar Posts:


Share on TwitterShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit


About the Author

Par
Hey! Don't be surprised, I'm a flash developer. While Flash is definitely one of my favorite languages to develop in, most of all I just like making games. If you want to see the games I've developed so far head over to my website, DigitallyBold, in the link below. If you want to know more about what I'm working on now and in the future be sure to follow me on twitter.




22 Comments


  1. Attila K.

    Great tutorial! ^^


  2. Clouse

    So how exactly can we get it so that when i click with the custom cursor, the regular mouse won’t appear?


  3. Fei

    nice tutorial. jus 1 question:

    in the updateStack function, when you do addChild(this), does it automatically remove the old cursor that’s already in the stage? if not, why don’t you first remove it?

    again, thx for the tutorial!


  4. Fei

    me again. played around it a little bit. added “stageRef.removeChild(this)” for the updateStack function, somehow throws a event dispatch recursion error. that makes me wonder why just do “stageRef.addChild(this)” only won’t cause the same recursion error? doesn’t that statement will trigger the udpateStack function again and again?


  5. Par

    I’m not sure what’s causing your recursion issue but doing addChild over and over isn’t going to make a new cursor so why would we remove it? We’re just adding the child to the display stack at the top. If it’s already in the stack it will just move it to the top of the stack.


  6. Fei

    i see. thx.


  7. @Fei: DisplayObjects can only have one parent. If you add a DO to another DO it is first removed from it’s current parent. If you add a DO to its parent it short-circuits the remove/re-add and just updates it’s position in the display list (which would be to the top in the case of addChild, or wherever you specify in the case of addChildAt).

    Thus, no REMOVED nor ADDED events are dispatched.

    In your code, when you called removeChild() first you split the atomic operation of a single addChild() call to the non-atomic removeChild()/addChild(). Since those events are dispatched immediately when the display list is modified it resulted in the ADDED event getting triggered again, and so forth…


  8. Par

    Thanks Troy :D Much more detailed explanation.


  9. Samuel

    Great! but I was wondering, how can I make that the cursor changes when I press the left click button? Is it possible? I have been looking for a tutorial that can help me with that but it is nowhere to be found; Can I make this using AS3?


  10. Par

    It can be done… you’ll have to setup listeners based on MouseEvent.MOUSE_DOWN and MouseEvent.MOUSE_UP.

    Or if you have a quick flicker and literally mean click then you can do it on MouseEvent.MOUSE_CLICK.


  11. guc

    Thanks for the great tutorial helped me alot. I’ve been wondering also about what Samuel mentioned. Do I need to create another MC w/new graphic for the MOUSE_DOWN/MOUSE_UP and call to them, or is there a way I can put it in the same MC as the basic cursor?


  12. Nice demo. One correction, in the final code sample, in the mouseReturnHandler function:

    removeEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler);

    should be

    stageRef.removeEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler);


  13. Par

    Thanks for pointing that out :D


  14. jack

    thx for the tutorial this site is really good ^^


  15. Thanks for this great tutorial. I’ve adapted it for my own use (I’m using PushButtonEngine) and added a couple of small features for usability. Here’s a link to my forum post about it, which includes my final code: http://pushbuttonengine.com/forum/viewtopic.php?f=5&t=377&start=0


  16. Alf

    Event.ADDED is also dispatched for example if you hold your mouse over a button, and when other movieclips contains motion tweens. So basicly this updateStack function is called many times unnecessarily! I’m guessing updateStack doesnt cost a lot of cpu, but still this is worth mentioning :)

    adobe docs: “The Event.ADDED constant defines the value of the type property of an added event object.”

    Maybe Event.ADDED_TO_STAGE is possible to use? I havent looked into that.


  17. the_horrible

    Best reason I’ve found online!!
    The best workarround is the “right-click” handling!!
    I love it!


  18. great post!

    Excuse me, can you tell me your SyntaxHighlighter Plugin name ?


  19. Hi all, found this tut really useful. I adapted the class and used it in a SinCity inspired first person shooter, you can play it here.

    http://www.newgrounds.com/portal/view/548231
    Thx again, and keep em’ coming


  20. David

    NOOOO
    THE ORANGE BALLS HAS TAKEN OVER


  21. StephenF

    Ive noticed in my own implementation of a rotatable cursor when there is interection with horizontal stacks of controls like checkboxes and sliders, there is a problem. The issue is that the exact ‘click point’ of the cursor seems to move when the rotation changes.

    Wondering if you were seeing same?



Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">


Advertisement