My very simple question is: how would I implement friction? Nothing I try seems to be working.
Oh, and speedX = 1.
Here's my code:
public void update() {
x += velocityX;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_RIGHT)
vx = xSpeed;
if (key == KeyEvent.VK_LEFT)
vx = -xSpeed;
}
public void KeyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_RIGHT)
vx = 0;
if (key == KeyEvent.VK_LEFT)
vx = 0;
}
Edit:
Now, once the player stops, he slows down (which is good), but he doesn't stop completely.
if (key == KeyEvent.VK_RIGHT) {
vx = 0.20 * vx;
if (vx < 0.2)
vx = 0;
playerAction = "still";
}
Friction is a force opposite to velocity. If you're dealing with forces at all, gravity or electric fields or rocket engines or something more mysterious, just add to the total force one more computed as velocity times some coefficient. You could get fancy and make its magnitude proportional to the speed squared or cubed, for different effects. Then compute velocity and position as usual.
If you're not dealing with forces and F=ma, but using a simpler kind of physics based only on velocity, which is common in video games, you need to decrease that velocity gradually. For each time step, compute new_velocity = 0.99 * current_velocity. Use whatever coefficient gives the right amount of slow-down. Again, you could get fancy and involve velocity squared in some way to alter the feel of the object's slowdown.
Often friction is assumed to be a constant force, considering the friction between two surfaces with a constant normal force, which would slowdown your objects velocity linearly. Other frictional forces like air drag often also have linear and quadratic terms.
If you would want to use friction between two surfaces you could do it like this:
if (vx > 0) vx += -friction / mass;
if (vx < 0) vx += friction / mass;
I also included the mass to suffice F = m * a for the acceleration. If there are also other forces acting on the object it would be a little more complicated since if the object has stopped moving it would only start moving again if the remaining forces exceed the frictional force.
By the way if you would like to make it more numerical correct, you could add a time step size into the simulation: vX += accelerationX * timeStep; and x += vX * timeStep;.
I have worked as a game AI engineer. That often involves making gameplay and physics. I recently had to answer this question myself. That's why I found this. Here is my solution. My problem may be a little different from yours but my challenge was to make it work no matter what framerate I was using. Here's my solution:
speed -= (speed * (1 - friction)) / fps;
friction is always a float between 0 and 1, 1 being no friction and 0 being essentially infinite friction. This makes sure the the right amount of friction will be applied proportional to frames per second.
If u, m and g in Ff=umg for the formula for the force of surface friction is constant, then a in F=ma would also be a constant number. Also because a = deltaV/s that means that the velocity equals acceleration times time (as=deltaV). This means that for every time interval the deltaV remains the same if Ff is the same. The change in speed only stops if it is not moving(v=0). So I think the best way to do this is to detect whether it's moving or not and apply the constant deltaV (for the opposite direction) and not apply it when v reaches zero.
Friction is a force that slows down any objects you have that are moving. So you'd need to have something like a background thread that constantly looks at the speed of all your objects, and slowly decrements each speed towards zero.
Related
The bounty expires in 5 days. Answers to this question are eligible for a +50 reputation bounty.
droid is looking for a more detailed answer to this question.
I’m (still) working on a small project controlling DMX-lights (using Art-Net).
At the moment I’m working on the “Movement-generator” and what I basically do is to use sine and cosine to calculate the DMX values (0-255) for the pan- and tilt-channel, like with this method:
public void runSineMovement() {
double degrees = x;
double radians = Math.toRadians(degrees);
double sine = Math.sin(radians);
double dmxValue = (int) ((sine * 127) + 127);
dmxValuesOBJ.setDmxValuesInArray(1, (int) dmxValue);
SendArtnet.SendArtnetNow();
x = x + 1;
if (x > 360) {
x = 1;
}
}
x = 1
I then have a ScheduledExecutorService that will call that method on a regular interval, like this:
int speed = 100;
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(SineMovement::runSineMovement, 0, 100000 * speed, TimeUnit.NANOSECONDS);
Above is working just fine, moving head (tilt-channel in this example) is moving perfectly. Now I want to use the “fine-channel”, that is, go from 8bit to 16bit (from 1 channel to 2 channels controlling the tilt-channel) so I can get smooth movement even at very slow speed. Remember, "fine-channel" have to go from 0 to 255 first and then "coarse-channel" can go to 1, then "fine-channel" from 0 to 255 and then "coarse-channel" to 2, and so on.
Earlier I build a movement-generator with “triangle-effect” where I looped from 0 to 65.536 and back to 0 and so on, and on every run I calculated the “coarse-channel” (counter/256) and the “fine-channel” (counter % 256) and that approach is working just fine.
Any ideas on how to approach this when using sine and cosine when generating the effect? Can I use the approach from the triangle-generator calculating “coarse” and “fine” using division and modulus?
EDIT: When thinking about it, I don't think the "fine" should have the form as a sine-wave, I mean, the "fine" will (if using sine) go very, very, fast, both up and down, and that will mess things up if the "coarse" is still going "up". I guess the correct is that the "fine" will always have the sawtooth-shape -> sawtooth from zero to max when coarse is going up, and sawtooth from max to zero when coarse is going down. Does that makes sense?
Thanks 😊
I've been trying to improve the behavior of one of the bosses in a top-down perspective shooter game that I'm working on, and one thing I haven't been able to quite implement correctly is plotting an intercept trajectory between the boss' "hook" projectile and the player according to the player's movement.
I've tried implementing it using the quadratic equation described here: https://stackoverflow.com/a/2249237/1205340
But I had pretty much the same results as this algorithm I came up with, which often will aim close to the player's expected position, but almost always misses unless the player is backpedaling away from the boss.
private float findPlayerIntercept(Pair<Float> playerPos, Pair<Float> playerVel, int delta) {
float hookSpeed = HOOK_THROW_SPEED * delta;
Pair<Float> hPos = new Pair<Float>(position);
Pair<Float> pPos = new Pair<Float>(playerPos);
// While the hook hasn't intercepted the player yet.
while(Calculate.Distance(position, hPos) < Calculate.Distance(position, pPos)) {
float toPlayer = Calculate.Hypotenuse(position, pPos);
// Move the player according to player velocity.
pPos.x += playerVel.x;
pPos.y += playerVel.y;
// Aim the hook at the new player position and move it in that direction.
hPos.x += ((float)Math.cos(toPlayer) * hookSpeed);
hPos.y += ((float)Math.sin(toPlayer) * hookSpeed);
}
// Calculate the theta value between Stitches and the hook's calculated intercept point.
return Calculate.Hypotenuse(position, hPos);
}
This method is supposed to return the theta (angle) for the boss to throw his hook in order to intercept the player according to the player's movement vector at the time the hook is thrown.
For reference, the Calculate.Hypotenuse method just uses atan2 to calculate the angle between two points. Calculate.Distance gets the distance in pixels between two positions.
Does anyone have any suggestions on how to improve this algorithm? Or a better way to approach it?
Your question is confusing (as you also talk about a quadratic equation). If your game is a 2d platform game in which the boss throws a hook with a given velocity with a certain angle with the floor, then I foud your solution:
By playing with the kinematic equations, you find that
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow class="MJX-TeXAtom-ORD">
<mo>θ</mo>
</mrow>
<mo>=</mo>
<mrow class="MJX-TeXAtom-ORD">
<mrow class="MJX-TeXAtom-ORD">
<mfrac>
<mrow>
<mi>arcsin</mi>
<mo><!-- --></mo>
<mo stretchy="false">(</mo>
<mi>d</mi>
<mi>g</mi>
<mo stretchy="false">)</mo>
</mrow>
<mrow class="MJX-TeXAtom-ORD">
<msup>
<mi>v</mi>
<mn>2</mn>
</msup>
</mrow>
</mfrac>
</mrow>
<mo>∗<!-- ∗ --></mo>
<mrow class="MJX-TeXAtom-ORD">
<mfrac>
<mn>1</mn>
<mrow class="MJX-TeXAtom-ORD">
<mn>2</mn>
</mrow>
</mfrac>
</mrow>
</mrow>
</math>
With d being the distance between the player and the boss, g being the gravitational constant and v being the initial velocity of the hook.
The reason that the hook keeps missing is that you always use a fixed timestep of 1 unit when integrating the player and hook's motion. This means that both objects' trajectories are a series of straight-line "jumps". 1 unit is far too large a timestep for there to be accurate results - if the speeds are high enough, there is no guarantee that the loop condition while(Calculate.Distance(position, hPos) < Calculate.Distance(position, pPos)) will even be hit.
The quadratic equation approach you mentioned was along the correct lines, but since you haven't understood the link, I will try to derive a similar method here.
Let's say the player's and hook's initial positions and velocities are p0, u and q0, v respectively (2D vectors). v's direction is the unknown desired quantity. Below is a diagram of the setup:
Applying the cosine rule:
Which root should be used, and does it always exist?
If the term inside the square root is negative, there is no real root for t - no solutions (the hook will never reach the player).
If both roots (or the single root) are negative, there is also no valid solution - the hook needs to be fired "backwards in time".
If only one root is positive, use it.
If both roots are positive, use the smaller one.
If the speeds are equal, i.e. v = u, then the solution is simply:
Again, reject if negative.
Once a value for t is known, the collision point and thus the velocity direction can be calculated:
Update: sample Java code:
private float findPlayerIntercept(Pair<Float> playerPos, Pair<Float> playerVel, int delta)
{
// calculate the speeds
float v = HOOK_THROW_SPEED * delta;
float u = Math.sqrt(playerVel.x * playerVel.x +
playerVel.y * playerVel.y);
// calculate square distance
float c = (position.x - playerPos.x) * (position.x - playerPos.x) +
(position.y - playerPos.y) * (position.y - playerPos.y);
// calculate first two quadratic coefficients
float a = v * v - u * u;
float b = playerVel.x * (position.x - playerPos.x) +
playerVel.y * (position.y - playerPos.y);
// collision time
float t = -1.0f; // invalid value
// if speeds are equal
if (Math.abs(a)) < EPSILON) // some small number, e.g. 1e-5f
t = c / (2.0f * b);
else {
// discriminant
b /= a;
float d = b * b + c / a;
// real roots exist
if (d > 0.0f) {
// if single root
if (Math.abs(d) < EPSILON)
t = b / a;
else {
// how many positive roots?
float e = Math.sqrt(d);
if (Math.abs(b) < e)
t = b + e;
else if (b > 0.0f)
t = b - e;
}
}
}
// check if a valid root has been found
if (t < 0.0f) {
// nope.
// throw an exception here?
// or otherwise change return value format
}
// compute components and return direction angle
float x = playerVel.x + (playerPos.x - position.x) / t;
float y = playerVel.y + (playerPos.y - position.y) / t;
return Math.atan2(y, x);
}
The jump size with these equations decreases as amount of updates per second goes down. With a delta value multiplying gravity force and amount that jumpspeed force decreases, as well as time elapsed being added by delta every iteration (the delta value is the amount of milliseconds passed since last update), one would think that it would work fine.
//d is delta
...
if(isFalling||isJumping){
elapsedTime +=d;
//the elapsed time is the total amount of time passed since one started jumping,
//so that's logical to add the amount of time since last update.
long tesquared = (long) Math.pow(elapsedTime, 2);
//amount of time elapsed squared.
jumpSpeed+=-0.0000005*elapsedTime*d;
//this is the amount that jumpspeed is taken down by every time.
if(jumpSpeed > 0){
isJumping = true;
} else {
isJumping = false;
}
double fGravity = 0.0000001*tesquared*d;
// this is the equation for gravity, the amount that the player goes down
yRend += jumpSpeed - fGravity;
//the amount it goes up, minus the amount it goes down.
xRend -= strafeSpeed;
oldyRend = yRend;
}
To start a jump, one adds jumpSpeed by whatever amount.
The problem is that when the amount of updates per second decreases, the jumps decrease in duration and magnitute. I'm fairly certain that the delta values here are fine, which means that the problem must be in the equations themselves.
I'm thinking that fGravity is overrunning jumpSpeed more quickly when the delta is larger.
So my question. If the problem really is in the equations themselves, what is the correct way to model the upward force of a player minus the downward gravity force other than
jumpSpeed+=-0.0000005*elapsedTime*d;
and
double fGravity = 0.0000001*tesquared*d;?
If the problem is in the delta value not being applied correctly, then what would be the correct way to apply it?
Players do not have an "upward force" (except at the very point at which they're jumping). Forces impart momentum generating velocity. Once in the air, they do feel a downward force (i.e. gravity) which causes them to decelerate, ultimately generating a negative velocity which returns them to the ground.
If the player starts jumping upwards with velocity u, then at time t after the start of that jump the classic equation for calculating the position is y = ut + 0.5 * at^2.
In this case, a is gravity (which is negative, if y is "up"), giving y = u * t - 0.5 * g * t ^ 2
Basically the equation of a jump are like that:
the gravity applies vertically and produce a constant force downward. So the vertical velocity is vy = vy0 - elapsedTime * g with g being the gravity constant and vy0 the initial velocity at the beginning of the jump.
You don't have to compute the elapsed time. Simply at every frame, you do this:
vy -= g * dt; // dt is the elapsed time since last frame
y += vy * dt;
x += vx * dt; // vx doesn't change in the jump
I have a for loop and inside that integer x will increase from 533 to 813. That means 280 increments. In side the same loop I want to decrease y's value from 300 to 200 when above happens. Which means when x is 533 y must be 300 and when x is 813 y must be 200. I know this can do by decrease y's value by 100/280 in each iteration. But both are integers.
Here are some code sample i used but it is not working.:
for(int i = 0; i < b.getSize(); i++) {
x = b.getCar(i).getPosX();
b.getCar(i).setPosX(++x);
if(x >= ((getWidth() / 2) - 140) && x < ((getWidth() / 2) + 140)){
y = b.getCar(i).getPosY();
y = (double)(y - (10.0f / 28.0f));
b.getCar(i).setPosY((int)y);
}
}
How can I possibly do this. Thanks!
There are two solutions, a simple and a complex one. The simple one:
y = yoff + (int)( (double) height * x / width )
where yoff = 300, height = -100, width = 813-533. Basically, you do a floating point operation and then you round the result.
Alternatively, the same can be done using pure integer math using the Bresenham line algorithm but that would take a lot more code.
y must be a double or a float and you need to round its value when you want to use it.
If you wanna do animation, just have a look at interpolators. You can abstract the logic of computing the values in between your extremas.
Basically at the beginning, you give your interpolator the start and end values.
Then, you give the interpolator a time and it gives you back the value between start and end for that time value.
Bonus: it will allow you to change your animation look & feel without touching the rest of the code. (what you are trying to do is in fact a linear interpolation, but it will look much nicer using a sine function for instance, or some other algorithm such as bouncing, quadratic, ...)
It looks like the logic for drawing a line. The Bresenham's algorithm should be the best option.
Keep a helping variable double dy that keeps track of the precise value for y. At each iteration, update dy using your formula, then update y by taking the rounded/truncated value of dy.
NOt sure what you like to do, but your current solution sufers from rounding of floats to integers. To avoid this, calculate with floats / doubles and convert them to integer whensetting positions.
I have this function to limit a rotation to the range from 0.0 to 360.0:
private float ClampRotation( float rotation ) {
while( rotation < 0.0f ) rotation += 360.0f;
while( rotation >= 360.0f ) rotation -= 360.0f;
return rotation;
}
This functions works great and it probably can't be more efficient, but I'm just wondering if there are a native Java function that can do the same?
The closest I get is Math.min/max, but it doesn't work as this. A rotation of -10.0 should output 350.0 and not 0.0 as min/max would do.
% (modulus) works on floating point values so use rotation % 360.0f (you will need to add 360.0 afterwards to negative numbers)
Use the modulus operator then account for values less than 0;
private float ClampRotation( float rotation ) {
rotation = rotation % 360f;
if (rotation < 0f) rotation += 360f;
return rotation;
}
it's just math.. you can do it like this:
private float ClampRotation( float rotation ) {
return rotation+360.0f*Math.ceil(-rotation/360.0f);
}
i'm pretty sure it's ok
You have the traditional implementation of wrapping angles which are less than an order of magnitude away the desired range.
Modulus is a bit weird for floating point - it returns negative for negative, so you still have to have a branch, and it involves a division, which is slower on some machines ( as in I've not found a machine where % is significantly less expensive than going round a loop with a couple of subtractions two or three times ).
If your values are within say -1000 to +1000, then your version is both clearer and faster. If your values are wider than that, go for a modulus based version. If it's very important, test both on your hardware with the value ranges you are going to use.