Restore dragged movieclips to their original position as they are dragged outside the stage in action script 3 - actionscript-3

I am creating a drag and drop the game for kids and I realized that when the kid drags a movie clip by mistake outside the stage the movie clip hangs where it is dragged onto and doesn't return back to its original position or it overlaps over other movie clips.
Thanks in advance
the code I am basically using is:
* square_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp2);
square_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt2);
function pickUp2(event: MouseEvent): void {
square_mc.startDrag(true);
event.target.parent.addChild(event.target);
startX = event.currentTarget.x;
startY = event.currentTarget.y;
}
function dropIt2(event: MouseEvent): void {
square_mc.stopDrag();
var myTargetName:String = "target" + event.target.name;
var myTarget:DisplayObject = getChildByName(myTargetName);
if (event.target.dropTarget != null && event.target.dropTarget.parent ==
myTarget){
event.target.removeEventListener(MouseEvent.MOUSE_DOWN, pickUp2);
event.target.removeEventListener(MouseEvent.MOUSE_UP, dropIt2);
event.target.buttonMode = false;
event.target.x = myTarget.x;
event.target.y = myTarget.y
} else {
event.target.x = startX;
event.target.y = startY;
}
}*

What you need to do is to preserve the initial position of the clip somewhere and then use it.
Basic algorithm I can think of can look as follows: 1 - player starts dragging a clip, init position is saved 2 - player releases the clip.
Two outcomes are possible: (a): the clip is on the right position or (b): it is misplaced. In case (b) you just need to assign initial coordinates back to the clip.
Very simple example:
private const initialCoords: Dictionary = new Dictionary();
private function saveInitialCoords(clip: DisplayObject): void {
initialCoords[clip] = new Point(clip.x, clip.y);
}
private funciton retreiveInitialCoords(clip: DisplayObject): Point {
return initialCoords[clip]; // it would return null if there is no coords
}
UPD: As it was pointed by #kaarto my answer might be irrelevant. If the issue is to keep the dragging movieclip
within some bounds I usually use something like this:
private var currentTarget: DisplayObject; // clip we're dragging currently
private var areaBounds: Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight); // you might want to ensure stage is not null.
private function startDrag(e: MouseEvent): void {
// I'll drop all checks here. Normally you want to ensure that currentTarget is null or return it to initial position otherwise
currentTarget = e.currentTarget as DisplayObject;
saveInitialCoords(currentTarget);
addEventListener(MouseEvent.MOUSE_MOVE, checkAreaBounds);
}
private funciton stopDrag(e: MouseEvent): void {
// some checks were dropped.
if (clipIsOnDesiredPlace(currentTarget)) {
// do something
} else {
const initialCoords: Point = retreiveInitialCoords(currentTarget);
currentTarget.x = initialCoords.x;
currentTarget.y = initialCoords.y;
}
currentTarget = null;
removeEventListener(MouseEvent.MOUSE_MOVE, checkAreaBounds);
}
private funciton checkAreaBounds(e: MouseEvent): void {
// you might need to convert your coords localToGlobal depending on your hierarchy
// this function gets called constantly while mouse is moving. So your clip won't leave areaBounds
var newX: Number = e.stageX;
var newY: Number = e.stageY;
if (currentTarget) {
if (newX < areaBounds.x) newX = areaBounds.x;
if (newY < areaBounds.y) newY = areaBounds.y;
if (newX + currentTarget.width > areaBounds.x + areaBounds.width) newX = areaBounds.x + areaBounds.width - currentTarget.width;
if (newY + currentTarget.height > areaBounds.y + areaBounds.heght) newY = areaBounds.y + areaBounds.height - currentTarget.height;
currentTarget.x = newX;
currentTarget.y = newY;
}
}
... somewhere ...
// for each clip you're going to interact with:
for each (var c: DisplayObject in myDraggableClips) {
c.addEventListener(MouseEvent.MOUSE_DOWN, startDrag);
c.addEventListener(MouseEvent.MOUSE_UP, stopDrag);
}
Another option (if you don't want to limit the area with some bounds) is to use MouseEvent.RELEASE_OUTSIDE event and return a clip to it's initial position once it gets released:
stage.addEventListener(MouseEvent.RELEASE_OUTSIDE, onMouseReleaseOutside);
private function onMouseReleaseOutside(e:MouseEvent):void {
// return clip to it's position.
}
More info you can find in documentation: https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/MouseEvent.html#RELEASE_OUTSIDE

Related

How to prevent a drag action to affect the childrens of a MovieClip

My problem is: I have a MovieClip (obj) that users can drag to both sides to navigate, the code I use for this:
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import flash.geom.Rectangle;
var destination: Point = new Point();
var dragging: Boolean = false;
var speed: Number = 10;
var offset: Point = new Point();
var bounds: Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
obj.addEventListener(MouseEvent.MOUSE_DOWN, startdrag);
stage.addEventListener(MouseEvent.MOUSE_UP, stopdrag);
obj.addEventListener(Event.ENTER_FRAME, followmouse);
function startdrag(e: MouseEvent): void {
offset.x = obj.mouseX * obj.scaleX;
dragging = true;
}
function stopdrag(e: MouseEvent): void {
dragging = false;
}
function followmouse(e: Event): void {
if (obj) {
if (dragging) {
destination.x = mouseX;
}
obj.x -= (obj.x - (destination.x - offset.x)) / speed;
if (obj.x > bounds.left) {
obj.x = bounds.left;
}
if (obj.x < -obj.width + bounds.right) {
obj.x = -obj.width + bounds.right;
}
}
}
So far so good, the problem comes up when I put some clickable elements inside that MovieClip (obj), here are the code for the clickable elements:
objA.addEventListener(MouseEvent.CLICK, objATrigger);
objB.addEventListener(MouseEvent.CLICK, objBTrigger);
objC.addEventListener(MouseEvent.CLICK, objCTrigger);
function objATrigger(event: MouseEvent): void {
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
function objBTrigger(event: MouseEvent): void {
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
function objCTrigger(event: MouseEvent): void {
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
The problem is: When I drag the MovieClip (obj) there is a conflict with the event, when release the mouse after the drag, the event Click of MovieClips inside the MovieClip (obj) is fired, how can I fix this? They should only be triggered when there is no drag action.
This is how I handle dragging a parent that has clickable children. The benefit of this method, is that you don't need to do anything to the children (no extra conditions in their click handlers etc), the click event simply doesn't reach them.
You can also hopefully gleam some efficiency tips from the code/comments below:
var wasDragged:Boolean = false;
var dragThreshold:Point = new Point(10,10);
// ^ how many pixels does it need to move before it's considered a drag
//this is good especially on touchscreens as it's easy to accidentally drag the item a couple pixels when clicking.
var dragStartPos:Point = new Point(); //to store drag origin point to calculate whether a drag occured
var dragOffset:Point = new Point(); //to track the gap between the mouse down point and object's top left corner
obj.addEventListener(MouseEvent.MOUSE_DOWN, startdrag);
obj.addEventListener(MouseEvent.CLICK, dragClick, true); //listen on the capture phase of the event.
//the only reason we listen for click on the draggable object, is to cancel the click event so it's children don't get it
function dragClick(e:Event):void {
//if we deemed it a drag, stop the click event from reaching any children of obj
if(wasDragged) e.stopImmediatePropagation();
}
function startdrag(e: MouseEvent): void {
//reset all dragging vars
wasDragged = false;
dragStartPos.x = obj.x;
dragStartPos.y = obj.y;
//set the offset so the object doesn't jump when first clicked
dragOffset.x = stage.mouseX - obj.x;
dragOffset.y = stage.mouseY - obj.y;
//only add the mouse up listener AFTER the mouse down
stage.addEventListener(MouseEvent.MOUSE_UP, stopdrag);
//mouse_move is more efficient that enter_frame, and only listen for it when dragging
stage.addEventListener(MouseEvent.MOUSE_MOVE, followmouse);
}
function stopdrag(e:MouseEvent = null): void {
//remove the dragging specific listeners
stage.removeEventListener(MouseEvent.MOUSE_UP, stopdrag);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, followmouse);
}
function followmouse(e:MouseEvent): void {
if (obj) {
//do what you need to move the object
obj.x = stage.mouseX - dragOffset.x;
obj.y = stage.mouseY - dragOffset.y;
//check if the obj moved far enough from the original position to be considered a drag
if(!wasDragged
&& (Math.abs(obj.x - dragStartPos.x) > dragThreshold.x
|| Math.abs(obj.y - dragStartPos.y) > dragThreshold.y)
){
wasDragged = true;
}
}
}
I don`t know if this is the best approach, but it was possible to check using the code below:
stage.addEventListener(MouseEvent.MOUSE_DOWN, setmousepos);
brose_trigger.addEventListener(MouseEvent.MOUSE_UP, broseTrigger);
denso_trigger.addEventListener(MouseEvent.MOUSE_UP, densoTrigger);
honda_trigger.addEventListener(MouseEvent.MOUSE_UP, hondaTrigger);
var mousePos: Point = new Point();
function setmousepos(e:MouseEvent): void {
mousePos.x = mouseX;
}
function broseTrigger(e:MouseEvent): void {
if(mousePos.x == mouseX){
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
}
function densoTrigger(event:MouseEvent): void {
if(mousePos.x == mouseX){
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
}
function hondaTrigger(event:MouseEvent): void {
if(mousePos.x == mouseX){
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
}
When MOUSE_DOWN event is triggered, I store the mouse.x position in a variable, after that in the MOUSE_UP event, I compare the stored position with the actual position, if equals, TÃDÃ!
Do add condition in objATrigger function to check if dragging is false
function objATrigger(event: MouseEvent): void {
if(!MovieClip(root).dragging){
MovieClip(this.parent).gotoAndPlay(1, "Main");
}
}

Error: #1009: Type Error (Line #114)

I'm sort of a noob to flash, but I am programming a game right now, and I am trying to make my character move but i am getting error #1009 Here is my code in my "GameState".
Basically it errors out on any Keypress, I have my character named player (Player in the library) and it has another movie clip within it named WalkDown (I gave it an instance name of walkDown on the timeline) I am not really sure whats going on. Specifically it errors out on the line where its calling the frame name. Any help would be appreciated!
package {
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.geom.Point;
public class GameState extends MovieClip {
private var player:MovieClip;
private var walking:Boolean = false;
// is the character shooting
//private var shooting:Boolean = false;
// wlaking speed
private var walkingSpeed:Number = 5;
private var xVal:Number = 0;
private var yVal:Number = 0;
public function GameState() {
// constructor code
player = new Player();
addChild(player);
player.x = 300;
player.y = 300;
player.gotoAndStop("stance");
this.addEventListener(Event.ADDED_TO_STAGE, initialise);
}
private function initialise(e:Event){
// add a mouse down listener to the stage
//addEventListener(MouseEvent.MOUSE_DOWN, startFire);
// add a mouse up listener to the stage
//addEventListener(MouseEvent.MOUSE_UP, stopFire);
player.addEventListener(Event.ENTER_FRAME,motion);
stage.addEventListener(KeyboardEvent.KEY_UP,onKey);
// add a keyboard down listener
stage.addEventListener(KeyboardEvent.KEY_DOWN, offKey);
stage.focus = stage;
// Add keyboard events
}
private function motion(e:Event):void{
// if we are currently holding the mouse down
//if (shooting){
//FIRE
//fire();
//}
player.x += xVal;
player.y += yVal;
}
//private function startFire(m:MouseEvent){
//shooting = true;
//}
//private function stopFire(m:MouseEvent){
//shooting = false;
//}
private function onKey(evt:KeyboardEvent):void
{
trace("key code: "+evt.keyCode);
switch (evt.keyCode)
{
case Keyboard.W :
yVal = walkingSpeed;
if (! walking)
{
trace("walking up");
player.walkDown.gotoAndPlay("walking");
walking = true;
}
break;
case Keyboard.S :
yVal = - walkingSpeed;
if (! walking)
{
player.walkDown.gotoAndPlay("walking");
walking = true;
}
break;
case Keyboard.A :
xVal = walkingSpeed;
if (! walking)
{
player.walkDown.gotoAndPlay("walking");
walking = true;
}
break;
case Keyboard.D :
xVal = walkingSpeed;
if (! walking)
{
player.walkDown.gotoAndPlay("walking");
walking = true;
}
break;
}
}
private function offKey(evt:KeyboardEvent):void
{
switch (evt.keyCode)
{
case Keyboard.W :
//for now just reset velocity to zero
yVal = 0;
//also stop walk cycle etc.
player.gotoAndStop("stance");
//don't forget to update your Boolean
walking = false;
break;
case Keyboard.S :
//for now just reset velocity to zero
yVal = 0;
//also stop walk cycle etc.
player.gotoAndStop("stance");
//don't forget to update your Boolean
walking = false;
break;
case Keyboard.A :
//for now just reset velocity to zero
xVal = 0;
//also stop walk cycle etc.
player.gotoAndStop("stance");
//don't forget to update your Boolean
walking = false;
break;
case Keyboard.D :
//for now just reset velocity to zero
xVal = 0;
//also stop walk cycle etc.
player.gotoAndStop("stance");
//don't forget to update your Boolean
walking = false;
break;
}
}
// Players Motion
private function fire():void{
var b= new Bullet();
// set the position and rotation of the bullet
b.rotation = rotation;
b.x = x;
b.y = y;
// add bullets to list of bullets
MovieClip(player).bullets.push(b);
// add bullet to parent object
player.addChild(b);
// play firing animation
player.shooting.gotoAndPlay("fire");
}
}
}
You were saying the Error #1009 ( Cannot access a property or method of a null object reference ) arises when you do
player.walkDown.gotoAndPlay("walking");
If so, that is because you have to first go to the frame where the WalkDown MovieClip is in before you can access it.
If say your "stance" frame is in frame 1 and your WalkDown MovieClip is in frame 2. Your code in the onKey function should look like:
case Keyboard.W :
yVal = walkingSpeed;
if (! walking)
{
trace("walking up");
player.gotoAndStop(2); // player.walkDown is now accessible //
player.walkDown.gotoAndPlay("walking");
walking = true;
}
break;

HitTest for objects not yet on Stage

I need to add a MovieClip to stage, the limitation being that it should only be added to an empty area on the stage. The stage itself either contains complex shapes or is manipulable by the user i.e. he can drag/move objects to change the empty area. The hitTest and hitTestObject methods need DisplayObject already available on the stage. What is the right way to go - the only solution I can imagine is having added my object on the stage and then repeatedly doing hit tests?
[Imagine it to something like adding sprites in a video game - they must spawn in empty regions; if they pop out from inside of each other, then it'll look really odd.]
Well, when you create a new class, just turn it off with a variable and set the visibility to false, then loop until there is no hitTest.
A silly example:
public class someClass extends Sprite
{
private var objectsOnStage:Array;
public function someClass(objectsArray:Array) {
objectsOnStage = objectsArray;
visible = false;
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event){
removeEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(Event.ENTER_FRAME, SEARCH);
}
private function SEARCH(e:Event) {
var doesHit:Boolean = false;
x = Math.round(Math.random() * (550 - 0)) + 0;
y = Math.round(Math.random() * (400 - 0)) + 0;
for (var i:int = 0; i < objectsOnStage; i++) {
if (doesHit) break;
if (this.hitTestObject(objectsOnStage[i])) {
doesHit = true;
}
}
if (doesHit) return;
placedInit();
}
private function placedInit() {
visible = true;
removeEventListener(Event.ENTER_FRAME, SEARCH);
//now init the stuff you want.
}
}
You just check if bounding boxes of both clips overlaps. Like this:
import flash.geom.Rectangle;
import flash.display.MovieClip;
// create simple movie clips that has a rectangle shape inside
var sym1 : MovieClip = new Sym1();
var sym2 : MovieClip = new Sym2();
// get a rectanle of both clipt
var boundingBox1 : Rectangle = sym1.getBounds(this);
var boundingBox2 : Rectangle = sym2.getBounds(this);
// check if bounding boxes of both movie clips overlaps
// so it works like hitTestObject() method
trace( boundingBox1.intersects( boundingBox2) )
I know this post is super old, but in case it helps anybody --
If you need to do a hit test on a movieclip that isn't on the stage. A workaround is to rasterize it to a bitmap first.
var bitmapData:BitmapData = new BitmapData(mc.width, mc.height, true, 0x0000000);
bitmapData.draw(mc);
if (bitmapData.getPixel32(x, y) > 0) {
// Hit true.
}

startDrag - stop diagonal movement

Is there a way to have a MovieClip with startDrag, but to force only horizontal and vertical (i.e. not diagonal) movement?
Here is my solution. It tracks the mouseX and mouseY on click and compares it to last position. Finds out which direction the mouse is mainly moving then moves the object there. You may want to add some extra logic to lock the object to the nearest 10th unit or whatever unit size you want to form a snap grid for use in games or organized placement of the object.
Update: I went ahead and added a snapNearest function to help control the movement.
import flash.events.MouseEvent;
import flash.events.Event;
dragObj.addEventListener(MouseEvent.MOUSE_DOWN, dragIt);
var curX:Number = 0;
var curY:Number = 0;
var oldX:Number = 0;
var oldY:Number = 0;
var gridUnit:Number = 25;
function dragIt(e:MouseEvent):void
{
// set x,y on down
oldX = mouseX;
oldY = mouseY;
// add mouse up listener so you know when it is released
stage.addEventListener(MouseEvent.MOUSE_UP, dropIt);
stage.addEventListener(Event.ENTER_FRAME, moveIt);
trace("Start Drag")
}
function moveIt(e:Event):void
{
// figure out what the main drag direction is and move the object.
curX = mouseX;
curY = mouseY;
// figure out which is the larger number and subtract the smaller to get diff
var xDiff:Number = curX > oldX ? curX - oldX : oldX - curX;
var yDiff:Number = curY > oldY ? curY - oldY : oldY - curY;
if(xDiff > yDiff) {
dragObj.x = snapNearest(mouseX, gridUnit);
}else{
dragObj.y = snapNearest(mouseY, gridUnit);
}
oldX = mouseX;
oldY = mouseY;
}
function dropIt(e:MouseEvent):void
{
//remove mouse up event
stage.removeEventListener(MouseEvent.MOUSE_UP, dropIt);
stage.removeEventListener(Event.ENTER_FRAME, moveIt);
trace("Stop Drag")
}
// snap to grid
function snapNearest(n:Number, units:Number):Number
{
var num:Number = n/units ;
num = Math.round(num);
num *= units;
return num;
}
yes. there are a few options.
A. you can choose to use the startDrag() function and supply it's 2nd parameter with a bounds rectangle for your draggable object. something like;
dragSprite.startDrag(false, new Rectangle(0, 0, 20, stage.stageHeight));
B. you can set your draggable object to listen for mouse events, moving it according to the mouse movements. something like:
dragSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEventHandler);
function mouseDownEventHandler(evt:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
function mouseMoveEventHandler(evt:MouseEvent):void
{
//only move dragSprite horizontally
//dragSprite.y = evt.stageY;
dragSprite.x = evt.stageX;
}
function mouseUpEventHandler(evt:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
You could use a modifier key, for instance normal behavior would be horizontal & press down the shift key to move vertically.
function mouseMoveEventHandler(evt:MouseEvent):void
{
if(!evt.shiftKey)
dragSprite.x = evt.stageX;
else
dragSprite.y = evt.stageY;
}
You can only constrain to one axis or the other (using a constraint rectangle) But diagonal movement would be possible in the method you propose, unless you also define some other limits... for example a grid.

What is the most effective way to test for combined keyboard arrow direction in ActionScript 3.0?

I need to monitor the direction a user is indicating using the four directional arrow keys on a keyboard in ActionScript 3.0 and I want to know the most efficient and effective way to do this.
I've got several ideas of how to do it, and I'm not sure which would be best. I've found that when tracking Keyboard.KEY_DOWN events, the event repeats as long as the key is down, so the event function is repeated as well. This broke the method I had originally chosen to use, and the methods I've been able to think of require a lot of comparison operators.
The best way I've been able to think of would be to use bitwise operators on a uint variable. Here's what I'm thinking
var _direction:uint = 0x0; // The Current Direction
That's the current direction variable. In the Keyboard.KEY_DOWN event handler I'll have it check what key is down, and use a bitwise AND operation to see if it's already toggled on, and if it's not, I'll add it in using basic addition. So, up would be 0x1 and down would be 0x2 and both up and down would be 0x3, for example. It would look something like this:
private function keyDownHandler(e:KeyboardEvent):void
{
switch(e.keyCode)
{
case Keyboard.UP:
if(!(_direction & 0x1)) _direction += 0x1;
break;
case Keyboard.DOWN:
if(!(_direction & 0x2)) _direction += 0x2;
break;
// And So On...
}
}
The keyUpHandler wouldn't need the if operation since it only triggers once when the key goes up, instead of repeating. I'll be able to test the current direction by using a switch statement labeled with numbers from 0 to 15 for the sixteen possible combinations. That should work, but it doesn't seem terribly elegant to me, given all of the if statements in the repeating keyDown event handler, and the huge switch.
private function checkDirection():void
{
switch(_direction)
{
case 0:
// Center
break;
case 1:
// Up
break;
case 2:
// Down
break;
case 3:
// Up and Down
break;
case 4:
// Left
break;
// And So On...
}
}
Is there a better way to do this?
You can keep track of whether each key is down or not by listening for all KEY_DOWN and KEY_UP events, and storing each key state in an array. I wrote a class a while ago to do just that (included at the end of my answer).
Then you are no longer tied to the event model to know if a certain key is down or not; you can periodically check every frame (or every timer interval). So you could have a function like:
function enterFrameCallback(e:Event):void
{
var speed:Number = 1.0; // net pixels per frame movement
thing.x += (
-(int)Input.isKeyDown(Keyboard.LEFT)
+(int)Input.isKeyDown(Keyboard.RIGHT)
) * speed;
thing.y += (
-(int)Input.isKeyDown(Keyboard.UP)
+(int)Input.isKeyDown(Keyboard.DOWN)
) * speed;
}
which would take into account all possible combinations of arrow key presses. If you want the net displacement to be constant (e.g. when going right and down at same time, the object moves X pixels diagonally, as opposed to X pixels in both horizontal and vertical directions), the code becomes:
function enterFrameCallback(e:Event):void
{
var speed:Number = 1.0; // net pixels per frame movement
var displacement:Point = new Point();
displacement.x = (
-(int)Input.isKeyDown(Keyboard.LEFT)
+(int)Input.isKeyDown(Keyboard.RIGHT)
);
displacement.y = (
-(int)Input.isKeyDown(Keyboard.UP)
+(int)Input.isKeyDown(Keyboard.DOWN)
);
displacement.normalize(speed);
thing.x += displacement.x;
thing.y += displacement.y;
}
Here is the Input class I wrote (don't forget to call init from the document class). Note that it also keeps track of mouse stuff; you can delete that if you don't need it:
/*******************************************************************************
* DESCRIPTION: Defines a simple input class that allows the programmer to
* determine at any instant whether a specific key is down or not,
* or if the mouse button is down or not (and where the cursor
* is respective to a certain DisplayObject).
* USAGE: Call init once before using any other methods, and pass a reference to
* the stage. Use the public methods commented below to query input states.
*******************************************************************************/
package
{
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.display.Stage;
import flash.geom.Point;
import flash.display.DisplayObject;
public class Input
{
private static var keyState:Array = new Array();
private static var _mouseDown:Boolean = false;
private static var mouseLoc:Point = new Point();
private static var mouseDownLoc:Point = new Point();
// Call before any other functions in this class:
public static function init(stage:Stage):void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 10);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp, false, 10);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 10);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp, false, 10);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false, 10);
}
// Call to query whether a certain keyboard key is down.
// For a non-printable key: Input.isKeyDown(Keyboard.KEY)
// For a letter (case insensitive): Input.isKeyDown('A')
public static function isKeyDown(key:*):Boolean
{
if (typeof key == "string") {
key = key.toUpperCase().charCodeAt(0);
}
return keyState[key];
}
// Property that is true if the mouse is down, false otherwise:
public static function get mouseDown():Boolean
{
return _mouseDown;
}
// Gets the current coordinates of the mouse with respect to a certain DisplayObject.
// Leaving out the DisplayObject paramter will return the mouse location with respect
// to the stage (global coordinates):
public static function getMouseLoc(respectiveTo:DisplayObject = null):Point
{
if (respectiveTo == null) {
return mouseLoc.clone();
}
return respectiveTo.globalToLocal(mouseLoc);
}
// Gets the coordinates where the mouse was when it was last down or up, with respect
// to a certain DisplayObject. Leaving out the DisplayObject paramter will return the
// location with respect to the stage (global coordinates):
public static function getMouseDownLoc(respectiveTo:DisplayObject = null):Point
{
if (respectiveTo == null) {
return mouseDownLoc.clone();
}
return respectiveTo.globalToLocal(mouseDownLoc);
}
// Resets the state of the keyboard and mouse:
public static function reset():void
{
for (var i:String in keyState) {
keyState[i] = false;
}
_mouseDown = false;
mouseLoc = new Point();
mouseDownLoc = new Point();
}
///// PRIVATE METHODS BEWLOW /////
private static function onMouseDown(e:MouseEvent):void
{
_mouseDown = true;
mouseDownLoc = new Point(e.stageX, e.stageY);
}
private static function onMouseUp(e:MouseEvent):void
{
_mouseDown = false;
mouseDownLoc = new Point(e.stageX, e.stageY);
}
private static function onMouseMove(e:MouseEvent):void
{
mouseLoc = new Point(e.stageX, e.stageY);
}
private static function onKeyDown(e:KeyboardEvent):void
{
keyState[e.keyCode] = true;
}
private static function onKeyUp(e:KeyboardEvent):void
{
keyState[e.keyCode] = false;
}
}
}