ActionScript - Mouse Logic Problem - actionscript-3

dumb problem. embarrassed that i haven't found a solution. i'm tired.
a red square in on the stage. mouse-down + mouse-drag-up will move the red square downward (+y), while mouse-down + mouse-drag-down will move the red square upward (-y). this opposite motion is desired.
however, during a mouse drag the square must begin moving from it's current y position, regardless of how many mouse drags have changed it's initialized position. currently, the red square will always begin at stage 0, since my mouseDownOrigin variable is incorrect because my brain is asleep.
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Test extends Sprite
{
private var sp:Sprite = new Sprite();
private var mouseDownOrigin:int;
public function Test()
{
sp.graphics.beginFill(0xFF0000);
sp.graphics.drawRect(0, 0, 100, 100);
sp.x = sp.y = 200;
addChild(sp);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEventHandler);
}
private function mouseDownEventHandler(evt:MouseEvent):void
{
mouseDownOrigin = evt.stageY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
private function mouseMoveEventHandler(evt:MouseEvent):void
{
sp.y = mouseDownOrigin - evt.stageY;
}
private function mouseUpEventHandler(evt:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
}
}

You need to record the red square y position on the MouseUp event handler, practically recording the position you leave the square in.
private var currentPosition:int;
private function mouseUpEventHandler(evt:MouseEvent):void
{
currentPosition = sp.y;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
}
private function mouseMoveEventHandler(evt:MouseEvent):void
{
var n:int = event.stageY - mouseDownOrigin ;
sp.y = currentPosition - n;
}

Related

ActionScript 3, handling MOUSE_UP outside stage

I'm new to ActionScript 3.0. I tried a tutorial at http://www.senocular.com/flash/tutorials/as3withmxmlc/ . The demo program animates a ball and allows it to be dragged.
There was a problem with the program as written. When you drag the mouse outside the stage and release the mouse button, the ball wouldn't get the MOUSE_UP event. The code, therefore would never call stopDrag(). I searched stackoverflow for suggestions, and one suggestion was to listen to MOUSE_UP with the stage as well as the ball and add some logic for dealing with it.
I added some code to do this. I also refactored the program as written because it was pretty disorganized. Here's what I have now:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
public class BallToss extends Sprite {
private var ball:TossableBall;
// mouse position at last call to trackMouseMvt()
private var lastMousePos:Point = new Point();
// delta mouse movement from frame L-1 to frame L, where L is last frame
private var lastDeltaMouse:Point = new Point();
public function BallToss() {
var stageBounds:Rectangle = new Rectangle(0, 0, stage.stageWidth,
stage.stageHeight);
ball = new TossableBall(50, stageBounds);
ball.x = stageBounds.width/2;
ball.y = stageBounds.height/2;
addChild(ball);
ball.addEventListener(MouseEvent.MOUSE_DOWN, grabBall);
// however I order the next two calls to addEventListener(), it seems
// that the ball's MOUSE_UP gets handled before the stage's MOUSE_UP
stage.addEventListener(MouseEvent.MOUSE_UP, handleStageMouseUp);
ball.addEventListener(MouseEvent.MOUSE_UP, releaseBall);
// initialize 'lastMousePos' and set up 'trackMouseMvt' to be called on
// every frame
lastMousePos = new Point(mouseX, mouseY);
ball.addEventListener(Event.ENTER_FRAME, trackMouseMvt);
}
private function grabBall(evt:MouseEvent):void {
trace("in grabBall");
// set ball 'glideVector' to (0,0) so it will stop moving
ball.setGlideVector(new Point(0,0));
ball.startDrag();
}
private function releaseBall(evt:MouseEvent):void {
trace("in releaseBall");
ball.stopDrag();
// set up the ball to glide at the rate of 'lastDeltaMouse'
ball.setGlideVector(lastDeltaMouse);
}
private function trackMouseMvt(evt:Event):void {
var currMouse:Point = new Point(mouseX, mouseY);
lastDeltaMouse = currMouse.subtract(lastMousePos);
lastMousePos = currMouse;
}
private function handleStageMouseUp(evt:Event):void {
trace("in handleStageMouseUp");
ball.stopDrag();
var stageBounds:Rectangle = new Rectangle(0, 0, stage.stageWidth,
stage.stageHeight);
if (ball.x > stageBounds.right - 0.5)
ball.x = stageBounds.right - 0.5;
else if (ball.x < 0)
ball.x = 0;
if (ball.y > stageBounds.bottom - 0.5)
ball.y = stageBounds.bottom - 0.5;
else if (ball.y < 0)
ball.y = 0;
}
}
}
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
class TossableBall extends Sprite {
private var stageBounds:Rectangle;
private var glideVector:Point = new Point();
private var friction:Number = .95;
public function TossableBall(size:Number, stageBoundsIn:Rectangle) {
stageBounds = stageBoundsIn;
graphics.lineStyle(1);
graphics.beginFill(0xFF8000);
graphics.drawCircle(0, 0, size/2);
addEventListener(Event.ENTER_FRAME, glide);
}
public function setGlideVector(glideVectorIn:Point):void {
glideVector = glideVectorIn;
}
private function glide(evt:Event):void {
x += glideVector.x;
y += glideVector.y;
var shapeBounds:Rectangle = getBounds(parent);
if (shapeBounds.left < stageBounds.left) {
glideVector.x = Math.abs(glideVector.x);
} else if (shapeBounds.right > stageBounds.right) {
glideVector.x = -Math.abs(glideVector.x);
}
if (shapeBounds.top < stageBounds.top) {
glideVector.y = Math.abs(glideVector.y);
} else if (shapeBounds.bottom > stageBounds.bottom) {
glideVector.y = -Math.abs(glideVector.y);
}
glideVector.x *= friction;
glideVector.y *= friction;
}
}
I don't like this code very much. The problem comes down to not being able to detect all the cases in one place. I would like to write something like this:
if (..ball and stage both got MOUSE_UP..) {
..handle it..;
else if (..only stage got MOUSE_UP..) {
..handle it..;
}
This logic would let me write more foolproof, simpler case handling and clearer logic. As things stand, there is a lot of complex behavior that emerges from this way of organizing the code.
The event listening model doesn't seem to make this possible. The response to events must happen individually, or must it? Is there a way to detect events that are "in the queue"?
Alternatively, I could avoid using startDrag(), i.e. avoid making the ball Sprite draggable, and have only the stage listen to MOUSE_UP, then handle all the drag logic myself. That would also let me better handle questions like where I want the ball to be positioned when the user drags outside the stage. I wonder if that is better overall.
To track object being dragged this works good for me:
ball.addEventListener(MouseEvent.MOUSE_DOWN, onBallMouseDown)
var _stage:Stage;
private function onBallMouseDown(e:MouseEvent):void
{
_stage = stage;
stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp)
stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove)
ball.startDrag();
}
private function onStageMouseMove(e:MouseEvent):void
{
// track ball coordinates
}
private function onStageMouseUp(e:MouseEvent):void
{
ball.stopDrag();
_stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp)
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove)
}
What about that, after years of Flash programming only now have I discovered the joys of MouseEvent.RELEASE_OUTSIDE. No more ugly hacks needed.

