Submit to StumbleUpon Share

Hello and welcome back to my blog!

Just a quick post for a change this time; I just discovered something pretty useful that I couldn't find anywhere on the net regarding drag and drop in Actionscript 3 so here goes...

Drag n drop

AS3 has some very useful functions for assisting in drag/drop: Sprite.startDrag() Sprite.stopDrag() and Sprite.dropTarget.

It also has some very handy functionality to stop given InteractiveObjects and DisplayObjectContainers from swollowing mouse events: InteractiveObject.mouseEnabled and DisplayObjectContainer.mouseChildren.

The problem comes when you want to use them together and your scene is quite a complex hierarchy:

Animal Army

In this example from the game I'm writing at the moment, I'm just implementing the chat system as you can see. But I discovered a problem using it with the pre-existing drag/drop code.

The GUI in the above image is all attached to the Stage (so it doesn't move as the camera moves), whereas the game level is a child of an object attached to the main MovieClip.

Obviously I didn't want the chat window to swallow mouse events that were destined for the level behind it, so I set mouseEnabled=false on the chat window (and importantly, the container above it which is the GUI root - this took me a good while to discover).

However, the drag drop system was still reporting dropTargets with mouseEnabled=false which meant my lovely inventory items (bottom right) didn't get dragged and placed in the level where I wanted (mouse cursor), because flash has decided that I'd like to drop things on to my chat window instead.

Rage ensued. Until I worked out this neat hack (and yes, it is a hack really but what can you do?).

/// <summary>
/// Love little hack which makes the drop target obey mouseEnabled
/// </summary>
public function GetDropTarget(topMostObject:DisplayObject):DisplayObject
{
	if ( topMostObject is InteractiveObject )
	{
		var tmo:InteractiveObject = topMostObject as InteractiveObject;
		if ( tmo.mouseEnabled==false )
		{
			// this is the magic
			tmo.visible = false;
			m_draggingIcon.startDrag(true);
			m_draggingIcon.stopDrag( );
 
			// replace with new drop target
			topMostObject = m_draggingIcon.dropTarget;
 
			// restore visibility
			tmo.visible = true;
		}
	}
 
	return topMostObject;
}

And you call it like this:

// must call this first otherwise dropTarget will be null
m_draggingIcon.stopDrag( );
var topMostObject:DisplayObject = GetDropTarget(m_draggingIcon.dropTarget);
...

So, what's going on here?

Well, basically I'm examining the dropTarget returned by flash to see if it has mouseEnabled=false set. If it does, I simply make said object invisible (which will hide it from the drag/drop system) and redo the drag/drop. The resulting dropTarget is then correct - as long as there isn't yet another dropTarget underneath with mouseEnabled=false of course, but fixing that is left as an excercise for the reader! 🙂

Until next time, have fun!

Cheers, Paul.

Submit to StumbleUpon Share