May 30 2009

Custom Mouse Cursor for ActionScript 3

I threw together an FLA for someone to show them the different ways to handle custom mouse cursors in ActionScript 3 (AS3). I figured I should start posting more of my code for people since I use other people’s blogs all the time to figure out my own problems.

I’m mostly coding up stuff for Flash, Flex, Augmented Reality, iPhone, PHP, and CSS/HTML right now so hopefully I’ll have the time to post more snippets of things I’ve figured out trying to get all this technology to work.

This movie requires Flash Player 9

Direct Access to the X and Y Mouse Coordinates

The first method allows us a finer control over the movement of the cursor by directly changing the X and Y coordinates of the cursor movieclip with the X and Y coordinates of the mouse. If we wanted to restrict the movement to say, a specific Y coordinate (as we’ll see in the next example), we can do that just as easily by keeping the target_mc.y a constant when we update it’s X coordinate.

// Set up our listeners for each of our mouse actions
boundary_mc.addEventListener( MouseEvent.MOUSE_OVER,
onMouseOver );
boundary_mc.addEventListener( MouseEvent.MOUSE_OUT,
onMouseOut  );
// Ignores all sub movie clips and treats them as the parent
//      — otherwise events will be triggered on the child
//      movieclips and not our main clip
target_mc.mouseChildren   = false;
boundary_mc.mouseChildren = false;

// Ignore all the mouse events for the cursor
//      — otherwise MOUSE_OUT will trigger since mouse is
//      now on target_mc instead of boundary_mc
target_mc.mouseEnabled = false;

///////////////////////////////////////////////////////////////
// ON MOUSE OVER /////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When the mouse rolls over onto our red boundary, hide
//   mouse/show cursor
//
function onMouseOver( theEvent:MouseEvent ):void
{
// Swap the mouse for the cursor
Mouse.hide(); // hide mouse cursor
target_mc.visible = true;

// Add a listener to handle the moving of the mouse
// We add the listener here because otherwise the onMouseMove
//    would execute whenever the mouse moved, whether it was
//    on our boundary or not. Not a big deal, but better for
//    efficiency
boundary_mc.addEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion );

// Handle the movement now so we don’t have to wait for a
//   mouse movement to reposition the cursor
onMouseMotion(null);
}

///////////////////////////////////////////////////////////////
// ON MOUSE MOTION ///////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When the mouse moves, we also want to move our target to follow
//   the mouse
//
function onMouseMotion( theEvent:MouseEvent ):void
{
// Reposition our custom cursor
target_mc.y = stage.mouseY;
target_mc.x = stage.mouseX;
}

///////////////////////////////////////////////////////////////
// ON MOUSE OUT //////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When mouse goes outside our red boundary, show default mouse,
//      and hide our custom one
//
function onMouseOut( theEvent:MouseEvent ):void
{
// Swap the cursor for the mouse
Mouse.show();
target_mc.visible = false;

// Stop listening for mouse movement
boundary_mc.removeEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion );
}

The Drag and Drop Method

Our next method uses the drag function built into Flash. With this function you can drag a movieclip around the stage with the mouse automatically. This restricts some of our freedom, but gives us some very easy coding to control the mouse cursor to specific regions. In this case we simply restrict the motion of the cursor along a rectangle of 0 height (so it won’t move along the Y axis) and with a width as wide as our boundary box. This feature has its advantages, and I merely include it to demonstrate how to use it in the context of a custom mouse cursor.

// Set up our listeners for each of our mouse actions
boundary2_mc.addEventListener( MouseEvent.MOUSE_OVER,
onMouseOver2 );
boundary2_mc.addEventListener( MouseEvent.MOUSE_OUT,
onMouseOut2  );
// Ingores all sub movie clips and treats them as the parent
//      — otherwise events will be triggered on the child
//      movieclips and not our main clip
target_mc.mouseChildren    = false;
boundary2_mc.mouseChildren = false;

// Ignore all the mouse events for the cursor
//      — otherwise MOUSE_OUT will trigger since mouse is
//      now on target_mc instead of boundary_mc
target_mc.mouseEnabled = false;

// Calculate the the vertical center of our boundary
//   so that the cursor can move along that line
var verticalCenter_num = boundary2_mc.y + (boundary2_mc.height / 2);