AS3 mouse events not firing when mouseX = 0

I'm creating what should be a very simple, full screen drag and drop game in Flash Develop. It works fine except in one frustrating instance.
I add items to the stage, add MOUSE_DOWN listeners to them and start dragging when one hears that listener. I then add a MOUSE_UP listener to figure out when to stop the drag. Again, this works fine unless mouseX = 0. When the mouse is all the way to the left of the screen and I mouse up or mouse down no listener is fired. I also took it out of full screen mode and if the mouse is at or below 0 no mouse events will fire.
What in the world is going on?
private function itemSelectedHandler(e:MouseEvent):void
{
thisItem = GameItem(e.currentTarget);
thisItem.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, itemUnselectedHandler, false, 0, true);
}
private function itemUnselectedHandler(e:MouseEvent):void
{
stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_UP, itemUnselectedHandler);
thisItem.removeEventListener(MouseEvent.MOUSE_DOWN, itemSelectedHandler);
}
You are calling stopDrag on the class and not the dragged sprite. Try something like the following :
package
{
public class Main extends Sprite
{
private var _draggedSprite:Sprite = null;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
for (var i:int = 0; i < 10; i++)
{
createBox();
}
}
private function createBox():void
{
var sp:Sprite = new Sprite();
sp.graphics.beginFill(0xff0000, 1);
sp.graphics.drawRect(0, 0, 30, 30);
sp.graphics.endFill();
sp.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
sp.x = Math.random() * (stage.stageWidth - 30);
sp.y = Math.random() * (stage.stageHeight - 30);
addChild(sp);
}
private function onMouseDown(e:MouseEvent):void
{
var sp:Sprite = e.target as Sprite;
sp.startDrag();
_draggedSprite = sp;
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onMouseUp(e:MouseEvent):void
{
_draggedSprite.stopDrag();
_draggedSprite = null;
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
}
}
This worked for me when mouseX=0 in fullscreen mode.

Bullets will only fire to the right?

I'm making a flash game for my course at college, I have been following a tutorial but been spinning it off for my own sake. One wall I hit is that when I fire a bullet, it will only fire to the right, with a little movement up or down, I have been trying to fix it for a while but nothing is happening and nothing works.
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Wizard extends MovieClip {
private var dx:Number;
private var dy:Number;
private var Bulletspeed:int;
public var Angle:Number;
public var newAngle:Number;
var shotCoolDown:int;
const MAX_COOLDOWN=20;
public function Wizard() {
//constructor
//Shot cool down
shotCoolDown=MAX_COOLDOWN;
addEventListener(Event.ENTER_FRAME, update);
//set up an event listener for when the turret is added to stage
addEventListener(Event.ADDED_TO_STAGE, initialise);
}
function initialise(e:Event) {
//reduce shot cool down by one
shotCoolDown=shotCoolDown-1;
//add a click listener to the stage
stage.addEventListener(MouseEvent.CLICK, fire);
}
function fire(m:MouseEvent) {
//Able to shoot
if (shotCoolDown<=0) {
//resets cool down
shotCoolDown=MAX_COOLDOWN;
//spawn bullet
var B = new Bullet();
//set position and rotation of the bullet
B.rotation=rotation;
B.x=x;
B.y=y;
//add the bullet the the wizard
parent.addChild(B);
}
}
function update():void {
//Shot cool down
shotCoolDown--;
//Make the Wizard face the mouse
if (parent!=null) {
dx=stage.mouseX-this.x;
dy=stage.mouseY-this.y;
Math.abs(dx);
Math.abs(dy);
var Angle=Math.atan2(dy,dx);
var newAngle = Angle * (180 / Math.PI);
if ((0 < newAngle) && (newAngle <= 90)) {
gotoAndPlay("Right");
} else if ((90 < newAngle) && (newAngle <= 180)) {
gotoAndPlay("Down");
} else if ((-180 < newAngle) && (newAngle <= -90)) {
gotoAndPlay("Left");
} else if ((-90 < newAngle) && (newAngle <= 0)) {
gotoAndPlay("Up");
}
this.rotation=Angle;
}
}
}
}
That's the code for my player class, with things such as bullets firing and what not. I think I know the problem, I need to link it to the rest of the Wizard update. But I don't know how, here is my bullet class if needed.
package {
import flash.display.Sprite;
import flash.events.Event;
public class Bullet extends Sprite {
private var speed:int;
private var myCharacter:Wizard;
public function Bullet() {
//constructor
speed = 10;
addEventListener(Event.ENTER_FRAME, update);
}
function update (e:Event) {
//Move in the direction the bullet is facing
x=x+Math.cos(rotation/180*Math.PI)*speed;
y=y+Math.sin(rotation/180*Math.PI)*speed;
//Clears bullet once it leaves the stage
if (x<0 || x>500 || y<0 || y>500) {
//removes the update listner
removeEventListener(Event.ENTER_FRAME, update);
parent.removeChild(this);
}
}
}
}
You're setting the Wizard's rotation to Angle, which is in radians; the rotation is then passed on to the Bullet, which expects its rotation to be in degrees. It's probably better to set this.rotation=newAngle; at the end of update(), as the UIComponent class expects that value in degrees and uses it for rotating its drawing.

