ActionScript Local X And Y Coordinates Of Display Object? - actionscript-3

i'm trying to trace the x and y coordinates from within a sprite. i've added a rectangle to the stage:
var rect:Rectangle = new Rectangle(10, 10, 200, 200);
addChild(rect);
rect.x = rect.y = 100;
adding a Mouse_Move event to the rect, i can trace mouseX and mouseY to receive the coordinates of the stage while moving over the rect, but how do i get the local x and y coordinates? so if i mouse over the very top left of the rect sprite, the mouseX and mouseY return 10 as the global coordinates, but how do i make it return 0 and the local coordinates of the sprite?
i assumed localX and localY was what i was looking for, but this doesn't work:
function mouseOverTraceCoords(evt:MouseEvent):void
{
trace(mouseX, mouseY, evt.localX, evt.localY);
}

It depends how you have designed your Rectangle class,
if you have done something like this:
class Rect1 extends Sprite {
public function Rect1(x:Number, y:Number, width:Number, height:Number) {
var g:Graphics = graphics;
g.beginFill(0xff0000, 0.5);
g.drawRect(x, y, width, height);
g.endFill();
}
}
your local coordinate will be at 0,0 but you drawing start at x,y so when you are getting the localx, localY you will obtain x,y and not 0,0.
But if your class is designed as something like that :
class Rect2 extends Sprite {
public function Rect2(x:Number, y:Number, width:Number, height:Number) {
var g:Graphics = graphics;
g.beginFill(0xff0000, 0.5);
g.drawRect(0, 0, width, height);
g.endFill();
this.x = x;
this.y = y;
}
}
then your drawing start at 0,0 and your object is moved at x,y so the localX and localY from the MouseEvent will be ok.
Edit:
To get the local coordinate you can try using getBounds :
function mouseOverTraceCoords(evt:MouseEvent):void {
var dob:DisplayObject = DisplayObject(evt.target);
var bnds:flash.geom.Rectangle = getBounds(dob.parent);
var localX:Number=e.localX - bnds.x + dob.x;
var localY:Number=e.localY - bnds.y + dob.y;
trace(mouseX, mouseY, evt.localX, evt.localY, localX, localY);
}

take a look at globalToLocal

There's no need to do any transformations at all *, your Rectangle will have two properties called mouseX and mouseY which contain the local coordinates of the mouse.
If you're drawing your graphics offset within the rectangle, the coordinate system will not consider this, it's a better idea to offset the entire rectangle instead.
* assuming your Rectangle class is a subclass of DisplayObject, which I'd assume since you've got it on the stage.

Related

as3 - How do I make an object rotate to the crosshair instead of the mouse?

I placed the arm movieclip instance inside of the player movieclip instance. The crosshair instance is placed in the player movieclip's parent.
I'm trying to get the arm to rotate by following the crosshair. I tried using mouseX and mouseY and that seemed to work except I want the arm to follow the crosshair, not the mouse. The crosshair is placed in the player movieclip's parent so I use MovieClip(parent), so I put this code in the player class' enterframe:
var dx = MovieClip(parent).crosshair.x - arm.x;
var dy = MovieClip(parent).crosshair.y - arm.y;
var angle = Math.atan2(dy, dx) / Math.PI * 180;
arm.rotation = angle;
However when I do this, the arm does not rotate at all. What am I supposed to be doing?
The crosshair is an instance that is outside the movieclip and has the instance name of "crosshair". It's not a variable.
The code for the crosshair is inside player's parent's enterframe:
crosshair.x += (mouseX - crosshair.x) / 5;
crosshair.y += (mouseY - crosshair.y) / 5;
You need to convert the coords inside player MovieClip to the coords in the same system that the crosshair MovieClip using localToGlobal and globalToLocalmethods.
An example code:
this.addEventListener(Event.ENTER_FRAME, rotateArm);
var crosshair:MovieClip = MovieClip(this.parent).crosshair;
//---Rotate arm function
function rotateArm(evt:Event):void{
//---Move crosshair
moveCrossHair();
//---Convert the local Point to global Point
var point:Point = new Point(this.arm.x, this.arm.y);
var parentPoint:Point = this.parent.globalToLocal(this.localToGlobal(point));
var dx:Number = crosshair.x - parentPoint.x;
var dy:Number = crosshair.y - parentPoint.y;
var angle:Number = Math.atan2(dy, dx) / Math.PI * 180;
this.arm.rotation = angle;
}
//---Move crosshair function
function moveCrossHair():void{
crosshair.x += (this.parent.mouseX - crosshair.x) / 5;
crosshair.y += (this.parent.mouseY - crosshair.y) / 5;
}
Here you have a working example, it was built with Flash Pro but I've included a xfl example.
Download Example

