Tutorials

March 24, 2009

Creating an AS3 Object Oriented Custom Cursor

cc-tn

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.

If you have been around flash for any time whatsoever you’ve probably made a custom cursor. If not this tutorial is definitely for you. However, if you have made a custom cursor then the great thing about this tutorial is that we are going to learn to make an object oriented mouse cursor. What’s the benefits? Well we are going to create a class called cursor that we can use in all our future projects, you’ll never have to write a mouse cursor script again. Well, as long as you don’t want to get crazy and add cool effects that is. This tutorial will work great for your games when you want a new mouse that fits the style of gameplay you are developing. So let’s start the tutorial:

Step 1: Creating the Art for our New Mouse Cursor

Our new cursor will be an extension of MovieClip so you are going to do all our artwork in a MovieClip. So create a new MovieClip by pressing CTRL+F8 and name it cursor. We’ll go ahead and setup the Linkage on the New Symbol window you have open. If you don’t have a linkage section you will need to click the button in the bottom right that says “Advanced”. Now Export for Actionscript and set the class to “com.asgamer.cursor.Cursor.” Good now click okay and create your MovieClip.

The thing you need to keep in mind with your cursor is your Registration Point.  The Registration Point is the black plus sign (+) with the white border that represents the (0,0) coordinates of our MovieClip. You’ll likely want your Registration Point to be the same as the tip of the arrow on your OS’s mouse cursor.  My mouse cursor is going to be an arrow, original I know.  What I am going to design is a red arrow that points towards the right. The reason I am pointing it right is because later in the tutorial I’m going to add extra code that will make our arrow rotate towards the direction we are moving it. If you want to follow along the whole way through this tutorial you should make an arrow as well that points right.  Here’s my arrow:

1600% Zoom of my Cursor, actual size is around 25x16 pixels. Notice the Registration Point is at the tip of the arrow, it will directly correlate with your actual mouse cursor's location. The arrow points right so we can write rotational code on it later

1600% Zoom of my Cursor, actual size is around 25×16 pixels. Notice the Registration Point is at the tip of the arrow, it will directly correlate with your actual mouse cursor's location. The arrow points right so we can write rotational code on it later.

Step 2: Setting Up Our Document Class

Okay guys, if you’ve been around AsGamer you should know how to do this, if not you should read this article, but here’s the basics. Deselect all artwork and in the Properties window you should get a box called Document Class. Just write into it “com.asgamer.cursor.Main” without the quotes. Now we need to create our Main class. If you haven’t saved your fla yet, save it somewhere as cursorTest.fla.  Now inside the same folder as your cursorTest.fla create a folder structure of “com/asgamer/cursor/”.  Inside the cursor folder create a new file called Main.as.  And add this code into it:

package com.asgamer.cursor
{
	import flash.display.Sprite;
 
	public class Main extends Sprite
	{
 
		private var cursor:Cursor;
 
		public function Main() : void
		{
			cursor = new Cursor(stage);
			stage.addChild(cursor);
		}
 
	}
 
}

Good. The code is super simple. All we are doing is creating an instance of our Cursor class(which we will write next) and adding it to the stage. The only thing you need to keep in mind is our Cursor will always need the stage passed into it at construction.  If you are having problems understanding any of the above code, you DEFINITELY need to read this article, as it explains adding Library Objects to the stage via ActionScript.

Step 3: The code behind our new Cursor

So you’re ready go make our different cursor display instead of the regular mouse cursor. Remember when earlier we set up the Linkage for our unique cursor? Let’s put that to use, create a Cursor.as file in our “com/asgamer/cursor/” directory.  Add this code to it and I’ll break down exactly what it means in a second:

