mouseEnabled vs dropTarget in AS3

Submit to StumbleUpon

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

About Paul Firth

A games industry veteran of ten years, seven of which spent at Sony Computer Entertainment Europe, he has had key technical roles on triple-A titles like the Bafta Award Winning Little Big Planet (PSP), 24: The Game (PS2), special effects work on Heavenly Sword (PS3), some in-show graphics on the BBC’s version of Robot Wars, the TV show, as well as a few more obscure projects.   Now joint CEO of Wildbunny, he is able to give himself hiccups simply by coughing.   1NobNQ88UoYePFi5QbibuRJP3TtLhh65Jp
This entry was posted in Animal Army, AS3, Technical. Bookmark the permalink.

12 Responses to mouseEnabled vs dropTarget in AS3

  1. jonathanasdf says:

    Just curious, but have you tried setting mouseChildren = false on the chat container (in addition to setting mouseEnabled = false). It could be possible that what the dropTarget is reporting is not your chat container, but rather the textfield inside said container, which it doesn’t seem to me as if you had set its mouseEnabled to false.

    In case you didn’t know this, you can use flash.utils.getQualifiedClassName to get the classname of an object instance, and that could help you narrow down just what exactly is being detected as a dropTarget.

    Cheers,
    jonathanasdf

  2. jonathanasdf says:

    Actually, nevermind. If that was the case, your hack wouldn’t work either because tmo.mouseEnabled would be true. I guess the behaviour makes sense because the definition of mouseEnabled is for mouse EVENTS, whereas the draganddrop system is not an event based system.

    An alternative not as hacky solution that I can think of is having your objects that should receive the drop events having a specific Boolean function (you can create an interface for that function if you want), and after stopDrag iterate through getObjectsUnderPoint (the returned order is depth sorted I believe), calling that function on each of the objects that have it (i.e. all the objects that implement the interface) until one returns true. Then, you can have a more elaborate draganddrop system. For example: you have things that can be dropped onto the ground, and things like potions that must be dragged onto the player for it to activate. With your hack, when you drag a non-potion onto the player, the returned topMostObject is the player, and then the player has to handle what happens when other random objects are dragged onto him – or alternatively the ground needs to handle using potions by checking the location of the player. With the less hacky setup, you can have the function in the player class just return false when it is not a potion type, and everything will just work.

    Actually, now that I think about it a bit more, the same thing could be achieved with your hack as well… Oh well, that’s quite a beautiful hack :)

    • Paul Firth says:

      Hi Jonathan,

      Actually, I already have the interface driven system that you mention for drag/drop; draggable items implement IDragSource, droppable surfaces implement IDropTarget, and each object in the world has a DroppedOnto() function :) Originally I did have the system using getObjectsUnderPoint() but there was some problem that I can’t exactly remember with it – perhaps the sort order wasn’t top-down…. Anyway, I had to revert to using the built in start/stopDrag() functions…

      You are probably right about the behaviour of mouseEnabled being separate to dropTarget, but since there is no way to control what the system returns for dropTarget, it seems a bit of an oversight :)

      Cheers, Paul.

  3. Stefano Ronchi says:

    Evening Paul,
    Mui thanks for the info -lol actually didn’t utilise any of your methods, but learning about the dropTarget method allowed me to progress in my own gaming endavours.

    Now I just need to figure out how to drop a sprite containing a bitmap onto an svg sprite…time to peruse your methods more and search about….thanks again, I’ve made a note to thank you in the eventual credits!

  4. Danc says:

    Hey, that game looks familiar. Seems to be coming together. :-)

    Just be sure you credit the art as required under the Creative Commons license. A small nod to the original Bunni would be polite since there appears to be at least some mild inspiration going on.

    take care,
    Danc.

  5. David says:

    Hey,
    I think your website is hacked.
    When I open your website in Mozilla browser, NoScript is popping out a message:

    “NoScript filtered a potential cross-site scripting(XSS) attempt from bla bla bla”.

    So, better check the issue.

  6. Hi,
    Thanks for sharing such grateful blog post. I really happy with reading your blog post. keep it up regular manner post.
    Angry Birds Flash

  7. vamapaull says:

    That’s a nice little hack!

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>

WP-SpamFree by Pole Position Marketing