Movieclip stops rotating after it's Box2D Body - actionscript-3

I have made a Car Game using Box2D [in Flash] and I have one remaining bug, which I cannot fix. I added graphics and put them on top of the Box2D body. Everything went as good as expected, but after X rotations the movie clips for the car-wheels, stop spinning. I do something like this wheelSprite.rotation = wheelBody.GetAngle() * 180 / Math.PI. I ran a separate program and I saw that, if you do X.rotation += variable and you increase the variable every frame, after ~30 000 (value of variable) the MovieClip stops rotating, so I reset it to 0 after ~28 000. What do I do? The wheelBody.GetAngle() keeps going up, and I need it to make it look real. How do I reset it?

I faced this problem some time ago. The solution was:
rotation = newRotation % 2*Math.PI;
Which means that rotation must be between 0 and 360 degrees (0 - 2*PI).

Remainder solve this issue:
yourMC.rotation = (yourMCbody.GetAngle() * 180 / Math.PI) % 360;
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/operators.html#modulo

Can't you use the SetAngle() function to set the angle to an equivalent angle?
ie: If the angle rotates over 360 degrees, set it back to 0?

The Box2D manual specifies that the rotation of bodies is unbounded and may get big after awhile and that you can you can reset it using SetAngle.
I use a while loop to calculate the normalized angle (you can apparently call modulo with a floating point operand but I don't know if that is bad for performance). This code normalizes the angle to 0 <= angle < 2pi but I've seen angles sometimes normalized to -pi <= angle < pi as well.
const 2PI:Number = Math.PI * 2;
var rotation:Number = wheelBody.GetAngle();
// normalize angle
while(rotation >= 2PI)
rotation -= 2PI;
while(rotation < 0)
rotation += 2PI;
// store the normalized angle back into Box2D body so it doesn't overflow (optional)
wheelBody.SetAngle(rotation);
// convert to degrees and set rotation of flash sprite
wheelSprite.rotation = rotation * 180 / Math.PI;
I haven't collected the code into a function but it would be easy to do so.

Related

Away3D HoverCamera Pan Angle - relative angle out of 360

I'm trying to work out the percentage of rotation of the HoverCamera but .panAngle() returns any number from -infinity to + inifinity, is there a way to work out the current angle out of 360 instead, no matter how times you rotate the camera?
For the mod operator in AS3 you need to check for negative values too:
angle = angle % 360;
if(angle<0) angle+=360;

How can I make a symbol point at the mouse?

I want to make a symbol rotate to point at the mouse. I'm using this function, but it doesn't work below the symbol's pivot. The inverse tan function has a range of 180 degrees right? So how can i get 360 degrees of movement?
Would I need to add an if statement to check the mouse position or is there a more elegant solution?
function panelTrack(){
angle = -180/Math.PI * Math.atan((mouseX - panel.x)/(mouseY - panel.y));
panel.rotation = angle;
trace(panel.rotation);
}
Math isn't my strong point - so perhaps someone else will provide a better answer, but to get all 4 quadrants, you need to use atan2.
angle = Math.atan2(mouseY - panel.y, mouseX - panel.x) * 180 / Math.PI;
I seem to recall it has to do with a check for a value of 0 (that Math.atan doesn't do).
const radiance:Number=180/Math.PI;
angle=-(Math.atan2(mouseX-panel.x, mouseY-panel.y))*radiance;
I used minus because usually the orientation is reverse when you don't add minus.
hope this helps.

Flash crash after matrix rotation

In my Flash program I have a step where I want to rotate a displayObject around the center of its container.
As some of you may know, Flash has a default center point for rotation which is the top left corner, and doesn't fit for my case.
To achieve my specific rotation, I do 3 successive transformations using matrices, like this:
public function rotateAroundCenter(object:DisplayObject, container:DisplayObject, angleDegrees:Number):void {
var matrix:Matrix = object.transform.matrix;
var rect:Rectangle = object.getBounds(container);
matrix.translate(-(rect.left + (rect.width / 2)), -(rect.top + (rect.height / 2)));
matrix.rotate((angleDegrees / 180) * Math.PI);
matrix.translate(rect.left + (rect.width / 2), rect.top + (rect.height / 2));
object.transform.matrix = matrix;
}
This bit of code does the trick and I can rotate displayObjects around their container center like I want to.
Problem: For some of these objects (couldn't find a discriminating factor between those who work and those who don't), any time I try to apply a 180 degrees rotation to put them upside down using previous bit of code, Flash unloads the SWF, which seems very much like a crash to me. I only get this crash for some of these objects, but if they crash once they crash anytime I apply a 180 degrees rotation using my function.
I suspect a memory leak, but then, if 90 or 270 degrees rotations work, why would this specific case make my whole program crash?
Any clues about this issue will be very appreciated. Thanks!

how to apply delta framerate to a dynamic y motion

i have recently added delta into my game. it works fine for wasd movement but not the gravity. I have 2 variables for gravity. yMotion (the dynamic motion to change the y axis by every tick) and gravity (the multiplier of the falling).
Each tick the yMotion goes down by gravity and then the y-axis is changed by yMotion. so if i set the yMotion to 2 for say, i will go up then it will fall.
my delta is the the ratio to to framerate. so if my rendering fps is a base of 60 and my actual fps is 30 my delta is 2. And if my rendering fps is 60 and my actual is 120 (somehow) then the delta is 0.5
well i need to add my delta framerate to my jumping and i cant get anything to work. heres my basic gravity/fall.
yMotion -= gravity; //gravity doesnt ever change.
if (!flying) { //if fly mode is on it skips this so the player doesnt go down
vector.y += yMotion;
}
heres where my jumping is at
if (jump && !inAir) { //in air is if the player isnt colliding with an object and jump is if the user if pressing space
yMotion = jumpingHeight*Game.delta; // Game.delta is the delta
}
to sum it up i need the delta to work. thanks!
Generally you have a velocity vector that you modify as you would in a constant-framerate game, and you multiply this velocity by delta to get the change in position.
Every frame, Velocity.X and Y = WASD_Input; (Constant, no delta multiplication), and Velocity.Z += Gravity * Delta; and finally Position += Velocity * Delta;.
(Note: I use Z as the up/down axis, as that follows the mathematical standard for 3D models.)

How do I apply gravity to my bouncing ball application?

I've written a fairly simple java application that allows you to drag your mouse and based on the length of the mouse drag you did, it will shoot a ball in that direction, bouncing off walls as it goes.
Here is a quick screenshot:
alt text http://img222.imageshack.us/img222/3179/ballbouncemf9.png
Each one of the circles on the screen is a Ball object. The balls movement is broken down into an x and y vector;
public class Ball {
public int xPos;
public int yPos;
public int xVector;
public int yVector;
public Ball(int xPos, int yPos, int xVector, int yVector) {
this.xPos = xPos;
this.yPos = yPos;
this.xVector = xVector;
this.yVector = yVector;
}
public void step()
{
posX += xVector;
posY += yVector;
checkCollisions();
}
public void checkCollisions()
{
// Check if we have collided with a wall
// If we have, take the negative of the appropriate vector
// Depending on which wall you hit
}
public void draw()
{
// draw our circle at it's position
}
}
This works great. All the balls bounce around and around from wall to wall.
However, I have decided that I want to be able to include the effects of gravity. I know that objects accelerate toward the earth at 9.8m/s but I don't directly know how this should translate into code. I realize that the yVector will be affected but my experimentation with this didn't have the desired effect I wanted.
Ideally, I would like to be able to add some gravity effect to this program and also allow the balls to bounce a few times before settling to the "ground."
How can I create this bouncing-elastic, gravity effect? How must I manipulate the speed vectors of the ball on each step? What must be done when it hits the "ground" so that I can allow it to bounce up again, but somewhat shorter then the previous time?
Any help is appreciated in pointing me in the right direction.
Thanks you for the comments everyone! It already is working great!
In my step() I am adding a gravity constant to my yVector like people suggested and this is my checkCollision():
public void checkCollision()
{
if (posX - radius < 0) // Left Wall?
{
posX = radius; // Place ball against edge
xVector = -(xVector * friction);
}
else if (posX + radius > rightBound) // Right Wall?
{
posX = rightBound - radius; // Place ball against edge
xVector = -(xVector * friction);
}
// Same for posY and yVector here.
}
However, the balls will continue to slide around/roll on the floor. I assume this is because I am simply taking a percentage (90%) of their vectors each bounce and it is never truly zero. Should I add in a check that if the xVector becomes a certain absolute value I should just change it to zero?
What you have to do is constantly subtract a small constant (something that represents your 9.8 m/s) from your yVector. When the ball is going down (yVector is already negative), this would make it go faster. When it's going up (yVector is positive) it would slow it down.
This would not account for friction, so the things should bounce pretty much for ever.
edit1:
To account for friction, whenever it reverses (and you reverse the sign), lower the absolute number a little. Like if it hits at yVector=-500, when you reverse the sign, make it +480 instead of +500. You should probably do the same thing to xVector to stop it from bouncing side-to-side.
edit2:
Also, if you want it to react to "air friction", reduce both vectors by a very small amount every adjustment.
edit3:
About the thing rolling around on the bottom forever--Depending on how high your numbers are, it could be one of two things. Either your numbers are large and it just seems to take forever to finish, or you are rounding and your Vectors are always 5 or something. (90% of 5 is 4.5, so it may round up to 5).
I'd print out a debug statement and see what the Vector numbers are like. If they go to somewhere around 5 and just stay there, then you can use a function that truncates your fraction to 4 instead of rounding back to 5. If it keeps on going down and eventually stops, then you might have to raise your friction coefficient.
If you can't find an easy "rounding" function, you could use (0.9 * Vector) - 1, subtracting 1 from your existing equation should do the same thing.
When the balls are all rolling around on the ground, yes, check to see if the velocity is below a certain minimum value and, if so, set it to zero. If you look at the physics behind this type of idealized motion and compare with what happens in the real world, you'll see that a single equation cannot be used to account for the fact that a real ball stops moving.
BTW, what you're doing is called the Euler method for numerical integration. It goes like this:
Start with the kinematic equations of motion:
x(t) = x0 + vx*t + 0.5*axt^2
y(t) = y0 + vyt + 0.5*ayt^2
vx(t) = vx0 + axt
vy(t) = vy0 + ay*t
Where x and y are position, vx and vy are velocity, ax and ay are acceleration, and t is time. x0, y0, vx0, and vy0 are the initial values.
This describes the motion of an object in the absence of any outside force.
Now apply gravity: ay = -9.8 m/s^2
To this point, there's no need to do anything tricky. We can solve for the position of each ball using this equation for any time.
Now add air friction: Since it's a spherical ball, we can assume it has a coefficient of friction c. There are typically two choices for how to model the air friction. It can be proportional to the velocity or to the square of velocity. Let's use the square:
ax = -cvx^2
ay = -cvy^2 - 9.8
Because the acceleration is now dependent on the velocity, which is not constant, we must integrate. This is bad, because there's no way to solve this by hand. We'll have to integrate numerically.
We take discrete time steps, dt. For Euler's method, we simply replace all occurances of t in the above equations with dt, and use the value from the previous timestep in place of the initial values, x0, y0, etc. So now our equations look like this (in pseudocode):
// Save previous values
xold = x;
yold = y;
vxold = vx;
vyold = vy;
// Update acceleration
ax = -cvxold^2;
ay = -cvyold^2 - 9.8;
// Update velocity
vx = vxold + axdt;
vy = vyold + aydt;
// Update position
x = xold + vxold*dt + 0.5*axdt^2;
y = yold + vyolddt + 0.5*ay*dt^2;
This is an approximation, so it won't be exactly correct, but it'll look OK. The problem is that for bigger timesteps, the error increases, so if we want to accurately model how a real ball would move, we'd have to use very tiny values for dt, which would cause problems with accuracy on a computer. To solve that, there are more complicated techniques. But if you just want to see behavior that looks like gravity and friction at the same time, then Euler's method is ok.
Every time slice you have to apply the effects of gravity by accelerating the ball in teh y downwards direction. As Bill K suggested, that's as simple as making a subtraction from your "yVector". When the ball hits the bottom, yVector = -yVector, so now it's moving upwards but still accelarating downwards. If you want to make the balls eventually stop bouncing, you need to make the collisions slightly inelastic, basically by removing some speed in the y-up direction, possibly by instead of "yVector = -yVector", make it "yVector = -0.9 * yVector".
public void step()
{
posX += xVector;
posY += yVector;
yVector += g //some constant representing 9.8
checkCollisions();
}
in checkCollisions(), you should invert and multiply yVector by a number between 0 and 1 when it bounces on the ground. This should give you the desired effect
It's a ballistic movement. So you got a linear movement on x-axis and an uniform accelerated movement on y-axis.
The basic idea is that the y-axis will follow the equation:
y = y0 + v0 * t + (0.5)*a*t^2
Or, in C code, for example:
float speed = 10.0f, acceleration = -9.8f, y = [whatever position];
y += speed*t + 0.5f*acceleration*t^2;
Where here I use tiem parametrization. But you could use Torricelli:
v = sqrt(v0^2 + 2*acceleration*(y-y0));
And, on this model, you must maintain the last values of v and y.
Finally, I've done something similar using the first model with dt (time's differential) being fixed at 1/60 second (60 FPS).
Well, both models give good real-like results, but sqrt(), for example, is expensive.
You really want to simulate what gravity does - all it does is create force that acts over time to change the velocity of an object. Every time you take a step, you change the velocity of your ball a little bit in order to "pull" it towards the bottom of the widget.
In order to deal with the no-friction / bouncing ball settles issue, you need to make the "ground" collision exert a different effect than just strict reflection - it should remove some amount of energy from the ball, making it bounce back at a smaller velocity after it hits the ground than it would otherwise.
Another thing that you generally want to do in these types of bouncy visualizations is give the ground some sideways friction as well, so that when it's hitting the ground all the time, it will eventually roll to a stop.
I agree with what "Bill K" said, and would add that if you want them to "settle" you will need to reduce the x and y vectors over time (apply resistance). This will have to be a very small amount at a time, so you may have to change your vectors from int to a floating point type, or only reduce them by 1 every few seconds.
What you want to do is change the values of xVector and yVector to simulate gravity and friction. This is really pretty simple to do. (Need to change all of your variables to floats. When it comes time to draw, just round the floats.)
In your step function, after updating the ball's position, you should do something like this:
yVector *= 0.95;
xVector *= 0.95;
yVector -= 2.0;
This scales the X and Y speed down slightly, allowing your balls to eventually stop moving, and then applies a constant downward "acceleration" to the Y value, which will accumulate faster than the "slowdown" and cause the balls to fall.
This is an approximation of what you really want to do. What you really want is to keep a vector representing the acceleration of your balls. Every step you would then dot product that vector with a constant gravity vector to slightly change the ball's acceleration. But I think that my be more complex than you want to get, unless you're looking for a more realistic physics simulation.
What must be done when it hits the
"ground" so that I can allow it to
bounce up again
If you assume a perfect collision (ie all the energy is conserved) all you have to do reverse the sign of one of the velocity scalar depending on which wall was hit.
For example if the ball hits the right or left walls revese the x scalar component and leave the the y scalar component the same:
this.xVector = -this.xVector;
If the ball hits the top or bottom walls reverse the y scalar component and leave the x scalar component the same:
this.yVector = -this.yVector;
but somewhat shorter then the previous
time?
In this scenario some of the energy will be lost in the collision with the wall so just add in a loss factor to take of some of the velocity each time the wall is hit:
double loss_factor = 0.99;
this.xVector = -(loss_factor * this.xVector);
this.yVector = -(loss_factor * this.yVector;