package com.asgamer.cursor
{
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.ui.Mouse;
 
	public class Cursor extends MovieClip
	{
 
		private var stageRef:Stage;
 
		public function Cursor(stageRef:Stage)
		{
			Mouse.hide(); //make the mouse disappear
			mouseEnabled = false; //don't let our cursor block anything
			this.stageRef = stageRef;
			x = stageRef.mouseX;
			y = stageRef.mouseY;
 
			stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true);
		}
 
		private function updateMouse(e:MouseEvent) : void
		{
			x = stageRef.mouseX;
			y = stageRef.mouseY;
 
			e.updateAfterEvent();
		}
 
	}
 
}

Alright… source code explaination time.

  • first of all, imports. Just the classes we need to use the functionality we want. Plain and simple.
  • stageRef:Stage, it’s our reference to the stage… a class variable and we pass it into our cursor in the constructor.
  • Mouse.hide(); the other side of Mouse.show(), it allows us to make the mouse disappear, so we can add our cursor.
  • mouseEnabled = false; Here’s the deal… Our mouse, while now not visible (because of Mouse.hide()), is still there. It’s like a MovieClip with an alpha of 0. And our Cursor well it’s just a MovieClip that is following our mouse. So it BLOCKS EVERYTHING. Flash won’t know when we are over a button because our Cursor movieClip is in the way. To fix this, simple, mouseEnabled = false. That means our new Cursor doesn’t react to the mouse.
  • x = stageRef.mouseX; get the x coordinates of the mouse from the stage and set it to our Cursor’s position.  The same for the y.
  • stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true); We use event listeners all the time. It’s a staple of Actionscript 3.0 (as3). So what’s this one? Simple when we move our mouse anywhere the updateMouse function will be called.
  • Our updateMouse function just accepts our MouseEvent and sets the x and y position based on the mouse position. But it does one more thing…
  • e.updateAfterEvent(); In as2, you used to just call updateAfterEvent for this… not anymore. We take the MouseEvent Object that is thrown into our updateMouse function and we say once it’s complete to render it. Here’s what Adobe says it does: “Instructs Flash Player or Adobe AIR to render after processing of this event completes, if the display list has been modified.” Anyway, let me explain it this way… This line of code makes sure the mouse moves extremely smooth and doesn’t jitter.

Here’s the example:

Alright that’s it!!!, you could wrap this code up now and use it over and over whenever you need it. All you’d have to do is create a new cursor and make sure it’s linkage is com.asgamer.cursor.Cursor.  As long as that is set correctly and you create an instance of cursor somewhere in your code, you are good to go. Sweet huh? A completely object oriented custom cursor. We did it with OOP, now reuse it!

But… let’s take it a step further… you know for the fun of it.

Step 4: Making our Cursor Rotate with the Direction of the Mouse

Okay, so we’ve made things rotate based on direction many times before at AsGamer. I mean we’re all about flash games, using geometry and trigonometry is what we do. So let’s do it one more time to make our mouse rotate with the direction it is moving. To do this we’re going to need to keep up with the previous position of the mouse at each frame, that way we can calculate the difference in position and find the angle our mouse is moving.

So we’ll create a class variable that is a point. If you’ve never used Flash’s Point class, it’s great. You can use it to find the global position of a local movieclip and visa versa. But simply put, we can keep track of an x and y value with one variable instead of two. So let’s create a class variable called p and make it be a point.  So you’re not confused, I’ll go ahead a show you the new Cursor that uses the point and the trig.  I’ll explain the changes after the code:

package com.asgamer.cursor
{
	import flash.display.MovieClip;
	import flash.display.Stage;
	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;
			this.stageRef = stageRef;
			x = stageRef.mouseX;
			y = stageRef.mouseY;
 
			stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true);
		}
 
		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();
		}
 
	}
 
}

