Wrote a function that calculates the coordinates of a sprite that moves in a circle.
Well, the formula is elementary
x = x0 + R * cos (t * a + a0)
y = y0 + R * sin (t * a + a0)
The function looks like this
public void pointDefinition(float delta)
{
sprite.setPosition(Gdx.graphics.getWidth()/2+(85*(float)Math.cos(i*delta)), Gdx.graphics.getHeight()/2+(85*(float)Math.sin(i*delta)));
i = i + 0.5;
}
I call it in render ()
In the end, everything works, but the sprite somehow nervously twitches.
Here is a video that demonstrates this.
video
The following content is sent to the delta variable.
pointDefinition(Math.min(Gdx.graphics.getDeltaTime(), 1 / 60f));
I can not understand the reason
You should increment i with delta instead of using delta as a parameter in the formula:
public void pointDefinition(float delta)
{
sprite.setPosition((Gdx.graphics.getWidth() / 2) + (85 * (float)Math.cos(i)), (Gdx.graphics.getHeight() / 2) + (85 * (float)Math.sin(i)));
i = i + delta;
}
After all, delta will have different values each time, which is what is causing your little icon to move back sometimes.
To understand what is happening, imagine these two iterations:
First iteration
i = 2
delta = 0.0025
In this case, i * delta will be 0.005.
Second iteration
i = 2.5
delta = 0.0017
In this case, i * delta will be 0.00425.
As you can see, the value of i * delta, which you are using as the parameter of Math.sin() and Math.cos(), decreased in the second iteration, causing your icon to jitter.
To keep the animation consistent, it is important to make sure the parameter you pass to these two functions (Math.sin() and Math.cos()) only increases with each iteration!
Related
The issue I have is that I'm attempting to add drag to an object in this basic physics simulation (Java [Processing]), but once I add the appropriate formula, it causes the objects velocity to increase drastically in the opposite direction. Of course the problem is that drag for some reason is being calculated too high but I'm not sure why thats happening as I'm using the real world equation.
void setup(){size(1280,720);}
class Circle{
float x,y,r,m,dx,dy,ax,ay,fx,fy;
Circle(float xPos, float yPos, float Radius, float Mass){
x = xPos;
y = yPos;
r = Radius;
m = Mass;
}
void ADD_DRAG(){
fx -= 0.5 * 1.225 * dx * dx * 0.5 * r * PI;
fy -= 0.5 * 1.225 * dy * dy * 0.5 * r * PI;
}
void update(){
ADD_DRAG();
ax = fx / m;
ay = fy / m;
dx += ax / frameRate;
dy += ay / frameRate;
x += dx / frameRate;
y += dy / frameRate;
}
}
Circle[] SceneObjects = {new Circle(50,50,20,20000),new Circle(50,50,2,20)};
void draw(){
background(51);
for (Circle c : SceneObjects){
c.update();
circle(c.x * 3,c.y * 3,c.r * 3);
}
}
void mouseClicked(){
if(SceneObjects[1].fx != 2000)
SceneObjects[1].fx = 2000;
else
SceneObjects[1].fx = 0;
}
This is the code, essentially there is a Circle class which stores the objects properties and then the forces applies are updated each draw loop. The mouseClicked void is just for testing by adding a force to the objects. All and any help is appreciated, thanks!
Maths I am Using:
Rearranged F=ma for ax = fx / m;
Acceleration * time = Speed for dx += ax / frameRate; (frameRate is 1/time)
Distance = Speed * time = for x += dx / frameRate; (same as above)
For drag im using this equation https://www.grc.nasa.gov/WWW/K-12/rocket/drageq.html with the constants eg air density etc added as seen.
There are a couple of things wrong here.
You haven't given us numbers (or a minimal complete example), but the vector algebra is off.
Yes, the acceleration is f = -kv2, and |v|2 = vx2 + vy2, but that doesn't mean that you can decompose f into fx=kvx2 and fy=kvy2. Not only is your magnitude off, but your acceleration is now not (in general) aligned with the motion; the path of your projectile will tend to curve toward a diagonal between the axes (e.g. x=y).
Also, your code always gives acceleration in the negative x and negative y directions. If your projectile happens to start out going that way, your version of air resistance will speed it up.
Finally, your time interval may simply be too large.
There is a better way. The differential equation is v' = -k v|v|, and the exact solution is v = (1/kt) z, (with appropriate choice of the starting time) where z is the unit direction vector. (I don't know how to put a caret over a letter.) This leads to v(t) = (1/t)v(t=1.0)
So you can either work out a fictional time t0 and calculate each new velocity using 1/(kt), or you can calculate the new velocity from the previous velocity: vn+1 =vn/(kd vn + 1), where d is the time interval. (And then of course you have to decompose v into vx and vy properly.)
If you're not familiar with vector algebra, this may seem confusing, but you can't get an air-resistance sim to work without learning the basics.
I've been struggling for some time now on how to correctly calculate the yaw angle from an IMU, but can't get it to work. I'm using the LSM9DS1, if that matters.
I already have proper values for roll and pitch. The value for yaw is also more or less correct until I start tilting the device. Therefore I have to implement some kind of tilt compensation.
I calculate the euler angles as follows:
double weight = 0.05f;
private void calculateEulerAngles() {
// Measured angle by the accelerometer
double rollXLMeasured = Math.atan2(this.accelerometer.getX(), this.accelerometer.getZ()) / 2 / Math.PI * 360;
double pitchXLMeasured = Math.atan2(this.accelerometer.getY() / 9.81f, this.accelerometer.getZ() / 9.81f) / 2 / Math.PI * 360;
// Adding a low pass filter
double rollXLFiltered = (1 - this.weight) * rollXLFilteredOld + this.weight * rollXLMeasured;
double pitchXLFiltered = (1 - this.weight) * pitchXLFilteredOld + this.weight * pitchXLMeasured;
this.rollXLFilteredOld = rollXLFiltered;
this.pitchXLFilteredOld = pitchXLFiltered;
// Calculating deltaTime
long time = System.nanoTime();
int difference = (int) ((time - this.deltaTime) / 1000000000);
this.deltaTime = time;
// Adding a complementary filter
this.roll = ((1 - this.weight) * (this.roll + this.gyroscope.getY() * difference)) + (this.weight * rollXLMeasured);
this.pitch = ((1 - this.weight) * (this.pitch - this.gyroscope.getX() * difference)) + (this.weight * pitchXLMeasured);
// Calculating yaw using the magnetometer and applying a low pass filter
double rollRadians = this.roll / 360 * (2 * Math.PI);
double pitchRadians = this.pitch / 360 * (2 * Math.PI);
double magnetometerXCompensated = (-this.magnetometer.getX() * Math.cos(rollRadians)) - (this.magnetometer.getY() * Math.sin(pitchRadians) *
Math.sin(rollRadians)) + (this.magnetometer.getZ() * Math.cos(pitchRadians) * Math.sin(rollRadians));
double magnetometerYCompensated = (this.magnetometer.getY() * Math.cos(pitchRadians)) + (this.magnetometer.getZ() * Math.sin(pitchRadians));
double yawMeasured = Math.atan2(magnetometerYCompensated, magnetometerXCompensated) / (2 * Math.PI) * 360;
double yawFiltered = (1 - this.weight) * yawFilteredOld + this.weight * yawMeasured;
this.yawFilteredOld = yawFiltered;
this.yaw = yawFiltered;
// Print roll, pitch and yaw for debug purposes
System.out.println(this.roll + ", " + this.pitch + ", " + this.yaw);
}
I don't include the whole code I use, since I think it's clear what the above code does and this is the part thats essential to the problem, I suppose.
And again, I get correct values, just not for yaw when I tilt the device. So there has to be an error concerning the math.
Do I have to do my calculations with the raw values, like the data thats inside the IMU, or use already processed data? For example this.accelerometer.getX() actually returns x_raw * 0.061f / 1000 * 9.81f with x_raw being the value stored inside the IMU and 0.061f being some coeffiecent. I basically copied the calculation from the Adafruit library, I'm not 100% sure why you have to multiply/divide those values though.
Also, you might have noticed that when I calculate the magnetometerXCompensated value I invert the x-axis. I do this, because the magnetometer axis aren't aligned with the acceleromter/gyroscope axis, so in order to align them I have to flip the x-axis.
Does anyone have an idea on how to solve this? I'm really tired of it not working properly, since I tried for quite a while now to solve it, but I'm not getting the results I wanted.
You can get all the equations from the next picture. The complimentary/Kalman filter is there in order to get less noise.
So i'm trying to make a program in java and i need to figure out how much I should add to x and y to make the player movement a constant speed at any angle. The information i have is 2 points, a starting point and an and and I need the char to move from a to b at a constant speed. I'm currently trying to figure out a bunch of different Math methods but I just cant get it right. Thanks in advance.
It's actually quite simple. You have points A (A.x, A.y) and B (B.x, B.y) and need the update for your character position.
Start by calculating the direction vector dir = B - A (subtract component-wise, such that dir.x = B.x - A.x; dir.y = B.y - A.y).
If you add this entire vector to your character's position, you will move it by sqrt(dir.x^2 + dir.y^2) (Pythagorean theorem). Hence, the speed will be: speed = sqrt(dir.x^2 + dir.y^2) / frameTime.
So if you want a constant speed, you have to find a multiple of the direction vector. This will be:
update = dir * speed / sqrt(dir.x^2 + dir.y^2) * frameTime
characterPosition = characterPosition + update
Don't bother with angle calculations. Vector arithmetic is usually way more robust and expressive.
Mathematically (I won't provide code, sorry), assuming you can move in any direction on a two dimensional plane, from the top of my head it could be something like this (taken from old school geometry):
Having a speed, let's say 20 pixels per second (it could also be any other unit you chose, including in-game distance)
Having a polling system, where you have 2 main variables: the last known coords for the char (point A: Ax, Ay), the time of the last known update.
Having the time of the current update.
Having the coords for the destination (point B: Bx, By).
Figure out the current position of your character, which could be done like this (without converting from cartesian to polar coord system):
Figure out angle of movement: find the deltas for X and Y (Dx=Bx-Ax and Dy=By-Ay respectively), and use tangent to find the angle where Angle = tan-1(Dy/Dx).
Figure out the travelled distance (TD) from last poll to current poll where TD = speed * elapsed time
Figure out the coords for the new position (Cx and Cy) using sine and cosine, where travelled X is Tx=TD*sin(Angle) and travelled Y is Ty=TD*cos(Angle).
Now add the travelled distances to your original coords, and you get the current position. Where Cx=Ax+Tx and Cy=Ay+Ty.
How "smooth" movement is depends highly on the quality of your polling and somehow also on rounding for small distances.
Since u didn't provide us code I can just guess what exactly you are trying.
So I'll start with some basics.
I guess you are not just trying to make a program
but the basic movement of an 2d based game engine.
However a constant moving is based of an update method
that reads the player input about 30 times while rendering.
Example from my Projects:
public void run() {
boolean isRunning = true;
long lastNanoTime = System.nanoTime(),nowNanoTime = System.nanoTime();
final double secondAsNano = 1000000000.0;
final double sixtiethOfSecondAsNano = secondAsNano / 30.0;
int delta = 1;
while(isRunning){
nowNanoTime = System.nanoTime();
if(delta * sixtiethOfSecondAsNano + lastNanoTime < nowNanoTime){
update();
delta++;
if(delta == 30){
delta = 1;
lastNanoTime = nowNanoTime;
}
}
render();
}
}
public update(){
if(Input.moveUP) setPlayerY(getPlayerY() - 0.2);
if(Input.moveDOWN) setPlayerY(getPlayerY() + 0.2);
if(Input.moveRIGHT) setPlayerX(getPlayerX() + 0.2);
if(Input.moveLEFT) setPlayerX(getPlayerX() - 0.2);
}
I just cut it down to be easy readable so it might not work correct but it should explain you how its basically done.
I ended up figuring this out almost an hour after posting this. Sorry that my question was so vague, what I was looking for was the math behind what i was trying to do not the code itself but thanks to people who answered. Here is the solution I came up with in code :
if (q.get(0)[0][0] > q.get(0)[1][0]) {
if(q.get(0)[0][0] == q.get(0)[1][0]) {
currentLocation[0] -= 5 * Math.cos((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
currentLocation[1] += 5 * Math.sin((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
}
else{
currentLocation[0] -= 5 * Math.cos((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
currentLocation[1] -= 5 * Math.sin((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
}
} else {
if(q.get(0)[0][0] == q.get(0)[1][0]) {
currentLocation[0] += 5 * Math.cos((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
currentLocation[1] -= 5 * Math.sin((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
}
else{
currentLocation[0] += 5 * Math.cos((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
currentLocation[1] += 5 * Math.sin((Math.atan(((double) q.get(0)[0][1] - (double) q.get(0)[1][1]) / ((double) q.get(0)[0][0] - (double) q.get(0)[1][0]))));
}
}
I figured out a way to get the result I wanted though I probably over complicated it. q is an ArrayList that holds 2d arrays that are 2x2 [a/b][x/y]. and currentLocation a 2 index array that's just [x/y]. The result is the affect I wanted where it draws a line in (X units) a pass from point a to b in any direction at the same speed. This question was poorly worded and i'm sorry for wasting peoples time.
What is the proper way to implement framerate-independent oscillation? I am using the LibGDX library which provides delta time for the update loop.
Currently, my sine wave pattern works as expected as long as the FPS is at a healthy 60 average (May have skewed slightly, due to slight gif-capture software lag):
http://i.stack.imgur.com/ZcKmX.gif
However, when the framerate drops, the pattern becomes skewed and acts rather strangely:
http://i.stack.imgur.com/tn82J.gif
Here is the sine wave method:
private void sineWaveDown(float speed, float amplitude, boolean mirror, float delta){
HitBox hitBox = getTransform().getHitBox();
int mirrored = 1;
if (mirror)
mirrored = -1;
Vector2 current = new Vector2(hitBox.x, hitBox.y);
current.y -= speed * delta;
current.x += MathUtils.sin(current.y * delta) * amplitude * mirrored;
hitBox.setPosition(current);
}
In this example, speed is 60 and amplitude is 2.
HitBox is derived from com.badlogic.gdx.math.Circle, and is used to logically represent the circles you see in the images above.
Edit: Question has been answered. Here is my working code:
private void sineWaveDown(float delta){
HitBox hitBox = getTransform().getHitBox();
int mirrored = 1;
if (config.mirrored)
mirrored = -1;
Vector2 current = new Vector2(hitBox.x, hitBox.y);
current.y -= config.speed * delta;
elapsedTime = (elapsedTime + delta) % (1/config.frequency);
float sinePosition = mirrored * config.amplitude * MathUtils.sin(MathUtils.PI2 * config.frequency * elapsedTime + config.phase);
current.x = config.spawnPosition.x + sinePosition;
hitBox.setPosition(current);
}
I haven't found a good way to do this without using elapsed time. You can "clean" the elapsed value with a modulus to avoid losing precision after a long time elapses.
elapsed = (elapsed + deltaTime) % (1/FREQUENCY);
float sinePosition = amplitude * MathUtils.sin(MathUtils.PI2 * FREQUENCY * elapsed + PHASE);
I'm not sure what you're doing basing the sine of x off of what y is, but you can adapt the above.
I am having an issue with gravity varying severely with frame rate shifts. When I run at 160 fps, my player jumps a few meters in the air then falls, but at about 10 fps, my player jumps half a meter then falls. My code for gravity is as follows:
public void fall(long delta) {
float increase = acceleration * ((delta) / 1000000000); //changes delta time (nanoseconds) to seconds
if(player.y + velocity + increase < -1.15f) {
if(velocity + inc < terminal_velocity) {
velocity += inc;
}
player.y += velocity;
}else{
player.y = -1.15f;
velocity = 0;
}
}
And where I call it:
while(!close_request) {
now = getTime();
int delta = getDelta(now);
player.fall(delta);
........other functions.........
}
I thought implementing the delta would keep the player from changing velocity too fast or too slow, but it actually made it a bit worse. I think this is due to the fact that as the time between frames increases, so does the increase in velocity which causes the player to fall abnormally fast. This comes from the fact that as the FPS increases, the player jumps much, much higher. Any ideas?
Your problem is in this line:
player.y += velocity;
which fails to take into account that velocity is "distance divided by time".
You're correctly modelling acceleration:
v = u + a * t // v = current velocity, a = acceleration, t = time
but not distance, which for small enough delta is:
delta_s = v * delta_t
You need to multiply velocity by delta before adding it to to the position.
You are not modeling the physics correctly. Assuming dt is small enough this will provide a "good enough" approximation.
curV // current velocity
accel // global acceleration constant
terminal // terminal velocity for object
dt // delta time in seconds
fall(dt):
deltaV = accel * dt // Change in velocity in a vacuum
newV = curV + deltaV // New velocity
if (newV < terminal) newV = terminal // Don't exceed downwards terminal velocity
y = y + dt * (curV+newV)/2 // New position
curV = newV // Save new velocity as current
It ignores the complexities of things like acceleration decreasing as you approach terminal velocity. The big difference between this and yours is the appearance of dt twice, once in calculating deltaV and then again in calculating the new vertical position.