I have a function that recognizes the ESC key being pressed. At which point, I want to stop dragging all items.
I"ve tried this.stopDrag() but it wont override the MOUSE_DOWN event.
It there a way to force it to "drop" the item being dragged?
Thanks
stage.addEventListener(KeyboardEvent.KEY_DOWN, escapeKeyDown);
function escapeKeyDown(event : KeyboardEvent):void {
if (event.keyCode == 27) {
trace("ESC");
this.stopDrag();
}
}
Make a global array of all your dragging DisplayObjects:
static var CURRENT_DRAGGING_ITEMS:Array = [];
Then whenever you call startDrag on anything, add it to the array.
function onMouseDown(event:MouseEvent):void
{
event.target.startDrag();
CURRENT_DRAGGING_ITEMS.push(event.target);
}
Then when you hit ESC, just loop through the array, calling stopDrag on all items, and removing them from the array.
function escapeKeyDown(event:KeyboardEvent):void
{
event.target.stopDrag();
var targetIndex:uint = CURRENT_DRAGGING_ITEMS.indexOf(event.target);
CURRENT_DRAGGING_ITEMS.splice(targetIndex, 1);
}
Make sure you also remove the dragging item from the array when you call stopDrag on it from anywhere else.
Related
I am looking to have a single function that removes listeners based on the switch/case button that was clicked. I have 2 MCs on the stage named "btn01" and "btn02" and have an array with matching names.
I want btnRemove() to be able to removeListener to btn01 if it was click, or if btn02 was clicked. How do I accomplish this? Thanks.
var buttons = new Array(btn01, btn02);
for (var a=0; a<buttons.length; a++){
buttons[a].buttonMode=true;
buttons[a].addEventListener(MouseEvent.CLICK,buttonClick);
}
function btnRemove() {
e.currentTarget.removeEventListener(MouseEvent.CLICK,buttonClick); //1120: Access of undefined property e
}
function buttonClick(e:Event):void{
switch(e.currentTarget.name){
case "btn01":
btnRemove(); //remove btn01 listener
break;
case "btn02":
btnRemove(); //remove btn02 listener
break;
}}
event.currentTarget is an object who calls listener so it would be your button, you can remove listener with a help of currentTarget, see next code:
btn01.addEventListener(MouseEvent.CLICK, OnClickBtn);
btn02.addEventListener(MouseEvent.CLICK, OnClickBtn);
function OnClickBtn(e:Event):void
{
if ( e.currentTarget.hasEventListener(MouseEvent.CLICK) )
{
e.currentTarget.removeEventListener(MouseEvent.CLICK, OnClickBtn);
}
}
I am doing a game for my computer science class and I am working on inventory, dragging an item into it. I do not know how to set the item as whatever the user clicked to drag.
At the moment I hard coded it to the item they are dragging, but in the future I want more items, so a variable set to the item they are dragging would make it work perfectly, but I don't know what it's called to do that.
Here is my code for inventory item dragging
function dragItem (event:MouseEvent):void
{
knife_loot.startDrag();
}
function dropItem (event:MouseEvent):void
{
knife_loot.stopDrag();
if ((knife_loot.hitTestObject(inv_game)) && (inv_game.visible == true))
{
trace("Item dropped in inventory")
trace("")
knife_loot.x = 80
knife_loot.y = 120
}
}
// end of dragging and dropping items
You can start with:
// List the items you want to drag.
var aList:Array = [knife_loot, spoon_loot, fork_loot];
// InteractiveObject is superclass for SimpleButton, Sprite and MovieClip.
// If you're sure what they all are then just use their class instead.
for each (var anItem:InteractiveObject in aList)
{
// Subscribe them all for dragging.
anItem.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
}
public var draggedItem:InteractiveObject;
function onDrag(e:MouseEvent):void
{
// Use e.currentTarget because original MouseEvent e.target
// could be something from deep inside of top object e.currentTarget.
draggedItem = e.currentTarget as InteractiveObject;
draggedItem.startDrag();
// Let's hook drop events.
stage.addEventListener(Event.MOUSE_LEAVE, onDrop);
stage.addEventListener(MouseEvent.MOUSE_UP, onDrop);
}
function onDrop(e:Event):void
{
// Unhook drop events.
stage.removeEventListener(Event.MOUSE_LEAVE, onDrop);
stage.removeEventListener(MouseEvent.MOUSE_UP, onDrop);
// Drop the item.
draggedItem.stopDrag();
if ((draggedItem.hitTestObject(inv_game)) && (inv_game.visible == true))
{
trace("Item", draggedItem.name, "was dropped to inventory.");
trace("");
draggedItem.x = 80;
draggedItem.y = 120;
}
// Forget the item.
draggedItem = null;
}
I am pretty new to as3 and tried searching around for an answer to my question but it seems nothing works. I have an xml loaded file where when the user clicks the correct option (of 4) they get a point scored. I'm trying to disable the button after it has been clicked once but this is not happening. Any help would be greatly appreciated.
Here is the section I have.
function setupButtons():void {
for (var obj:Object in buttons)
{
buttons[obj].addEventListener(MouseEvent.CLICK, checkAnswer);
}
buttons[obj].addEventListener(MouseEvent.MOUSE_UP,disableBtns);
}
function disableBtns(evt:MouseEvent):void {
for (var obj:Object in buttons)
evt.currentTarget.removeEventListener(MouseEvent.MOUSE_UP,disableBtns);
buttons[obj].enabled = false;
}
Here are some comments next to your original code to help explain what is likely happening:
function setupButtons():void {
//you're adding a click listener for every object in `buttons`
for (var obj:Object in buttons)
{
buttons[obj].addEventListener(MouseEvent.CLICK, checkAnswer);
}
//this next line seems out of place,
//it is NOT a part of your for loop above so it will only run once,
//The value of obj will be the LAST item in the for loop above
buttons[obj].addEventListener(MouseEvent.MOUSE_UP,disableBtns);
}
function disableBtns(evt:MouseEvent):void {
//you don't have curly braces on this next for loop line
//this means it's only going to run the line immediately following the loop as part of the loop.
for (var obj:Object in buttons)
//your attempting to remove the same listener over and over again (since this line is in a loop)
evt.currentTarget.removeEventListener(MouseEvent.MOUSE_UP,disableBtns);
//this next line is not part of the loop above.
//I imagine you only want to disable the button that was clicked (evt.currentTarget)
//This will only disable whatever the last value of obj was in the loop above
buttons[obj].enabled = false;
}
Now, here is a simple code refactoring that may help:
//first, just have one click listener for each button, forget the mouse up listener
function setupButtons():void {
for (var obj:Object in buttons){
buttons[obj].addEventListener(MouseEvent.CLICK, btnClick);
}
}
function btnClick(evt:MouseEvent):void {
//If buttons are of the SimpleButton class, you can just disable them
evt.currentTarget.enabled = false;
//OR, if the buttons are not of the SimpleButton class
evt.currentTarget.mouseChildren = false;
evt.currentTarget.mouseEnabled = false;
//OR, just remove the click listener
evt.currentTarget.removeEventListener(MouseEvent.CLICK, btnClick);
//run the checkAnswer function
checkAnswer(evt);
}
To disable all buttons when any 1 is clicked, you could do this:
function btnClick(evt:MouseEvent):void {
for (var obj:Object in buttons){
buttons[obj].removeEventListener(MouseEvent.CLICK, btnClick);
}
//run the checkAnswer function
checkAnswer(evt);
}
I have a dropdown menu that lets you select an item to be placed on the stage. The item is drag and droppable so I use event.currentTarget.startDrag(); to start the drag. Ok, everything works fine so far.
However, I also need to be able to rotate the item while it is being dragged (using the spacebar).
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
WHATGOESHERE?.gotoAndStop(rotate);
}
If I hardcode in an instance name of an object everything works fine - so the rotate function is working properly. The problem is, how can I reference event.currentTarget from the startDrag function while inside of the keyDown event?
My first thought was to set event.currentTarget to a variable and then calling the variable from within the keyDown event. However, targetHold = event.currentTarget; does not seem to record the instance name of the object being clicked...
public var targetHold:Object = new Object;
function ClickToDrag(event:MouseEvent):void {
event.currentTarget.startDrag();
targetHold = event.currentTarget;
trace ("targetHold " + targetHold);
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
targetHold.gotoAndStop(rotate); //does not work
}
}
function ReleaseToDrop(event:MouseEvent):void {
event.currentTarget.stopDrag();
}
As you click the object, it should have focus. If you register the listener for the KeyboardEvent on the object and not on the stage, it will be .currentTarget.
Here's an example of what I have in mind. Right after starting the drag, add the listener to the same object instead of the stage.
event.currentTarget.startDrag();
event.currentTarget.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
The proper way of doing this would be to define all the functionality in a class. Within a self contained class, you would not need any .currentTarget.
Here is how I would do this: (well, actually I'd follow #null's advice and encapsulate it in a sub class that all your dragable objects would extend, but that is a little broad so this will do)
public var targetHold:MovieClip; //don't make a new object, just create the empty var
public function YourConstructor(){
//your other constructor code
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown); //don't add the listener in the click function
}
private function clickToDrag(event:MouseEvent):void {
if(targetHold) ReleaseToDrop(null); //safeguard in case flash lost the focus during the mouse up
targetHold = event.currentTarget as MovieClip; //assign the current target. Might as well cast it as MovieClip and get code completion benefits
targetHold.startDrag();
trace ("targetHold " + targetHold);
}
private function myKeyDown(e:KeyboardEvent):void{
//check if target hold exists
if (targetHold != null && e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
targetHold.gotoAndStop(rotate);
}
}
private function ReleaseToDrop(event:MouseEvent):void {
if(targetHold) targetHold.stopDrag();
targetHold = null;
}
I am having trouble with the controls showing up for my transform tool. When I click my image I get the bounding box (to scale or rotate the image), but when I hover over the corner I do not get the cursor to transform it.
I am using these files:
TransformTool.as
TransformToolControl.as
TransformToolCursor.as
This is my code to call the transform tool:
var tool:TransformTool = new TransformTool();
addChild(tool);
And this later on to make the tool show up when the image is clicked and make the tool disappear when the stage is clicked:
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
My image selection for the bounding box to appear and disappear work perfectly. All my code works as expected.... except the actual controls on the bounding box. Please help!
Edit
The concept is the user can click an image from a menu and drag a new instance of that image to the stage. Then the user can click the new instance and should be able to rotate or scale it. Then they can click off the image to make the bounding box disappear. (They can add as many images to the stage that they want).
Here is some code that shows the basic click, create new instance, and drag process I have implemented.
//sb1 is the menu area that contains a group of images
//hill is one of the images the user can add to the stage
sb1.hill.addEventListener(MouseEvent.MOUSE_DOWN, createCopy);
var i:int=0;
var tmpImage:Sprite; //to store which image is being dragged currently
function createCopy(e:MouseEvent):void {
tmpImage = new Hill_mc();
tmpImage.name = "hillChild"+(i++); //increment every copy
container.addChild(tmpImage);
tmpImage.x = mouseX-470;
tmpImage.y = mouseY-270;
tmpImage.startDrag();
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); //add the mouse down to this new object
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //since the mouse is currently down, we need to listen for mouse up to tell the current copy to stop dragging
}
//this will be called when click a copy
function onDown(e:MouseEvent):void {
tmpImage = Sprite(e.currentTarget); //get a reference to the one that was clicked, so we know which object to stop dragging on the global mouse up.
container.addEventListener(MouseEvent.MOUSE_UP, onUp); //listen for the mouse up
tmpImage.startDrag();
}
function onUp(e:MouseEvent):void {
container.removeEventListener(MouseEvent.MOUSE_UP,onUp);
if (tmpImage.hitTestObject(thesubmenu1)) {
container.removeChild(tmpImage);
}
else {
tmpImage.stopDrag();
}
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
EDIT
I found this code and placed it in my TransformTool.as. I feel like it's so close and that there must be something called incorrectly because I get an error for a null object reference:
public function select(event:Event):void {
// the selected object will either be the
// event target or current target. The current
// target is checked first followed by target.
// The parent of the target must match the
// parent of the tool to be selected this way.
if (event.currentTarget != this
&& event.currentTarget.parent == parent){
setTarget(event.currentTarget as DisplayObject, event);
}else if (event.target != this
&& event.target.parent == parent){
setTarget(event.target as DisplayObject, event);
}
}
/**
* Helper selection handler for deselecting target objects. Set this
* handler as the listener for an event that would cause the
* deselection of a target object.
* It is not required that you use this event handler. It is only a
* helper function that can optionally be used to help ease
* development.
*/
public function deselect(event:Event):void {
if (_target != null && event.eventPhase == EventPhase.AT_TARGET){
setTarget(null, null);
}
}
You give too little information to determine what exactly is wrong.
However, there is a very good sample code that does exactly what you want here :
http://www.senocular.com/demo/TransformToolAS3/TransformTool.html
(Click on the link at the bottom of the image.)
I am sure that you are going to make it with this.
EDIT :
Try to use the built-in handlers. I would do something like this :
Instead of this :
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
Do this :
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, tool.select);
stage.addEventListener(MouseEvent.MOUSE_DOWN, tool.deselect);
EDIT :
If you do not have the handlers, I am not sure :) but I would recommand removing event listeners in each method as they might be interfering with each other.
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tmpImage.removeEventListener(MouseEvent.CLICK, select);
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_DOWN, deselect);
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}