Enemy rotates very strangely - actionscript-3

I have this problem: there is this enemy which rotates to my player. While "orbiting" the enemy with my player I can see that the enemy is rotating towards my player.
And then the enemy suddenly turns around 360 degrees and facing to my player again. I don't know why it does this strange 360 degree turn but it happens every time when I orbit the enemy for a few seconds. I don't know where the problem might be.
tempEnemy.dX = tempEnemy.x - player.x;
tempEnemy.dY = tempEnemy.y - player.y;
tempEnemy.rotateTo = toDegrees(getRadians(tempEnemy.dX, tempEnemy.dY));
if(tempEnemy.frame < 0) tempEnemy.frame += 360;
if(tempEnemy.frame > 359) tempEnemy.frame -= 360;
tempEnemy.trueRotation = int((tempEnemy.rotateTo - tempEnemy.frame) / tempEnemy.rotateSpeed);
tempEnemy.vX += (player.x - tempEnemy.x) / tempEnemy._speed;
tempEnemy.vY += (player.y - tempEnemy.y) / tempEnemy._speed;
tempEnemy.vX *= tempEnemy.decay;
tempEnemy.vY *= tempEnemy.decay;
Update:
private function toDegrees(radians:Number):Number
{
var degrees:Number = Math.floor(radians * 180 / Math.PI);
//trace (degrees);
return degrees;
}
private function getRadians(deltaX:Number, deltaY:Number):Number
{
var radian:Number = Math.atan2(deltaY, deltaX);
if (deltaY < 0)
{
radian += (2 * Math.PI);
}
return(radian);
}

Without seeing your getRadians function, perhaps you're passing 360° calculating a reflex angle?
Maybe something like:
var degrees:Number = Math.atan2(tempEnemy.y - player.y, tempEnemy.x - player.x) * 180 / Math.PI;
var delta:Number = degrees - tempEnemy.rotation;
while (delta <= -180)
delta += 360;
while (delta > 180)
delta -= 360;
Compensate degrees with the resting angle of your enemy display object design.

It sounds like you've used a timeline tween. Either use a code tween, or grab the tween I used here http://flexdiary.blogspot.com/2010/04/sample-code-for-oop-timeline-insideria.html. I don't remember what exactly I did to make the timeline tween go full circle, rather than twisting back before restarting, but you should be able to export and reuse the tween.
If you want to use a code tween, you can either use Flash's built in tween classes or use a library like Tweensy.

Related

Tank with Rotating Turret AS3

