Ultrashock Tutorials > Flash5 > Flash5 'Custom Cursors'  
 
by: Davin Risk, Fluffco


Source File

PDF file

 
Flash5 'Custom Cursors'
 

 

With Flash5, you gain the ability to create what Macromedia refers to as 'custom cursors'. With a tiny amount of code, you can replace the system's arrows, hands, and I-bars with whatever you choose. What's behind all this is the simple Mouse object.

Mouse goes on. Mouse goes off.

What does the Mouse object have to do with custom cursors? Well everything really. You see, there really isn't anything in Flash5's new object-oriented language that refers to the 'cursor' let alone a 'custom cursor'. The Mouse object provides the dead simple ability to dynamically switch between two states -- hide and show. Simply put, you can turn system cursor off and on at will.

Why would you want to get rid of the cursor? Clearly that would cause all sorts of havoc as users blindly moused around your interface hoping for some feedback to lead them around your site. Okay, that's where the concept of a 'custom cursor' comes in.

The Lowrider of Cursors

Because Flash5 can hide the system cursor, you can make your own cursors, pointers, or what-have-yous take its place. Anything that's a movieclip instance can be your cursor with it own look, animations, behaviors and properties. And, best of all, it's really easy to do.

Since Flash5 now allows us to associate scripts with specific movieclip instances through ClipEvents, we can create a simple 'custom cursor' by placing the following in the instance's object actions:

onClipEvent (load) {
   Mouse.hide();
   startDrag (this);
}

As illustrated in the no-frills example below, a 'custom cursor' arrow and an excitingly clickable interactive object can interact together without a hitch.

"What's so simple about that?" you say. "What does that code have to do with my cool 'custom cursor'?" you demand.

The code above is telling Flash to do two things when the movieclip instance loads. First, the Mouse object is set to its Mouse.hide() state -- no more system cursor. Then, by using startDrag (this) Flash knows we want to automatically 'start dragging' (go figure) the movieclip instance associated with the script. Easy right?

Cursors! Foiled again!

Alright. So, that works pretty nicely; why should you keep on reading? Well, here's the thing, if you're only ever going to need a 'custom cursor' which can click on a few buttons and has only one state you're fine. But... I'm guessing that you might want to drag something with your new-fangled cursor or possibly have it react in a contextual manner like your system cursor does -- so you should probably stick around.

Let's try a little experiment by altering the interface from the previous example to include a standard draggable movieclip.

Urgh. That doesn't work at all does it? Now, someone out there might say, "maybe I can write some script that will stop dragging the first cursor while dragging the folder and then start dragging it again when I'm done?" Well sure, you could probably do that -- but don't! Macromedia actually refers to two methods for creating 'custom cursors' in the Flash5 manuals. The next method I'll call the 'alternate' method as Macromedia kind of hides it in the Actionscript reference volume (with a typo to really mess you up). I think you'll learn to call this method 'the better way' once you see what it does and how it's just as brief as the previous code.

Follow that mouse!

What wrong with the first method of creating a 'custom cursor' is a familiar problem from Flash 4 -- you can't drag two objects at once. Because we were telling our cursor movieclip to start dragging after we hid the mouse, it behaves just like any other dragged object when we try and click and drag the folder in the example.

In Flash4, one way around this sort of problem might have been to track the position of a hidden 'map' movieclip being dragged by the system cursor and to use scripting to dynamically position objects based on the 'map' position. But that's a lot of work to go through just for a fancy cursor in this case right? Don't worry. Again, Flash5's extended scripting language has you covered.

Replacing the previous ClipEvent script with the following does wonders:

onClipEvent (load) {
   Mouse.hide();
}

onClipEvent (mouseMove) {
   this._x = _root._xmouse;
   this._y = _root._ymouse;
updateAfterEvent();
}

See for yourself in this jury-rigged version of the last example.

"Hmmm... That does seem to work. How Come?"

What's different here is that we again take advantage of a feature new to Flash5 -- the ability to get the location of the system cursor at any time (even if you've hidden it) through the _xmouse and _ymouse properties as they relate to the _root.

