Moving on X Y axis based on rotation - actionscript-3

I'm trying to make the character move based on their angle of rotation, however it moves like it is strafing right.
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
lilman.rotation = 0
var personRotation:Number = lilman.rotation * (Math.PI / 180)
stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent)
{
if(e.keyCode==65)
{
lilman.rotation -= 5
}
else if(e.keyCode==68)
{
lilman.rotation += 5
}
})
stage.addEventListener(MouseEvent.MOUSE_DOWN, function()
{
personRotation = lilman.rotation * (Math.PI / 180)
lilman.x += Math.cos(personRotation)*5
lilman.y += Math.sin(personRotation)*5
trace(Math.cos(personRotation) +", "+ Math.sin(personRotation) +", "+ personRotation +", "+ lilman.rotation)
})

I've tested your code. It's 100% fine.
To solve the strafing issue you need to edit the MovieClip object's own rotation. Assuming your MC is facing upwards (north), make it face right (east) as origin of 0 degrees.
1) Right-click the MC and choose edit.
2) In Edit mode... Select everything and (a) rotate it 90 degrees to the right, (b) align the (was previously) bottom to the point +. Test if it works as expected

Related

As3 Trigonometry and math

i'm trying to create a minigame with circles rotating around circles
however, i have a problem when i shoot the circle and it hits the second circle it doesnt continue the angle but "jumping" to the other side i'm sure it something with the angle var that should reset or something. can you help me im getting nervous around here... :(
check the example
This is my code for the enter frame function that deals with the circles
public function UpdateCircles(e:Event):void
{
for (var i:int = 0; i < EnemySpriteVector.length; i++)
{
EnemySpriteVector[i].rotation += EnemySpriteVector[i].enemyspeed;
}
var rad:Number = angle * (Math.PI / 180); // Converting Degrees To Radians
if (IsplayerShoot)
{
playerSprite.x += Math.cos(rad) * PlayerCircleShootSpeed;
playerSprite.y += Math.sin(rad) * PlayerCircleShootSpeed;
for (var j:int = 0; j < EnemySpriteVector.length; j++)
{
if (EnemySpriteVector[j].hitTestPoint(playerSprite.x,playerSprite.y) && (EnemySpriteVector[j].IsCircleHit == false))
{
trace("hit");
EnemySpriteVector[j].IsCircleHit = true;
removeChild(EnemySpriteVector[0]);
EnemySpriteVector.splice(0, 1);
var EnemySprite:Sprite = new EnemySpriteClass();
EnemySpriteVector.push(EnemySprite);
addChild(EnemySprite);
EnemySprite.x = Math.random() * stage.stageWidth;
EnemySprite.y = Math.random() * stage.stageHeight;
IsplayerShoot = false;
}
}
}
else
{
playerSprite.x = EnemySpriteVector[0].x + EnemySpriteVector[0].radius * Math.cos(rad); // Position The Orbiter Along x-axis
playerSprite.y = EnemySpriteVector[0].y + EnemySpriteVector[0].radius * Math.sin(rad); // Position The Orbiter Along y-axis
angle += EnemySpriteVector[0].enemyspeed; // Object will orbit clockwise
playerSprite.rotation = (Math.atan2(playerSprite.y - EnemySpriteVector[0].y, playerSprite.x - EnemySpriteVector[0].x) * 180 / Math.PI); //only rotates the player circle itself
}
}
Looks like when the pink circle hits the green one it simply continues its rotation from where it left of. A quick solution would be to add 180 degrees to the angle. Keep in mind this will only work for static objects. If you want a more dynamic environment I would recommend using vectors (linear algebra). Vector math is really easy to understand and it hides a lot of complex trigonometry. You can start here :)

How to find correct offset to adjust sprite to the position of box2D body after rotation