I'm making a battleship simulator that controls a battleship with the WASD keys and the turret with the mouse pointer. The turret can move 360 degrees.
It rotates as it should; however, whenever the mouse pointer makes the turret reach an angle of 0 or 360 degrees, it begins rotating endlessly until I move the mouse pointer back to a different angle.
Attached is the code I have so far for turret movement:
var PTurret1angle:Number = 270;
function PTurretRotate(Evt:Event){
var Turret1x:Number;
var Turret1y:Number;
var Turret1Angle:Number;
Turret1x = mvi_PTurret1.x - mouseX;
Turret1y = mvi_PTurret1.y - mouseY;
Turret1Angle = Math.round(Math.atan2(Turret1y,Turret1x) * (180/Math.PI) + 180);
if(Turret1Angle > PTurret1angle){
mvi_PTurret1.rotation += 1;
PTurret1angle += 1;
if(PTurret1angle == 360){
PTurret1angle = 0;
}
}
else if(Turret1Angle < PTurret1angle){
mvi_PTurret1.rotation -= 1;
PTurret1angle -= 1;
if(PTurret1angle == 0){
PTurret1angle = 360;
}
}
txt_Turret1Angle.text = Turret1Angle.toString();
txt_PTurret.text = PTurret1angle.toString();
}
So, my two questions are:
1) How do I ensure that the turret will remain locked on to where the mouse pointer is, regardless of mouse pointer position?
2) Is there any way to make the rotation more efficient? For example, if my pointer requires the turret to only turn about 30 degrees, it will actually turn 330 degrees depending on the circumstance.
Thank you for your help.
Your turret angles are funky because of these two if statements:
if(PTurret1angle == 0){
PTurret1angle = 360;
}
and
if(PTurret1angle == 360){
PTurret1angle = 0;
}
These are making your endless rotation (mouse on top, angle is zero, angle is set to 360 which is greater than zero, you subtract one, oh man now it's at 359 which is greater than zero, gotta rotate all the way around, oh man we got to zero, gotta set it to 360, ......etc.....).
You can accomplish the "efficient rotation" by checking the difference between Turret1Angle and PTurret1angle. Here are my assumptions:
Zero is pointing straight up.
Positive rotation is clockwise rotation.
Turret1Angle is mouse angle and PTurret1angle is actual current turret angle
The most you ever want to turn is 180 degrees. (efficient rotation)
That being said, you can figure out which way to turn based on two things: the sign of the difference between Turret1Angle (mouse angle) and PTurret1angle (actual turret angle), and the magnitude of this difference. What do I mean by this?
examples using Turret1Angle (mouse) - PTurret1angle (actual):
Mouse is at 1 degree, turret is at 359. Mouse - turret = -358. The most you want to turn is 180 degrees, so since abs(-358) > 180, then add 360 (as the difference is negative). This gives you +2, which means turn 2 degrees clockwise!
Mouse is at 359, turret is at 1. Mouse - turret = 358. abs(358) > 180, so subtract 360 degrees (as the difference is positive). This gives you -2, so turn 2 degrees counterclockwise!
Mouse is at 1, turret is at 3. Mouse - turret = -2. Since abs(-2) < 180, we don't need to add 360, just turn 2 degrees counterclockwise!
I'm a little rusty with my ActionScript, so I won't actually code this out for you. I think I've explained how to implement the two fixes you asked about thoroughly, but if you have any trouble I'd be happy to psuedocode it.
EDIT: Here's some psuedocode:
var AngleDiff:Number;
// starting after declarations/getting basic information, within your function
Turret1Angle = Math.round(Math.atan2(Turret1y,Turret1x) * (180/Math.PI) + 180);
AngleDiff = Turret1Angle - PTurret1angle;
if(Math.abs(AngleDiff) > 180){ // efficient movement
if(AngleDiff > 0){
AngleDiff -= 360;
}else if(AngleDiff < 0){
AngleDiff += 360;
}
if(AngleDiff > 0){ // do the actual movement
PTurret1Angle += 1;
mvi_PTurret1.rotation += 1;
}else if(AngleDiff < 0){
PTurret1Angle -= 1;
mvi_PTurret1.rotation -= 1;
}
You can probably fix the numbers greater than 360 problem with modulo division, as Lukasz suggests.
PTurret1Angle = PTurret1Angle % 360;
(note: that was more actual code than psuedocode. I haven't actually tested it though so it may/may not work)

As3: Math, I'm too stupid for this. (trigonometry)

Okay, so I made some ai where a guard is following my character.
I am using this code:
private function getDegrees(radians:Number):Number
{
//return Math.floor(radians/(Math.PI/180));
return radians / 0.01745 | 0;
}
private function getRadians(delta_x:Number, delta_y:Number):Number
{
var r:Number = Math.atan2(delta_y, delta_x);
if (delta_y < 0)
{
//r += (2 * Math.PI);
r += 6.283;
}
return r;
}
And then in the loop
if(isShooting)
{
// calculate rotation based on mouse X & Y
_dx = this.x - _root.assassin.x;
_dy = this.y - _root.assassin.y;
// which way to rotate
_rotateTo = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (_rotateTo > this.rotation + 180) _rotateTo -= 360;
if (_rotateTo < this.rotation - 180) _rotateTo += 360;
// ease rotation
_trueRotation = (_rotateTo - this.rotation) / _rotateSpeedMax;
// update rotation
this.rotation += _trueRotation;
gotoAndStop(5);
isWalking = false;
isStanding = false;
}
The thing is, the guard rotates weirdly, it's as if he isn't looking at the player. It's as if the player is somewhere else. Dunno, it just doesn't work.. I have no idea what is wrong with the code!
You should just compute the relative angle
_rotateTo = getDegrees(getRadians(_dx, _dy));
_trueRotation = (_rotateTo - this.rotation) / _rotateSpeedMax;
then normalize this to be as close to zero as possible
_trueRotation = (_trueRotation+900) %360 - 180;
and then cut this to the maximal rotation per step
_trueRotation = max(_trueRotation,_rotateSpeedMax* _timestep);
_trueRotation = min(_trueRotation,-_rotateSpeedMax*_timestep);
and use this then to update the forward direction
this.rotation += _trueRotation;
Speed usually is change per time, so there should be a multiplication with some time step for semantic consistency. Of course, you may have the time step equal to 1, or rotateSpeedMax is really a rotateMaxAngle (per step), then the multiplication with timestep can be removed.
To keep the rotation positive you should use modulus 360 like below for readability and (code) simplicity until and unless it's a clear performance issue: (I think this is right for AC3, just looked it up online quick)
_rotateTo = _rotateTo % 360;
The other possible issue is with how you define _dx and _dy. I'm guessing that the assassin is facing in the opposite direction as intended. The fix is to useI'm thinking it should either be:
_dx = _root.assassin.x - this.x;
_dy = _root.assassin.y - this.y;

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.

Draw random way in ActionScript

I'd like to move an AS 3 movieclip randomly. This is what I currently have, bound to the ENTER_FRAME event. This obviously moves the movieclip from the left upper to the right lower edge, so I need some kind of switch to add/substract the target positions.
function movePsycho(e:Event):void {
e.target.y += Math.random()*2;
e.target.x += Math.random()*2;
if (e.target.y >= stage.height || e.target.x >= stage.width)
e.target.removeEventListener(Event.ENTER_FRAME, movePsycho);
}
You don't need add/substract thing. You just have to make sure not only you get positive values out of your random, but negatives too, so it runs to all sides.
Try changing your random generating lines to this:
e.target.y += Math.random()*10 - 5;
e.target.x += Math.random()*10 - 5;
This will work if you want to make it move in a 5px radius.
I just realized you may want to generate a new random point on the screen, then move to that point and when your object reaches the destination generate another random point to go to. So if that's the case, try this:
mc.addEventListener(Event.ENTER_FRAME, onFrame);
var dirX:int = mc.x;
var dirY:int = mc.y;
function generateRandomPoint():void
{
dirX = Math.random() * stage.stageWidth;
dirY = Math.random() * stage.stageHeight;
}
function onFrame(e:Event):void
{
mc.x += (dirX - mc.x) * 0.1;
mc.y += (dirY - mc.y) * 0.1;
if(Math.abs(dirX - mc.x) < 1 || Math.abs(dirY - mc.y) < 1)
generateRandomPoint();
}
i don't know actionscript but you may find help with this
http://www.actionscript.org/forums/showthread.php3?t=270725

as3 rotational drag / acceleration

Sprite.rotation+=10;
Sprite.rotation*=0.97;
because in as3 the system goes from 180 to -180 I don't know how to apply a drag to a constantly rotating object if it moves either direction. Do I have to convert to radians somehow and then do something? I am pretty bad with math.
I'm not sure "drag" makes sense with the code you've posted. What you've shown would slowly wind the object back to 0 rotation.
If you want a drag/acceleration effect, create a separate variable with your acceleration factor, which you apply every frame. Then, you can apply a factor to that variable to slow rotation down/speed it up.
Something like:
private var _rotationAcceleration:Number = 0;
private var _dragFactor:Number = 0.97;
private var _clip:Sprite;
private function startSpin():void {
_rotationAcceleration = 10.0;
}
private function enterFrameListener(event:Event):void {
_clip.rotation += _rotationAcceleration;
_rotationAcceleration *= _dragFactor;
}
I think you're looking for this:
private function updateRotation():void
{
var _dx:Number = _player.x - stage.mouseX; // rotate _player mc to mouse
var _dx:Number = _player.y - stage.mouseY; // rotate _player mc to mouse
// which way to rotate
var rotateTo:Number = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (rotateTo > _player.rotation + 180) rotateTo -= 360;
if (rotateTo < _player.rotation - 180) rotateTo += 360;
// ease rotation
var _trueRotation:Number = (rotateTo - _player.rotation) / 5; // rotation speed 5
// update rotation
_player.rotation += _trueRotation;
}
public function getRadians(delta_x:Number, delta_y:Number):Number
{
var r:Number = Math.atan2(delta_y, delta_x);
if (delta_y < 0)
{
r += (2 * Math.PI);
}
return r;
}
public function getDegrees(radians:Number):Number
{
return Math.floor(radians/(Math.PI/180));
}
It actually does goes from 180 to -180 (contrary to what Reuben says), but higher/lower values get automatically corrected to that range (i.e. 181 is converted to -179)... one way to work with this is to use an auxiliary variable for your math (animation or whatever) and then assign it to the rotation, say:
myVar+=10;
myVar*=.97;
clip.rotation=myVar;