Object still moving even when the number of move is 0 - actionscript-3

I have an object called player and a virtual joystick controller called joystick and it contains its knob called knob and I've placed the joystick and the knob in a different movieclip.
I use a script to move the player as the amount of movement of the knob.
Here's the code :
function enterFrame(e:Event): void {
if (moving) {
// I move the knob as the touch point moves
// and the player as the knob moves
} else {
// I'm trying to slow down the knob movement to get back to its default position
// and slow down the player movement until it stopped
if (knob.x - joystick.x > 0) {
knob.x -= (knob.x - joystick.x)*.5;
player.x -= -(knob.x - joystick.x)*.9;
}
if (knob.x - joystick.x < 0) {
knob.x += -((knob.x - joystick.x)*.5);
player.x += (knob.x - joystick.x)*.9;
}
if (knob.y - joystick.y > 0) {
knob.y -= (knob.y - joystick.y)*.5;
player.y -= -((knob.y - joystick.y)*.9);
}
if (knob.y - joystick.y < 0) {
knob.y += -((knob.y - joystick.y)*.5);
player.y += (knob.y - joystick.y)*.9;
}
// Then I use trace to trace the player x position
trace(player.x);
}
}
And what I got is when I move the knob to left position and touch_end it, the slow down works but the player keep moving left by .01. But when I move the knob to another directions and touch_end it, the slow down works well until the player stopped.
Why could that happens?
Is there a way I can fix this?

This looks like a floating-point precision effect. If you start with knob.x at 1 and joystick.x at 0.5, you'll get:
knob.x joystick.x knob-joystick knob-joystick/2
1 0.5 0.5 0.25
0.75 0.5 0.25 0.125
0.625 0.5 0.125 0.0625
0.5625 0.5 0.0625 0.03125
0.53125 0.5 0.03125 0.015625
0.515625 0.5 0.015625 0.0078125
It's clearly trending towards zero, but there's a small remaining positive value when you calculate knob.x-joystick.x.
Note: Since your if statement that changes knob.x is in an EnterFrame listener, any joystick changes in response to user input will take longer than this to occur.
Instead of checking that your difference is > 0, check that it's greater than some small guard value, e.g.
if (knob.x - joystick.x > 0.01) {
knob.x -= (knob.x - joystick.x)*.5;
player.x -= -(knob.x - joystick.x)*.9;
}
//etc.
You might also add some guard code at the end of your listener:
if (knob.x > 0 && knob.x < 0.01) {
knob.x = 0;
}
//etc.

Well, after working around it, finally I did it!
I use Math.floor "trick" to force the -0.0249999999999828 (the last position when moving to left which make the player keep moving left even when I'm not control it anymore) to be change to 0.
Here's the code :
function enterFrame(e:Event): void {
.... // bla bla bla
} else {
if (knob.x > joystick.x) {
knob.x -= (knob.x - joystick.x)*.5;
player.x -= -((knob.x - joystick.x)*.9);
}
if (knob.x < joystick.x) {
knob.x += -(Math.floor((knob.x - joystick.x)*.5));
player.x += Math.floor((knob.x - joystick.x)*.9);
}
if (knob.y > joystick.y) {
knob.y -= (knob.y - joystick.y)*.5;
player.y -= -((knob.y - joystick.y)*.9);
}
if (knob.y < joystick.y) {
knob.y += -(Math.floor((knob.y - joystick.y)*.5));
player.y += Math.floor((knob.y - joystick.y)*.9);
}
}
}
I changed the if (knob.x - joystick.x > 0) (and all of kind of this) to if (knob.x > joystick.x) I think it's more efficient to detect where the knob is (right, left, up, down).
Or maybe you guys can find another way more efficient and more exact? It would help me

Related

Why can't I get a Symbol to move up and down towards the mouse in Actionscript 3

I want the Symbol(named player) to move on the y axis towards my mouse. The code I wrote only moves it up and i can't figure out why it wont follow my mouse and move down.
This is the section of code:
if (mouseY < player.y){
player.y -= playerYSpeed;
}
else if(mouseY > player.y)
{
player.Y += playerYSpeed;
}
player.Y += playerYSpeed;
you've capitalize the y property, it needs to be lower case.
player.y += playerYSpeed;

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)