I am trying to implement phsyics with the as3 box2d port. I currently have a b2body for each of some certain sprites in my game and I am able to update the sprite's positions correctly from the positions of the bodies. This is shown in the picture below (debugDraw shows the positions of the b2bodies overlaid on their corresponding spirtes. The green rectangles are the walls and floor)
However, I also want to have the sprite's rotations reflect the rotations of the b2bodies. But, after I rotate the sprites, the offset I use to center them correctly with the b2body positions is no longer accurate.
My code for updating the sprites positions is as follows:
private function Update(update_event:TimerEvent):void
{
//step physics simulation forward
world.Step(0.025,10,10);
//update all objects in world
for each (var obj:HouseItemPhysicsObject in physicsObjects)
{
//update object's position from gravity if it is not being dragged
if(!obj.isHeld)
{
/*adjust rotation of sprite along with body -> yourMC.rotation = (yourMCbody.GetAngle() * 180 / Math.PI) % 360; */
obj.object.rotation = (obj.pBody.GetAngle() * 180/Math.PI) % 360;
if(obj.object.rotation >=5)
// set object's x position but adjust for offset between the cooridinate systems
obj.x = (obj.pBody.GetPosition().x* scaleFactor)-(obj.object.width/2);
//keep in horizontal bounds of screen
if(obj.x > GeneralConstants.GAME_WIDTH)
{
obj.x =GeneralConstants.GAME_WIDTH;
}
else if(obj.x < 0)
{
obj.x = 0;
}
// set object's x position but adjust for offset between the cooridinate systems in Flash and box2d
obj.y = (obj.pBody.GetPosition().y * scaleFactor)-(obj.object.height/2);
//keep in vertical bounds of the screen
if(obj.y > GeneralConstants.GAME_HEIGHT)
{
obj.y =GeneralConstants.GAME_HEIGHT;
}
else if(obj.x < 0)
{
obj.x = 0;
}
/*Draw shapes to see for debug*/
//obj.DrawDebug();
//trace("OBJECT's X is :" + obj.x + " Y is :" +obj.y);
trace("Object's rotation is:" + obj.object.rotation);
}
}
//move debug draw to front of display list
m_sprite.parent.setChildIndex(m_sprite, m_sprite.parent.numChildren - 5);
world.DrawDebugData();
}
How can I find the correct X and Y offset between the coordinate systems (Flash and Box2d) after rotating the sprite according to the b2Body? Thanks for the help.
EDIT:
For clarity, the object is a class that extends the Sprite class, and it's data member _object is a an instance of MovieClip.
Box2D objects have their anchor point in the center by default, while for Flash objects, it's in the top left. To position them properly, you need to take this into account
Easy way
Wrap your Bitmaps/whatever in a Sprite and center them:
// create the image, center it, and add it to a holder Sprite
var image:Bitmap = new Bitmap( objGraphicsBitmapData );
image.x = -image.width * 0.5;
image.y = -image.height * 0.5;
var holder:Sprite = new Sprite;
holder.addChild( image );
Now just set the position and rotation of holder as you do currently, and it should be fine
Hard way
You need to manually adjust the position offset based on the object's rotation. A simple rotation function:
public function rotate( p:Point, radians:Number, out:Point = null ):Point
{
// formula is:
// x1 = x * cos( r ) - y * sin( r )
// y1 = x * sin( r ) + y * cos( r )
var sin:Number = Math.sin( radians );
var cos:Number = Math.cos( radians );
var ox:Number = p.x * cos - p.y * sin;
var oy:Number = p.x * sin + p.y * cos;
// we use ox and oy in case out is one of our points
if ( out == null )
out = new Point;
out.x = ox;
out.y = oy;
return out;
}
First we need to store the object's offset - this is normally new Point( -obj.width * 0.5, -obj.height * 0.5 ). You need to stock this while it's rotation is 0, and rotating the object will change its width and height properties, so the following won't work properly.
obj.offset = new Point( -obj.width * 0.5, -obj.height * 0.5 );
When you're updating the position, simply rotate the offset by the rotation and add it:
// get our object's position and rotation
// NOTE: you'll probably need to adjust the position based on your pixels per meter value
var pos:Point = new Point( obj.pBody.GetPosition().x, obj.pBody.GetPosition().y ); // pos in screen coords
var rotR:Number = obj.pBody.GetAngle(); // rotation in radians
var rotD:Number = radiansToDegrees( rotR ); // rotation in degrees
// rotate our offset by our rotation
var offset:Point = rotate( obj.offset, rotR );
// set our position and rotation
obj.x = pos.x + offset.x;
obj.y = pos.y + offset.y;
obj.rotation = rotD;
Other useful functions:
public function degreesToRadians( deg:Number ):Number
{
return deg * ( Math.PI / 180.0 );
}
public function radiansToDegrees( rad:Number ):Number
{
return rad * ( 180.0 / Math.PI );
}
If you do it to give your sprites properties of physical objects, it can be easier to use physInjector for box2D:
http://www.emanueleferonato.com/2013/03/27/add-box2d-physics-to-your-projects-in-a-snap-with-physinjector/
It is free can do it in a couple of lines.

Movieclip to spawn in a set parameter

I like to make a movieclip randomly spawn in a set area. But theres a little more to it, usually you'd have something like the X pos set to something like 250 (say the centre) and the Y pos set to be math.random but it won't work for how I'd like it.
I'm making a First Person Shooter and want the Enemy movieclip to spawn off stage but from the Top, Bottom, Left and Right of the stage as shown in the quick annotated image here.
Is this possible to be done? If so how could I achive this?
Thanks for your help.
Something dirty like this would work
_enemy.x = _enemy.y = 0;
while(_enemy.x >= 0 && _enemy.x <= stage.stageWidth)
{
_enemy.x = Math.random() * (stage.stageWidth * 3) - stage.stageWidth;
}
while(_enemy.y >= 0 && _enemy.y <= stage.stageHeight)
{
_enemy.y = Math.random() * (stage.stageHeight * 3) - stage.stageHeight;
}
Or you could go for a more fancy approach, where enemies would spawn with a random angle on a circles edge. The enemies will always be spawned at a fixed distance from the stage's center, but this can easily be modified
var radius:Number = 800: // Set this to be greater than stage dimensions
var angle:Number = Math.random() * Math.PI * 2;
_enemy.x = (stage.stageWidth / 2) + ( Math.cos( angle ) * radius );
_enemy.y = (stage.stageHeight / 2) + ( Math.sin( angle ) * radius );