AS3 How to find current location of mc?

Thanks for the startdrag() suggestions, but I'm trying to avoid that atm
I'm trying to create a drag motion by using mouse_down then the mc = mouseX. Here is an image of the situation
But when I click, the mc always jumps to its registration point, which is the top left corner atm.
I can't work my head around how to grab the current location of the mc. Note that the mc (all_mc) is wider than the stage.
Can someone please help me out?
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(e:MouseEvent) {
this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}
function mouseMoveHandler(e:MouseEvent) {
all_mc.x = mouseX;
}
Edit:
Ok I kind of worked out the x location of the mouse in relation to the registration point of the mc (the registration is at the top left):
Math.abs(stage.x - all_mc.x) + mouseX
But how to I select that point of on the mc?
Modified Marty Wallace's answer to handle the difference between where you click and the registration point:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class DummyTest extends Sprite {
private var mDeltaX:Number = 0;
private var mDeltaY:Number = 0;
private var mGfx:Sprite;
public function DummyTest() {
mGfx = new Sprite();
with(mGfx.graphics) {
beginFill(0x00FF00);
drawRect(0, 0, 200, 200);
endFill();
}
addChild(mGfx);
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(e:MouseEvent) : void {
mDeltaX = mGfx.x - mouseX;
mDeltaY = mGfx.y - mouseY;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onMouseUp(e:MouseEvent) : void {
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onEnterFrame(e:Event) : void {
mGfx.x = parent.mouseX + mDeltaX;
mGfx.y = parent.mouseY + mDeltaY;
}
}
}
import flash.events.MouseEvent;
import flash.display.Sprite;
var mc:MovieClip;
var sprite:Sprite = new Sprite ;
sprite.graphics.beginFill(0x000000);
sprite.graphics.drawRect(0,0,100,100);
sprite.graphics.endFill();
this.addChild(sprite);
sprite.addEventListener(MouseEvent.MOUSE_DOWN,function(){
sprite.startDrag();}
);
sprite.addEventListener(MouseEvent.MOUSE_UP,function(){
sprite.stopDrag();}
);
startDrag() has a lockCenter argument which you could try playing with.
lockCenter:Boolean (default =
false) — Specifies whether the
draggable sprite is locked to the
center of the mouse position (true),
or locked to the point where the user
first clicked the sprite (false).
Without startDrag as per comment
Make this the base class of an object that you want to drag:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
public class Draggable extends Sprite
{
// vars
private var _hx:Number = 0;
private var _hy:Number = 0;
/**
* Constructor
*/
public function Draggable()
{
addEventListener(MouseEvent.MOUSE_DOWN, _mouseDown);
}
/**
* MouseEvent.MOUSE_DOWN
*/
private function _mouseDown(e:MouseEvent):void
{
_hx = mouseX;
_hy = mouseY;
addEventListener(Event.ENTER_FRAME, _handle);
addEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
/**
* MouseEvent.MOUSE_UP
*/
private function _mouseUp(e:MouseEvent):void
{
removeEventListener(Event.ENTER_FRAME, _handle);
removeEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
/**
* Event.ENTER_FRAME
*/
private function _handle(e:Event):void
{
x = parent.mouseX - _hx;
y = parent.mouseY - _hy;
}
}
}
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
var positionX:Number = 0;
var positionY:Number = 0;
function mouseDownHandler(e:MouseEvent) {
positionX = all_mc.mouseX;// save the x position for future reference
positionY = all_mc.mouseY;// save the y position for future reference
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}
function mouseMoveHandler(e:MouseEvent) {
all_mc.x = stage.mouseX - positionX ;
all_mc.y = stage.mouseY - positionY ;
}
function mouseUpHandler(e:MouseEvent) {
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}

AS3 - How to drag an object in a line that is not vertical or horizontal

I would like to drag an object in one line.
I already know how to do this in a horizontal or vertical line
Here's how I do this
private var handle:Sprite;
private function init():void
{
handle = new Sprite();
handle.mouseChildren = false;
handle.buttonMode = true;
handle.graphics.beginFill(0xFF0000);
handle.graphics.drawCircle(0, 0, 5);
handle.addEventListener(MouseEvent.MOUSE_DOWN, startMove);
handle.addEventListener(MouseEvent.MOUSE_UP, stopMove);
}
private function startMove(evt:MouseEvent):void
{
var bounds:Rectangle = new Rectangle(0, 0, 100, 1);
handle.startDrag(false, bounds);
}
private function stopMove(evt:MouseEvent):void
{
handle.stopDrag();
}
But I want do drag my object in a line that isn't horizontal or vertical.
For example, I would like to drag the object from the top left corner to the bottom right corner, in one straight line.
I tried to rotate the bounds rectangle, but it seems that you can not rotate a Rectangle.
How do I drag an object in a non-vertical (or non-horizontal) line?
Thank you very much!
Vincent
You cannot use startdrag system to do it. You have to use an enterframe event and constraint x/y yourself :
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Test extends Sprite
{
private var handle:Sprite;
public function Test()
{
handle = new Sprite();
addChild(handle);
handle.mouseChildren = false;
handle.buttonMode = true;
handle.graphics.beginFill(0xFF0000);
handle.graphics.drawCircle(0, 0, 5);
handle.addEventListener(MouseEvent.MOUSE_DOWN, startMove);
addEventListener(MouseEvent.MOUSE_UP, stopMove);
}
private function startMove(evt:MouseEvent):void
{
stage.addEventListener(Event.ENTER_FRAME, updateClipPos);
}
private function stopMove(evt:MouseEvent):void
{
stage.removeEventListener(Event.ENTER_FRAME, updateClipPos);
}
private function updateClipPos(e:Event) : void
{
if(mouseX < 100)
{
handle.x = mouseX;
handle.y = handle.x;
}
}
}
}