Player velocity will never go to zero after collision?

My collision code is supposed to inverse the x velocity and reduce it to a third, then when the player is not pressing either "A" or "D" keys, the velocity should slowly reduce to zero, however, once the player collides the velocity only reduces to a small decimal between .25 and .70 (either positive or negative based on previous directions.)
//Function to determine what to do with keys
function KeyHandler():void{
//A Key Handlers
if(aKeyPressed == true){
if(Math.abs(_vx) < MaxSpeed){
_vx += -6;
}
}
//Player _vx somehow won't hit zero!!!
else if(aKeyPressed == false){
if(_vx < 0){
_vx += 1;
}
}
//D Key Handlers
if(dKeyPressed == true){
if(Math.abs(_vx) < MaxSpeed){
_vx += 6;
}
}
else if(dKeyPressed == false){
if( _vx > 0){
_vx += -1;
}
}
//W Key Handlers
if(wKeyPressed == true){
if(Jumped == false){
_vy = -15;
Jumped = true;
}
}
else if(wKeyPressed == false){
}
}
//Code for Right Collision
if(RightCollision){
while(RightCollision){
Player.x -= 0.1;
RightCollision = false;
if(_boundaries.hitTestPoint((Player.x + (Player.width / 2)), (Player.y - (Player.height / 2)), true)){RightCollision = true;}
}
_vx *= -.33
}
//Code for Left Collision
if(LeftCollision){
while(LeftCollision){
Player.x += 0.1;
LeftCollision = false;
if(_boundaries.hitTestPoint((Player.x - (Player.width / 2)), (Player.y - (Player.height / 2)), true)){LeftCollision = true;}
}
_vx *= -.33
}
Note that abs(-.25) + abs(.7) ~ 1.0
The collision sets the velocity to something that is not an integer (e.g. 2 * .33 ~ .7), so +/- 1 will skip past 0 without landing on it.
The simple fix is to keep the velocity an integer which can be done with Math.floor, for instance. (Account for the difference in +/- velocities: floor only moves numbers one direction.)
Happy coding.
Also, I am not sure how the int type works in AS3 work, which might be worth exploring.

Enemy rotates very strangely

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.

Animated MovieClip jumps around screen randomly

I have an animated MovieClip of a fly that spawns at a random location and moves across the screen by bouncing off the walls. But every time the animation starts over, it seems to "jump" to a random location. Here is the code I have for when it spawns:
private function beginClass(e:Event):void{
_root = MovieClip(root);
do {
xRandom = Math.floor(Math.random() * 500);
yRandom = Math.floor(Math.random() * 350);
this.x = xRandom;
this.y = yRandom;
} while (Math.abs(xRandom - mouseX) > 20 && Math.abs(yRandom - mouseY) > 20);
}
And this is the code for its movement:
//Bouncing the fly off of the walls
if(this.x >= stage.stageWidth-this.width){
//if the fly hits the right side
//of the screen, then bounce off
flyXSpeed *= -1;
}
if(this.x <= 0){
//if the fly hits the left side
//of the screen, then bounce off
flyXSpeed *= -1;
}
if(this.y >= stage.stageHeight-this.height){
//if the fly hits the bottom
//then bounce up
flyYSpeed *= -1;
}
if(this.y <= 0){
//if the fly hits the top
//then bounce down
flyYSpeed *= -1;
}
How do I fix it so that the fly continues moving in its appropriate path every time the animation starts over?
If I understand the problem correctly, when starting the animation you have to check if it has already been started before.
A simple boolean variable would do:
private var hasStarted:Boolean = false;
private function beginClass(e:Event):void{
_root = MovieClip(root);
if (!hasStarted) {
hasStarted = true;
do {
xRandom = Math.floor(Math.random() * 500);
yRandom = Math.floor(Math.random() * 350);
this.x = xRandom;
this.y = yRandom;
} while (Math.abs(xRandom - mouseX) > 20 && Math.abs(yRandom - mouseY) > 20);
}
}
This way it'll only execute the random placing code once.