I'm trying to get this Vector3
to accelerate when it's to the right and decelerate when it's not. This is my update method. Why doesn't it accelerate? It has a constant speed. I know you could just add -5 to vel.x
if it's to the left and +5 if it's to the right and then stop it when vel.x
is 0 but I'm trying to make this work. I really don't understand what it is I'm doing wrong.
In the class I have declared two Vector3
s (used in update
)
public void update(float delta) {
timePassed += Gdx.graphics.getDeltaTime(); //irrelevant
if (pos.x > Kiwi.WIDTH / 2)
vel.add(-5, 0, 0);
vel.x *= 0.8f;
vel.scl(delta);
pos.add(vel.x, 0, 0);
vel.scl(1 / delta);
}
public void update(float delta) {
if (pos.x > Kiwi.WIDTH / 2)
vel.add(-5, 0, 0);
vel.x *= 0.8f;
vel.scl(delta);
pos.add(vel.x, 0, 0);
vel.scl(1 / delta);
}
The update method is called once for every frame. So what happens with your code above is that you reduce the velocity by 20% every frame, meaning if you have 60FPS, you will reduce your velocity to 0.8^60 = 1.eE-6
or practically zero in one second when you're to the left half of the screen.
You also want to to accelerate when it is to the right... Accelerate in which direction? What you're doing now is that if the position is to the RIGHT half of the screen, then it accelerates to the LEFT meaning as soon as you get to the RIGHT half it moves back to the LEFT! Change -5
to +5
and then it will fly off because you're increasing speed by 5*60=300 px/s^2
. You need to scale the acceleration by the time delta.
Also you will need to scale the deacceleration by the time delta too. The divide by delta (1/delta
) doesn't make any sense either so try this:
public void update(float delta) {
if (pos.x > Kiwi.WIDTH / 2)
vel.add(5*delta, 0, 0); // Acceleration is now 5 px/s^2 to the right
vel.x -= vel.x*0.2f*delta; // Decay speed by 20% every second
pos.add(vel.x*delta, 0, 0); // Move position by speed.
}
Without more code to go on, all I can do is show you the correct way to do the calculations in the general case.
If you want to use a Euler's method for solving the motion ODEs this is how you do it:
// Object state
speed = ...; // Unit is [m/s]
position = ...; // Unit is [m]
// Inputs
frameDelta = ...; // Unit is [s]
acceleration = ...; // Unit is [m/s^2]
// Update step
speed += acceleration * frameDelta; // Unit [m/s^2 * s] = [m/s];
position += speed * frameDelta; // Unit [m/s * s] = [m]
If you want the speed to "decay" you can do it by adding a suitable deacceleration (or drag/wind resistance/friction whatever you want to call it):
decayRate = ...; // Unit is [m/(m*s^2) = 1/s^2] ((de)acceleration per meter)
acceleration -= speed * decayRate * frameDelta; // Unit is [m/s*1/s^2*s = m/s]
Note: that you do not store the acceleration, you compute it each frame from other inputs (keyboard, mouse, forces, collisions etc).
Note2: Euler's method is the easiest solver you can use to compute the position and speed from acceleration. It comes with some problems, it is not as accurate as for example Runge-Kutta and it can also exhibit some stability issues with the oscillation.
You know when you see something shaking like it's crazy when it is stuck in a game? Yeah, that's probably Euler's method becoming unstable.