Alright… breakdown:

  • private var p:Point = new Point(); We created our point. Simple now… we’ll use it in a few seconds.
  • The next updates to our code are all in the updateMouse function. I like to go line by line through the code, but you’ll want to notice first that we set p.x =x and p.y = y near the end of the function. This is because points have a x and y variable associated with them.  Likewise, we assign them at the end of the function so the next time updateMouse is called p.x and p.y will be at the previous position of the mouse.  As long as we wait till the end of the function to change them, we can use p.x and p.y as the previous mouse position throughout the main content of the function.
  • var newRotation:Number = Math.atan2(y – p.y, x – p.x) * 180 / Math.PI; There’s really two things going on here at once. Don’t worry it’s all really simple.
    1. First of all Math.atan2 is a Flash static function that will let us get the angle a line is pointing. We just substract our old mouse y position from our new one and do the same with x and pass that into Math.atan2 and it returns our angle.If you want a truly accurate description of what Math.atan2 does you can read it here.
    2. Here’s the thing with Math.atan2, it returns a radian. Our MovieClip’s rotation is in degrees. So we need to convert our radians to degrees. Simple, just multiple the radian by 180 and divide it by PI(3.14159265358…). Done… our newRotation is the direction that our mouse is moving in degrees.
  • if (newRotation – rotation > 180) newRotation -= 360;. Why are we doing this??? Well, flash doesn’t believe in setting our rotation to anything above 360.  For example… if I type rotation = 377 then I try to trace the rotation… I’ll get 17. Which is the exact same angle as 377.  Cool, but problem:  If I want my rotation to ease from 350 to 377… that’s only a difference of 27… Yet if Flash changes it to 17 then we get a difference of 333 in the opposite direction. This will cause our Cursor to jitter badly! So let’s fix it by adjusting our newRotation.
  • rotation -= (rotation – newRotation) / 10; Basic easing concept. If you need to understand how this works, I’ve wrote an article that talks about it here.

Wanna see it in action?

Need this source code? Here you go… All 7 Massive KB of it.

Creating an AS3 Object Oriented Custom Cursor Zip Archive

Step 5: BulletProofing your Custom Cursor

There’s a few things we still need to do to make this cursor more effective.  Attila K. pointed out some issues so I wrote tutorial 2 on the subject. Click here the second part of this tutorial.

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.




10 Comments


  1. Attila K.

    Thanks for the tutorial, very helpful.
    However I noticed some things that could be added to improve this. Use the MOUSE_LEAVE event to remove the child when you leave the stage, and hide the mouse when you right click, and if a movieclip is added to the stage it will cover up the mouse.
    Just some suggestions, great tutorial btw!


  2. Par

    Good points. Things I didn’t think about :D I’ll update it


  3. da best. Keep it going! Thank you


  4. Alf

    Have you considered using the function startdrag() instead of creating a MOUSE_MOVE event listener? I would like to hear your opinion about this (if its better or worse). Thanks for all your great tutorials =)


  5. WJ

    And how can I change the displayed custom cursor in several states, like Mouse_Down and Mouse_Over?


  6. Where the author says: and set the class to “com.asgamer.cursor.Cursor.”

    Do not add the final period. I was getting a : Error #1065: Variable is not defined, until I removed it.


  7. Very good tutorials, Thanks. But I am looking for a code to change the cursor when the Mouse is down.


  8. Louis

    Hello,

    The scripts themselves work on their own, but when I tried to apply this to a current project, it caused the frames to jump all over the place and I get a massive amount of errors that say the same thing.

    1046: Type was not found or was not a compile-time constant: MouseEvent.

    How do I fix this?


  9. Martina V.

    Hi! Custom cursors are great, but when hovering over a button they don’t change like a normal cursor, so the visual cue that there is something to click is gone. I was wondering if you know a way to have a custom cursor and then make it change when hovering over a button?


  10. i am new to OOP and using all these classes and shiz, I usalluy just hack away until something works but this is great, I am understanding so much more. so thank you for teaching.But I have a question, about getting touch gestures to control the object instead of keystrokes would I have to create a class to handle touch and drag events’ similar to the KeyObject class and implement it that way? And I could then create another class to handle pinch to zoom’? I wish I could just pop it in the ship class but that doesn’t work (#1046 on the 2 functions for start & stop dragging)



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