as3 rotational drag / acceleration - actionscript-3

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;

Related

Actionscript 3.0 Mouse trail snake game logic

I am developing a game in actionscript 3.0 (adobe flash) similar to this https://www.tvokids.com/preschool/games/caterpillar-count. I have the code for dragging the head of the snake in the direction of the mouse. However, I do not know how do I add the body of the snake and make it follow the path of the head. Following is my code to drag movieclip in the direction of the mouse :
var _isActive = true;
var _moveSpeedMax:Number = 1000;
var _rotateSpeedMax:Number = 15;
var _decay:Number = .98;
var _destinationX:int = 150;
var _destinationY:int = 150;
var _dx:Number = 0;
var _dy:Number = 0;
var _vx:Number = 0;
var _vy:Number = 0;
var _trueRotation:Number = 0;
var _player;
var i;
createPlayer();
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
function createPlayer():void{
_player = new head();
_player.x = stage.stageWidth / 2;
_player.y = stage.stageHeight / 2;
stage.addChild(_player);
}
function onDown(e:MouseEvent):void{
_isActive = true;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
}
function onMove(e:MouseEvent):void{
updatePosition(_player);
updateRotation(_player);
}
function onUp(e:MouseEvent):void{
_isActive = false;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
}
function updatePosition(mc):void
{
// check if mouse is down
if (_isActive)
{
// update destination
_destinationX = stage.mouseX;
_destinationY = stage.mouseY;
// update velocity
_vx += (_destinationX - mc.x) / _moveSpeedMax;
_vy += (_destinationY - mc.y) / _moveSpeedMax;
}
else
{
// when mouse is not down, update velocity half of normal speed
_vx += (_destinationX - mc.x) / _moveSpeedMax * .25;
_vy += (_destinationY - mc.y) / _moveSpeedMax * .25;
}
// apply decay (drag)
_vx *= _decay;
_vy *= _decay;
// if close to target, slow down turn speed
if (getDistance(_dx, _dy) < 50)
{
_trueRotation *= .5;
}
// update position
mc.x += _vx;
mc.y += _vy;
}
function updateRotation(mc):void
{
// calculate rotation
_dx = mc.x - _destinationX;
_dy = mc.y - _destinationY;
// which way to rotate
var rotateTo:Number = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (rotateTo > mc.rotation + 180) rotateTo -= 360;
if (rotateTo < mc.rotation - 180) rotateTo += 360;
// ease rotation
_trueRotation = (rotateTo - mc.rotation) / _rotateSpeedMax;
// update rotation
mc.rotation += _trueRotation;
}
function getDistance(delta_x:Number, delta_y:Number):Number
{
return Math.sqrt((delta_x*delta_x)+(delta_y*delta_y));
}
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;
}
function getDegrees(radians:Number):Number
{
return Math.floor(radians/(Math.PI/180));
}
The script below will not miraculously work on its own, however it has all the logic you need, well-explained. It makes a chain of any length follow its head by certain rules. I used the same principle here many years ago: http://delimiter.ru/games/25-lines/alone.html
// This one will represent the Mouse position.
var Rat:Sprite = new Sprite;
// The ordered list of chain elements.
// It all starts with the Mouse.
var Snake:Array = [Rat];
// Call this one each time you want to
// extend the snake with the piece of tail.
function addTail(aPiece:DisplayObject):void
{
// Get the last snake element.
var lastPiece:DisplayObject = Snake[Snake.length - 1];
// Sync the tail coordinates.
aPiece.x = lastPiece.x;
aPiece.y = lastPiece.y;
// Add the new piece to the snake.
Snake.push(aPiece);
}
// Add the pre-defined head as the first element.
addTail(SnakeHead);
// Now start following the Mouse.
addEventListener(Event.ENTER_FRAME, onFrame);
// Fires every frame and adjusts the whole snake, if needed.
function onFrame(e:Event):void
{
// Sync the attractor point with the Mouse.
Rat.x = mouseX;
Rat.y = mouseY;
// Now lets make each piece follow the previous piece,
// one by one, starting from the head, down to the tail.
for (var i:int = 1; i < Snake.length; i++)
{
followOne(Snake[i - 1], Snake[i]);
}
}
function followOne(A:DisplayObject, B:DisplayObject):void
{
// Think of these values as of vector
// pointing from B position to A position.
var dx:Number = A.x - B.x;
var dy:Number = A.y - B.y;
// Figure out the distance between the given pieces.
var aDist:Number = Math.sqrt(dx * dx + dy * dy);
// Do nothing if pieces are closer than 20 px apart.
// You can change this value to make snake shorter or longer.
if (aDist < 20)
{
return;
}
// This literally means "eat one tenth of the distance
// between me and the previous piece". If you want pieces
// to follow each other with more vigor, reduce this value,
// if you want the whole snake to slither smoothly, increase it.
B.x += dx / 10;
B.y += dy / 10;
// Rotate the B piece so it would look right into A's direction.
// Well, unless your pieces are round and look all the same.
B.rotation = Math.atan2(dy, dx) * 180 / Math.PI;
}