as3 applying gravity to a missile

I'm trying to create a "worms" style turn based artillery game is as3. I am able to add my ball on the x/y location of the character and have the ball fire in the direction of the mouses location when the click is made but I am now having difficulty in applying gravity to the ball. If anybody can help me at all with what I need to do to make the ball drop in an arc after being fired that would be great.
My code for adding the ball and having it fire in the selected direction is:
Game Main:
function redFollow(e:MouseEvent):void
{
var a1 = mouseY - redPower.y;
var b1 = mouseX - redPower.x;
var radians1 = Math.atan2(a1,b1);
var degrees1 = radians1 / (Math.PI/180);
redPower.rotation = degrees1;
}
public function redFIRE(Event:MouseEvent)
{
removeChild(redPower);
turnchangeover();
addChild(RPBall);
trace("FIRE!");
RPBall.x = red.x;
RPBall.y = red.y;
RPBall.rotation = redPower.rotation + 90;
}
and then the ball's class code is:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class redBall extends MovieClip {
public function redBall() {
this.addEventListener(Event.ENTER_FRAME, moveShot);
}
function moveShot(event:Event){
var thisMissile:redBall = redBall(event.target);
var _missileSpeed:int = 7;
var gravity:int = 0.8;
//get the x,y components of the angle
var missileAngleRadians = ((-thisMissile.rotation - 180) * Math.PI /180);
//trace("missle angle: " + missileAngleRadians);
var yMoveIncrement = Math.cos(missileAngleRadians) * _missileSpeed;
var xMoveIncrement = Math.sin(missileAngleRadians) * _missileSpeed;
thisMissile.y = thisMissile.y +yMoveIncrement;
thisMissile.x = thisMissile.x + xMoveIncrement;
trace(thisMissile.y);
}
}
}
You need to store speed separately by X and by Y. See, after your ball has been launched, you don't care about angle, but only care about speed, and speed is what's affected by gravity. You already split speed by X and Y components in yMoveIncrement,xMoveIncrement, now you just need to have them be properties of the ball (it'll be its velocity), and add a small per-frame increment to Y component of velocity.
public class redBall extends MovieClip {
public var yVelocity:Number=0;
public var xVelocity:Number=0; // these will be assigned when the ball is shot
public static var gravity:Number=0.5; // Number, not "int"
// also "static" so that it'll affect all balls similarly
public function redBall() {
this.addEventListener(Event.ENTER_FRAME, moveShot);
}
function moveShot(event:Event){
// var thisMissile:redBall = redBall(event.target);
// why is ^ this? You can use "this" qualifier in this function
// we already have the x,y components of the angle
this.y = this.y + this.yVelocity;
this.x = this.x + this.xVelocity;
this.yVelocity = this.yVelocity + gravity;
// also, you care for rotation - let's add a trick
var angle:Number=Math.atan2(this.yVelocity,this.xVelocity);
// direction angle, in radians
this.rotation=angle*180/Math.PI; // make into degrees and rotate
trace(thisMissile.y);
}
}
It'll be a good practice if you will add a shoot function to redBall class that will accept angle and initial velocity, to assign xVelocity and yVelocity as you did in the listener.
In order to re-create the that projectile motion you'll need to introduce 3 variables Gravity (constant), velocity (on the x and y, similar to your move increment) and decay, also referred to as friction.
Friction should be a value under 1. So that it reduces velocity over time. Once the velocity is less than the Gravity in your system the item should start dropping back to the ground. The item will also slow down on the x axis.
velocity.y *= friction;
thisMissile.y += velocity.y + gravity.y;
Here's a generic tutorial on projectile physics that may be of interest and an AS3 tutorial on Angry Bird like ground to ground projectile.

Positioning movieclip with x and y coordinates

I have a strange problem. I have a two sprites that are added to other Sprite and I, with localToGlobal(), get their global x,y coordinates, but when I add another movieclip and try to move them to "global" coordinates on ENTER_FRAME event, they are locked on 0,0 of the stage??
I have traced coords and they are correct but no positioning... Why?
var point:Point = new Point();
addChild(pl_name);
pl_name.addEventListener(Event.ENTER_FRAME, mov);
function mov(e:Event):void
{
for (var i in players)
{
var gglobal:Point = players[i].localToGlobal(point);
pl_name.x = gglobal.x;
pl_name.y = gglobal.y;
trace ("nameX "+pl_name.x+" nameY "+pl_name.y);
}
}
The point you are giving it isnt set to anything before it is used. Try this.
point.x = players[i].x;
point.y = players[i].y;
var gglobal:Point = players[i].localToGlobal(point);

AS3 drawing line with brush PNG images pattern

This functionality exists in desktop programs such as Adobe Illustrator or Painter.
You can select a brush that is a pattern of images. Starting to paint on canvas displays a line (or any pattern) created from a set of images of different sizes and rotations. Approximately how I portrayed in the picture (the red line is a path of the brush motion).
Is there already a library for this effect, or how it can best be implemented?
Listen for MouseEvent.MOUSE_DOWN on your drawing canvas and once it fires, add a Event.ENTER_FRAME to begin drawing. The drawing itself is pretty straightforward - on every frame you take the mouseX and mouseY values and add the PNG image on the canvas in the exact place with any transformations (scaling, rotation, alpha) for that particular image. Here's a simple example:
private var PatternPNG:Class;
private var canvas:Sprite;
private function init() {
canvas = new Sprite();
addChild(canvas);
canvas.graphics.beginFill(0xFFFFFF);
canvas.graphics.drawRect(0,0,CANVAS_WIDTH,CANVAS_HEIGHT);
canvas.graphics.endFill();
canvas.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(e:Event):void
{
canvas.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
canvas.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
canvas.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onMouseUp(e:Event):void
{
canvas.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
canvas.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
canvas.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
var patternPiece:DisplayObject = new PatternPNG();
patternPiece.rotation = Math.random() * 360;
patternPiece.alpha = Math.random();
patternPiece.scaleX = patternPiece.scaleY = 0.2 + Math.random() * 0.8;
patternPiece.x = mouseX;
patternPiece.y = mouseY;
canvas.addChild(patternPiece);
}

ActionScript 3 - Tweening rotateAroundExternalPoint

i'm unsuccessfully trying to rotate a rectangle around an external point while tweening. i'm trying to lock the top of the red rectangle to the line while it tweens from left to right and rotates from 0º to 90º.
alt text http://www.freeimagehosting.net/uploads/0b937c92e6.png
the image above shows 3 states of the tween. state 1 shows the red rectangle at the start of the line with no angle. state 2 shows the red rectangle has tweened half way along the line with an angle of 45º that is also half the total angle of 90º. state 3 shows the final position of the tween where the red rectangle has an angle of 90º and is placed at the edge of the line.
it seems the problem i'm experiencing is that while tweening, the rotation causes the top of the red rectangle to lose sync with the black line.
here is my code that doesn't work, but hopefully will give you a clearer picture of what i'm attempting.
var angle:Number = 90;
var previousAngle:Number = 0;
var distanceObject:Object = new Object();
distanceObject.distance = line.width;
distanceTween = new Tween(distanceObject, "distance", None.easeNone, 0, distanceObject.distance, 5, true);
distanceTween.addEventListener(TweenEvent.MOTION_CHANGE, tweenHandler);
function tweenHandler(evt:TweenEvent):void
{
var angleShift:Number = (angle / distance) * distanceObject.distance;
//1:tween RedBox position
redBox.x = line.x + line.width * distanceObject.distance;
//2:tween RedBox angle
var externalPointMatrix:Matrix = redBox.transform.matrix;
MatrixTransformer.rotateAroundExternalPoint(externalPointMatrix, 0 + redBox.width * distanceObject.distance, 0, angleShift - previousAngle);
redBox.transform.matrix = externalPointMatrix;
previousAngle = angleShift;
}
I don't think you have specified the problem well enough for a generic solution. There are 3 things changing here: x, y and rotation. Each of these is calculated as a result of a point on the rectangle (the blue "x" in your diagram) that changes over time. That means the thing you need to focus on first is the point on the rectangle that changes over time. Next you need to know that the x and y can be calculated using that point along with the rotation.
So break it down into steps.
find the location of the "x" point on the line
rotate the object
find the location of the "x" point wrt to the rectangle
based on the angle of rotation and the known location of the "x" point calculate the x and y position of the rectangle (SOHCAHTOA)
Here is some code to illustrate:
package
{
import com.greensock.TweenNano;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width='500', height='300', backgroundColor='#ffffff', frameRate='30')]
public class BoxAnim extends Sprite
{
private static const LINE_WIDTH:int = 350;
private static const RECT_WIDTH:int = 150;
private static const RECT_HEIGHT:int = 100;
private static const FINAL_ROTATION:Number = Math.PI/2;
public var point:Number;
private var line:Sprite;
private var rect:Sprite;
private var cross:Sprite;
public function BoxAnim()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(event:Event):void
{
line = new Sprite();
addChild(line);
line.graphics.lineStyle(10, 0x0);
line.graphics.lineTo(LINE_WIDTH, 0);
line.x = 50;
line.y = 175;
rect = new Sprite();
addChild(rect);
rect.graphics.lineStyle(4, 0xFF0000);
rect.graphics.beginFill(0xFF0000, 0.5);
rect.graphics.drawRect(0, 0, RECT_WIDTH, RECT_HEIGHT);
rect.x = 50;
rect.y = 175;
cross = new Sprite();
addChild(cross);
cross.graphics.lineStyle(5, 0x41a9f4);
cross.graphics.moveTo(-5, -5);
cross.graphics.lineTo(5, 5);
cross.graphics.moveTo(5, -5);
cross.graphics.lineTo(-5, 5);
cross.x = 50;
cross.y = 175;
point = 0;
TweenNano.to(this, 3, {point: 1, onUpdate: tick});
}
private function tick():void
{
// first calculate where the point should be on the line
cross.x = (point * LINE_WIDTH) + line.x;
// calculate the angle of rotation
var rotationRadians:Number = (point * FINAL_ROTATION);
rect.rotation = rotationRadians*180/Math.PI;
// calculate where on the rectangle the point would be
var rectCrossX:Number = (point * RECT_WIDTH);
// use trig to find the x & y points
rect.x = cross.x - Math.cos(rotationRadians)*rectCrossX;
rect.y = cross.y - Math.sin(rotationRadians)*rectCrossX;
}
}
}
I'm just using the variable point as a percentage that goes from 0 to 1. I then scale it to find the position of the "x" point on the line. Scale it again to figure out the rotation. Scale it again to find where it lies along the top of the rectangle. Then trig solves the location of the corner of the rectangle wrt the point.