///////////////////////////////////////////////////////////////
// ON MOUSE OVER 2 ///////////////////////////////////////////
/////////////////////////////////////////////////////////////
// Same as our previous one, but set for another boundary
//
function onMouseOver2( theEvent:MouseEvent ):void
{
// Swap the mouse for the cursor
Mouse.hide();
target_mc.visible = true;

// Add a listener to handle the moving of the mouse
// We add the listener here because otherwise the
//    onMouseMove would execute whenever the
//    mouse moved, whether it was on our boundary
//    or not. Not a big deal, but better for efficiency
boundary2_mc.addEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion2 );

// Handle the movement now so we don’t have to wait
// for a mouse movement to reposition the cursor
target_mc.y = verticalCenter_num;
target_mc.x = stage.mouseX;
}

///////////////////////////////////////////////////////////////
// ON MOUSE MOTION 2 /////////////////////////////////////////
/////////////////////////////////////////////////////////////
// Restricts the movement of our custom cursor along the X axis
//
function onMouseMotion2( theEvent:MouseEvent ):void
{
// Calculate the the vertical center of our boundary
//   so that the cursor can move along that line
var verticalCenter_num = boundary2_mc.y +
(boundary2_mc.height / 2);

// We use startDrag() here since it’s easier to restrict
//   the cursor’s boundaryusing a Rectangle object.
// boundary2_mc.x: Start from the x position of our
//   boundary verticalCenter_num: Start from the
//   vertical center as our y coordinate
// boundary2_mc.width: Allow the cursor to move
//   the length of the boundary’s width (starting from x)
// 0: Don’t allow the cursor to move up or down
target_mc.startDrag( true, new Rectangle(
boundary2_mc.x,
verticalCenter_num,
boundary2_mc.width,
0)
);
}

///////////////////////////////////////////////////////////////
// ON MOUSE OUT 2 ////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When mouse goes outside our gray boundary, show default mouse,
//   hide custom mouse and stop drag
//
function onMouseOut2( theEvent:MouseEvent ):void
{
// Swap the cursor for the mouse
Mouse.show();
target_mc.visible = false;

// Stop our drag
target_mc.stopDrag();

// Stop listening for mouse movement
boundary2_mc.removeEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion2 );
}

I hope the code is commented well enough for you to understand what’s going on. It should be fairly self explanatory, but if not, feel free to ask.

Sample Code

Below is the source code for the SWF used at the top of the post:

Download the Custom Cursors sample code.


May 23 2009

River Clean Up and the Roanoke Times

On Virginia Tech’s Reading Day (the day between classes and the beginning of finals), the Scuba Club at Virginia Tech (SCVT) performed a clean up on the New River near Radford, VA. We picked up several trash bags of garbage, mostly that were left behind from the fishermen that frequent there. There were plenty of fishing line, beer cans and other trash to keep us busy for a few hours and we do this every year.

As it had been raining for the past several days prior, the river level was two feet higher than normal, and big trees were being swept down river. The visibility was non-existent and we didn’t want to get caught or crushed by the trees coming down, so we didn’t get to go diving. However, there is still a ton more beer cans and other trash left by the fishermen at the bottom of the river that we have yet to get to.

While we were there, a photographer from the Roanoke Times took several photos of us as we worked. I had passed up picking up some trash that was in the water because I was wearing shoes but since I had all my scuba equipment with me, I put on my diving boots and jumped into the water to pick up the pieces I had missed.

The photographer caught me just as I was walking out of the river and they put me as their main image. Pretty cool. Check out the image below and download the PDF for the full size.

SCVT May 7, 2009 River Cleanup

SCVT May 7, 2009 River Cleanup


May 19 2009

Claytor Lake

After we dived at the river that morning I then headed to a day on the lake. The water was cold but I still had my wetsuit so I made good use of it there as well.

April Trip to Claytor Lake

It may look innocent, but it was freezing cold water
It may look innocent, but it was freezing cold water
 
Gabor up on the wake board
Gabor up on the wake board
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Gabor is in a bit of pain after one of his falls
Gabor is in a bit of pain after one of his falls
 
 
 
 
 
 
 
 
 
 

May 18 2009

New River Dive

We went diving in the early morning in the New River. It was early, it was dark under the water, the water was cold, but we had a lot of fun.

Scott, Kevin and I diving in the New River

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

May 17 2009

Photos of the Week (5/17)

I finally got around to posting some photos. I’ve been extremely busy these past four weeks and haven’t had time to process any new photos. Here are just some photos from the past couple of weeks.

Anton and Eva

Anton and Eva

Gabe and Fifi

Gabe and Fifi

Mana and a MacBook Pro

Mana and a MacBook Pro