Orbiting objects with equal spacing AS3

I have a monster that produces crystals. I want each crystal to orbit the monster, but when there is more than one crystal, I want them to orbit at an equal distance from each other. I've been trying to get this to work using two blocks of code I already have, but each one does something different and i need one block of code that does it all.
This block simply allows an object to orbit another:
orbitRadius = 110;
angle += orbitSpeed;
rad = (angle * (Math.PI / 180));
orbitX = monster.x + orbitRadius * Math.cos(rad);
orbitY = monster.y + orbitRadius * Math.sin(rad);
Here's a video of what it looks like:
https://www.youtube.com/watch?v=ACclpQBsjPo
This block of code arranges crystals around the monster based on the amount of crystals there are:
radius = 110;
angle = ((Math.PI * 2) / targetArray.length) * targetArray.indexOf(this);
orbitX = monster.x - (radius * Math.cos(angle));
orbitY = monster.y - (radius * Math.sin(angle));
And here's this video: https://www.youtube.com/watch?v=TY0mBHc2A8U
I do not know how to both space the crystals equally and make them circle around the monster at the same time. What needs to be done in order to achieve this?
1) Hierarchical way: put crystals into the same container so they spread equally (like you are doing on the second video) then rotate the container.
2) Math way.
Implementation:
public class Orbiter extends Sprite
{
// Pixels.
public var radius:Number = 100;
// Degrees per second.
public var speed:Number = 360;
public var items:Array;
public var lastTime:int;
public function start()
{
stop();
rotation = 0;
items = new Array;
lastTime = getTimer();
addEventListener(Event.ENTER_FRAME, onFrame);
}
public function stop():void
{
items = null;
removeEventListener(Event.ENTER_FRAME, onFrame);
}
public function onFrame(e:Event = null):void
{
var aTime:int = getTimer();
rotation += speed * (aTime - lastTime) / 1000;
lastTime = aTime;
for (var i:int = 0; i < items.length; i++)
{
// Get the object.
var anItem:DisplayObject = items[i];
// Get the object's designated position.
var aPos:Point = getPosition(i);
// Follow the position smoothly.
anItem.x += (aPos.x - anItem.x) / 10;
anItem.y += (aPos.y - anItem.y) / 10;
}
}
private function getPosition(index:int):Point
{
// Calculate the angle with regard to the present items amount.
var anAngle:Number = (rotation - 360 / items.length) * Math.PI / 180;
var result:Point = new Point;
// Figure the position with regard to (x,y) offset.
result.x = x + radius * Math.cos(anAngle);
result.y = y + radius * Math.sin(anAngle);
return result;
}
}
Usage:
var O:Orbiter = new Orbiter;
// Define the offset.
O.x = monster.x;
O.y = monster.y;
// Set radius and rotation speed.
O.radius = 110;
O.speed = 270;
// Enable the rotation processing.
O.start();
// Append items to orbit.
O.items.push(Crystal1);
O.items.push(Crystal2);
O.items.push(Crystal3);
You can change radius and speed any time, as well as add/remove items, thanks to motion smoothing that all will look equally fine.

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 :)

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.