So, in the code above, we again hide the mouse but then instead of dragging our movieclip we set its position to equal that of the _root._xmouse and _root._ymouse coordinates. Since we are no longer dragging the cursor clip, it's free to now point, click, and drag other objects as you see fit.

Multiple personality cursors

Now that we've got the basics of making the 'custom cursor' covered, the next question is "why did we change the cursor in the first place?" Good question. I'd be the last person to knock someone for making something that was based purely on its aesthetic merits, but depending on the project and its intended users, you might want to put your new cursor to work and thereby move your Flash interface a little closer to being called an application.

One of the best (and arguably worst) things about the system cursor it that it can respond to the things it points at or clicks on -- it's a contextual tool. Would using your favorite paint program be as natural if your cursor didn't change from a brush, to a lasso, to a marquee? You might say, "hell yeah, I turn as much of that off as I can." But those contextual changes are there for the people who grasp the interface better by having visual cues that differentiate one task from another. This is what you can do with your 'custom cursors' without too much hassle.

I'll give you another example first and then get into what it's doing.

Alright, I won't pretend that I've created anything ground breaking in terms of interface design with that example but you get the idea. Let's take a look at the scripting behind that example all associated with the cursor movieclip:

onClipEvent (load) {
   Mouse.hide();
   left = 80;
   right = 230;
   top = 70;
   bottom = 130;
}

The ClipEvent load first sets the Mouse object to 'hide' and then sets the four variables used as boundaries for dragged objects.

onClipEvent (mouseMove) {
   this._x = _root._xmouse;
   this._y = _root._ymouse;
   for (objects in _root) {
      if (_root[objects].hitTest(_x, _y, true)) {
         over = objects;
      }
   }
   if (over == "folder") {
      gotoAndStop(2);
   } else if (over.substr(0,2) == "cp") {
      gotoAndStop(3);
   } else if (over == "resetbutton") {
      gotoAndStop(4);
   } else {
      gotoAndStop(1);
   }
updateAfterEvent();
}

The mouseMove event gets the cursor going by mapping its position to the _x and _y of the mouse. Then, a for loop captures all objects located in the _root and applies a hitTest which if true sets the variable 'over = objects'. This allows for further conditional checks to be made on all appropriate objects instead of needing to specifically address each object. When the mouse is found to be coming in contact with the folder, color pots, or the reset button, the cursor movieclip is told to jump to the appropriate stopped frame with the corresponding cursor state.

onClipEvent (mouseDown) {
   if (over == "folder") {
      startDrag (_root.folder, false, left, top, right, bottom);
   } else if (over == "cpyellow") {
      myColor = new Color("_root.folder.corefolder");
      myColor.setRGB(0xffcc66);
   } else if (over == "cpblue") {
      myColor = new Color("_root.folder.corefolder");
      myColor.setRGB(0x99cccc);
   } else if (over == "cpgreen") {
      myColor = new Color("_root.folder.corefolder");
      myColor.setRGB(0x669933);
   } else if (over == "resetbutton") {
      myColor = new Color("_root.folder.corefolder");
      myColor.setRGB(0x999966);
   } else {
      gotoAndStop(1);
   }
}

onClipEvent (mouseUp) {
   stopDrag ();
}

The mouseDown and mouseUp events generally track the functionality of the test interface: folder dragging, setting new folder colors, and resetting the folder to its default color. Note that both the mouseMove and mouseDown events have final else conditions that tell the cursor movieclip to revert to the default arrow pointer if it's not over top of or clicking an object.

So that part was a bit more convoluted than previous examples but it still packs quite a bit of functionality into a fairly small amount of code. Next let's take the opposite route and look at an example that simply uses a 'custom cursor' for effect.

Designers make things pretty right?

No one says your use of 'custom cursors' needs to make any sense or serve a purpose - I think the example above proves that. Extend the 'cursor' metaphor to mean whatever you choose and play with the many applications this simple Flash5 advance provides.

 
©2001 Ultrashock.com Inc. - All rights reserved