AS3 Missile Logic

I want to create a simple missile object, which moves at a set speed and rotates towards a specific target at a given rotation speed. However, I'm having trouble figuring out the math of it. This is my code so far:
private function enterFrame(e:Event):void {
// Rotate the missile towards the target.
var targetAngle:Number = getAngle(target.x, target.y, x, y);
if (targetAngle < 0) {
targetAngle += 360;
}
if (targetAngle - turnSpeed > rotation) {
rotation += turnSpeed;
} else if (targetAngle + turnSpeed < rotation) {
rotation -= turnSpeed;
} else {
rotation = targetAngle;
}
// Set the target point to move to based on angle and speed.
var newX:Number = x + Math.sin(degreesToRadians(rotation)) * speed;
var newY:Number = y + Math.cos(degreesToRadians(rotation)) * speed;
// Move to new location
x = newX;
y = newY;
}
private function getAngle (x1:Number, y1:Number, x2:Number, y2:Number):Number {
var dx:Number = x2 - x1;
var dy:Number = y2 - y1;
return (Math.atan2(dy,dx) * 180) / Math.PI;
}
private function degreesToRadians(degrees:Number):Number {
return degrees * Math.PI / 180;
}
I've been trying to debug it using trace and such, but I can't seem to figure out where the problem is, most likely because there are many problems and I can't tell if I've fixed one because the others are masking it. I suspect that the issue(s) lie somewhere in the rotation calculations, since I'm pretty sure that the movement part is working as it should, but I can't say for sure.
At any rate, whatever I do, the missiles always seem to fly off in random directions, sometimes tracking towards straight up, or straight down, or just looping around after nothing in particular.

Strafe Around a Point

This seems like a simple trig question, but for whatever reason, things aren't working out.
I'm trying to simply have an object rotate around a given point when the user presses the A/D keys (strafing around the mouse in a circular motion, while still facing the mouse).
Here's the code I've tried so far (all Math functions take and return radians):
if (_inputRef.isKeyDown(GameData.KEY_LEFT))
{
x += 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x) - Math.PI * 0.5);
y += 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x) - Math.PI * 0.5);
}
else if (_inputRef.isKeyDown(GameData.KEY_RIGHT))
{
x += 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x) + Math.PI * 0.5);
y += 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x) + Math.PI * 0.5);
}
And a more elegant method which accomplishes the same thing:
if (_inputRef.isKeyDown(GameData.KEY_LEFT))
{
x += 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x));
y -= 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x));
}
else if (_inputRef.isKeyDown(GameData.KEY_RIGHT))
{
x -= 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x));
y += 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x));
}
Now, they both kind of work, the object rotates around the mouse while always facing the mouse, but given enough time of holding down the strafe button, it becomes increasingly apparent that the object is also rotating AWAY from the mouse, as if its being pushed away.
I have no idea why this is and how to fix it.
Any insight is appreciated!
I think your current approach would only work if you take 'infinitely small' steps. As it is now, each movement is perpendicular to the "to-mouse vector" and thus increases the distance between mouse and object.
A solution would be to calculate the new position while keeping the distance to the mouse unchanged, by rotating the position around the mouse:
// position relative to mouse
var position:Point = new Point(
x - mouseX,
y - mouseY);
var r:Number = position.length; // distance to mouse
// get rotation angle around mouse that moves
// us "SPEED" unit in world space
var a:Number = 0;
if (/* LEFT PRESSED */) a = getRotationAngle( SPEED, r);
if (/* RIGHT PRESSED */) a = getRotationAngle(-SPEED, r);
if (a > 0) {
// rotate position around mouse
var rotation:Matrix = new Matrix();
rotation.rotate(a);
position = rotation.transformPoint(position);
position.offset(mouseX, mouseY);
x = position.x;
y = position.y;
}
// elsewhere...
// speed is the distance to cover in world space, in a straight line.
// radius is the distance from the unit to the mouse, when rotating.
private static function getRotationAngle(speed:Number, radius:Number):Number {
return 2 * Math.asin(speed / (2 * radius));
}
The above uses a Matrix to rotate the (x, y) position around the mouse position. Ofcourse you can apply the same principle without using Matrix if so desired.
I had to do some trig to come up with the right equation for getting the correct angle. The angle depends on the radius of the movement arc, since a larger radius but constant angle would increase the movement distance (undesired behavior). My earlier solution (before edits) was to scale the angle by the radius, but that would still result in slightly more movement with larger radii.
The current approach ensures that radius and speed remain constant in all cases.