I've been trying from hours to setup gravity and relate it to time or what we call frame independent bounce ball. I did everything correct I guess, and I tried to implement the system where height of ball would decrease after every bounce. I did not even start that, and my code is creating something absurd I don't understand why. Here's my code:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentFrame = System.currentTimeMillis();
dt = currentFrame - lastFrame;
dt = dt/1000;
lastFrame = currentFrame;
myFreakinRect.set(0,0, canvas.getWidth(), canvas.getHeight());
freakinRed.setColor(Color.RED);
freakinRed.setStyle(Paint.Style.FILL);
canvas.drawRect(myFreakinRect, freakinRed);
//
// o yuea
if(goingDown) {
//velocityY = Math.sqrt(100 + 2*gravity*(posY));
velocityY = gravity*(currentFrame - runTime);
} else {
velocityY = downV - gravity*(currentFrame - runTime);
}
if(posX > w - ballRadius*2) {
goingRight = false;
}
if(posX < 0) {
goingRight = true;
}
if(posY > h - ballRadius*2) {
//initY = initY - 0.25F;
//if(initY < 0) initY = 0;
Log.i("xxx", String.valueOf(initY));
runTime = currentFrame;
downV = velocityY;
goingDown = false;
}
if(velocityY <= 0) {
goingDown = true;
runTime = currentFrame;
}
if(goingDown) posY += velocityY*dt;
else posY -= velocityY*dt;
if(goingRight) posX += velocityX*dt;
else posX -= velocityX*dt;
canvas.drawText(String.valueOf(posX)+" "+String.valueOf(posY), 10, 10, new Paint());
canvas.drawBitmap(rBall, (float)posX, (float)posY, myFreakingFaintPaint);
invalidate();
}
Here's a GIF what is happening:
UPDATE:
Here's my updated code which is clean, understandable and works perfect:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentFrame = System.currentTimeMillis();
dt = currentFrame - lastFrame;
dt = dt/1000;
lastFrame = currentFrame;
velocityY = downV + gravity*(currentFrame - runTime);
posY += velocityY*dt;
posX += velocityX*dt;
if(posX > w - ballRadius*2 || posX < 0) {
velocityX = -velocityX;
}
if(posY >= h - ballRadius*2) {
posY = h - ballRadius*2 - 2;
runTime = currentFrame;
downV = -0.8*velocityY;
}
canvas.drawBitmap(rBall, (float)posX, (float)posY, null);
invalidate();
}
Here ...
if(goingDown) {
//velocityY = Math.sqrt(100 + 2*gravity*(posY));
velocityY = gravity*(currentFrame - runTime);
} else {
velocityY = downV - gravity*(currentFrame - runTime);
}
... you update the velocity (speed, actually) assuming that the ball will not bounce during this frame.
Then here ...
if(posY > h - ballRadius*2) {
//initY = initY - 0.25F;
//if(initY < 0) initY = 0;
Log.i("xxx", String.valueOf(initY));
runTime = currentFrame;
downV = velocityY;
goingDown = false;
}
... you have not yet updated posY, so you are determining whether the ball hit the floor as a result of the previous update. If it did, you reverse the direction of motion, but keep the speed you already computed for this frame. As a result, each time the ball bounces, its initial upward speed is one frame's worth of acceleration greater than the speed it was traveling when it hit the floor.
You have a similar effect at the top of the ball's motion, but it's smaller because the speed is small there.
There are a couple of ways you might solve this problem. The simplest is probably to perform the bounce check after the position update instead of before.
Additional notes:
use the signs of your X and Y speeds instead of separate direction-of-motion flags (thus making the names velocityY etc. accurate). Your code will be simpler, and you'll need to handle only one change of vertical direction, not two, because the equations of motion will handle the other automatically.
you have a bit of a precision problem because you assume that the ball travels in the same direction for a whole frame. This may become noticeable if you allow the ball to reach high speeds: it will appear to penetrate the floor before bouncing back up.
this computation is suspicious: dt = dt/1000. Since dt seems to be computed from System.currentTimeMillis(), I am inclined to guess that it, too, has type long. In that case, you are performing an integer division and thereby losing precision.
In general:
Split up into model and view. In that case the rendering still runs fine, because the calculations are pretty light-weight, but you shouldn't run code inside the rendering-routine that isn't directly related to painting something.
Next point:
Stay as close to reality as possible, if you simulate physics. You can always optimize afterwards, but first make sure your code is actually doing what it's supposed to do. I'm currently playing a bit around with projectile-motion, so I've got a basic idea of what the code is supposed to do. I've been attempting to understand yout code for 10 mins so far. Interim result: I'm confused and don't quite get it.
My suggestion:
Start off with clearer code and try to stick as close to physical rules as possible. This code isn't optimized as far as it could be, but it's readable, understandable and simulates close enough to the real life. That makes it a lot simpler to debug:
final double GRAVITY = -9.81;
final double BALL_ELASTICITY = 0.95;
double vx, vy;
double x, y;
//dt is delta-time in seconds!!!
void simulateBall(double dt){
//calculate when the ball will touch the floor the next time
double next_floor_touch = (-vy + Math.sqrt(vy * vy - 2 * GRAVITY * y)) / GRAVITY;
double after_floor_touch = dt - next_floor_touch;
boolean touches_floor = (next_floor_touch <= dt);
//calculate new y
if(touches_floor){
//predict the speed the ball will have, after it bounces from the floor
double vy_at_floor = vy + GRAVITY * next_floor_touch;
double vy_from_floor = vy_at_floor * (-1) * BALL_ELASTICITY;
//predict y starting from the floor at t = next_floor_touch until dt
y = 0 + vy_from_floor * after_floor_touch + 0.5 * GRAVITY * after_floor_touch * after_floor_touch;
}else{
//uniform acceleration
y = y + vy * dt + 0.5 * GRAVITY * dt * dt;
}
//calculate vy
if(touches_floor){
//see above
double vy_after_floor = (vy + GRAVITY * next_floor_touch) * (-1) * BALL_ELASTICITY;
vy = vy_after_floor + GRAVITY * after_floor_touch;
}else{
vy = vy + GRAVITY * dt;
}
... //that's already the hardest part
}
This uses the quadratic equation to predict when the ball will hit the floor and uniform acceleration to calculate the position from a given position, speed and acceleration. Unless I've made any mistakes in my calculation (this code is not tested), this should be physically precise. BALL_ELASTICITY represents how much of the speed is left, after the ball hits the floor. That's not physically precise - might be, IDK - , but should do for this purpose.
Related
When working with creating games in Libgdx, I have not been using the physics engine as I dont have too many moving parts in the game. So, to have objects fall from the top of the screen to the bottom, I used what the documentation had, something like this:
projectile.y -= 200 * Gdx.graphics.getDeltaTime();
That example will make said projectile go down at 200 pixels per second (I believe). What I am trying to do is make it so after two seconds, the projectile will transition from negative 200 per second, to positive 200 per second. I've tried using loops and Thread.sleep, but that will just freeze the entire game and unfreeze with the projectiles going the other way. Any ideas?
Linear interpolation.
All you need to do is determine the start point: x1 = -200
Determine the end point: x2 = 200
Determine the amount of seconds that it takes to reach the end point: tmax = 2.0 sec
Determine the difference that you need to add to the original to reach the end point: v = (x2-x1) = (200 - (-200)) = 400
Use the linear interpolation function: x1 + t*v = x2 where t e [0...1] //must be normalized to 0..1 interval
Thus at t = 0, the value is at x1 + 0 = x1; and at t = (tn/tmax) [which is 1], the value is at x1 + v = x2.
So all you need is a timer from 0 to 2 and the following equation:
float interpolationTimer = 0.0f;
final float interpolationTimerMax = 2.0f;
public void render()
{
float delta = Gdx.graphics.getDeltaTime();
interpolationTimer += delta;
if(interpolationTimer > interpolationTimerMax )
{
interpolationTimer = interpolationTimerMax ;
}
velocity.y = -200 + (interpolationTimer/interpolationTimerMax) * (400); //x1 + t*v = x2
projectile.y -= velocity.y * delta;
}
To get a change in direction of y, you need a polynomial function of x. For a single direction change, use a binomial; try something like
projectile.y = projectile.y
- 200 * Gdx.graphics.getDeltaTime()
+ 20 * Math.pow(Gdx.graphics.getDeltaTime(), 2);
If you are looking for linear interpolation of the speeds, just keep track of time.
float timeElapsed = 0.0f;
void render() {
timeElapsed += Gdx.graphics.getDeltaTime();
projectile.y -= 200.0f * (1.0f - timeElapsed);
}
Be sure to stop after timeElapsed has reached 2 seconds (that's if(timeElapsed < 2.0f)). Time elapsed variable will start at 0.0f and will slowly increment. Until it reaches 1.0f, projectile.y will get substracted from. However, as soon as time elapsed is higher than 1.0f, projectile.y will get added to.
I am trying to get my bullets to fire towards (input coords) at a constant speed.
So far I was able to get it to shoot at the direction but the farther I click (touch, android game) the faster the bullet goes. I have tried different methods by scaling but failed miserably, I have started coding just a month ago and using this as a project to increase my knowledge of how things work before I work on a full game but having too much trouble with this.
This is what I have been using to get the bullet to move towards the direction I want it to, the codes with // in front were other samples I got while browsing through the internet in hopes of getting what I wanted. I have thought of not using velocity to set the direction, but I have no clue of another method for this.
EDIT: All in short, I cannot get all the bullets to move in the same speed, farther I click, higher velocity bullet has.
Any help guys? Thanks a bunch
Player Class :
public void update(float delta) {
if (Gdx.input.isTouched()) {
if (System.currentTimeMillis() - lastShot >= FIRE_RATE) {
bullets.add(new Bullet(position.x + 6,position.y + 6,4,4,Gdx.input.getX() / 2,Gdx.input.getY() / 2));
lastShot = System.currentTimeMillis();
}
}
for (int i=0;i<bullets.size();i++) {
bullets.get(i).update(delta);
}
}
Bullet Class :
public Bullet(float x, float y, int width, int height, float targetX, float targetY) {
this.width = width;
this.height = height;
position = new Vector2( x , y );
velocity = new Vector2( 0 , 0 );
velocity.set(targetX - position.x,targetY - position.y);
//velocity.set(targetX - position.x, targetY - position.y).nor().scl(Math.min(position.dst(targetX, targetY), speedMax));
}
public void update(float deltaTime) {
//position.add(position.x + speedMax * deltaTime * ax,position.y + speedMax * deltaTime * ay);
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
//velocity.scl(1 - (0.98f * deltaTime));
// Linear dampening, otherwise the ball will keep going at the original velocity forever
}
Well, normalizing vectors should be rather straightforward. Take your components, square them, and add them together (pythagorean theorem) and then divide each component by this result. I.e. vX = (targetX - position.x)/Math.sqrt(((targetX - position.x) * (targetX - position.x)) + ((targetY - position.y) *(targetY - position.y )))
Then you can multiply vX by some constant, and do the same for a vY and then set your velocity.
Since in the digital world a real collision almost never happens, we will always have a situation where the "colliding" circle overlaps the rectangle.
How to put back the circle in the situation where it collides perfectly with the rectangle without overlap?
Suppose that the rectangle is stopped (null velocity) and axis-aligned.
I would solve this problem with a posteriori approach (in two dimensions).
In short I have to solve this equation for t:
Where:
is a number that answers to the question: how many frames ago did the
collision happen perfectly?
is the radius of the circle.
is the center of the circle
is its velocity.
and are functions that return the x and y coordinates of
the point where the circle and the rectangle collide (when the circle is
at position, that is in the position in which perfectly collide with the rectangle).
Recently I solved a similar problem for collisions between circles, but now I don't know the law of the functions A and B.
After years of staring at this problem, and never coming up with a perfect solution, I've finally done it!
It's pretty much a straight forward algorithm, no need for looping and approximations.
This is how it works at a higher level:
Calculate intersection times with each side's plane IF the path from current point to future point crosses that plane.
Check each side's quadrant for single-side intersection, return the intersection.
Determine the corner that the circle is colliding with.
Solve the triangle between the current point, the corner, and the intersecting center (radius away from the corner).
Calculate time, normal, and intersection center.
And now to the gory details!
The input to the function is bounds (which has a left, top, right, bottom) and a current point (start) and a future point (end).
The output is a class called Intersection which has x, y, time, nx, and ny.
{x, y} is the center of the circle at intersection time.
time is a value from 0 to 1 where 0 is at start and 1 is at end
{nx, ny} is the normal, used for reflecting the velocity to determine the new velocity of the circle
We start off with caching variables we use often:
float L = bounds.left;
float T = bounds.top;
float R = bounds.right;
float B = bounds.bottom;
float dx = end.x - start.x;
float dy = end.y - start.y;
And calculating intersection times with each side's plane (if the vector between start and end pass over that plane):
float ltime = Float.MAX_VALUE;
float rtime = Float.MAX_VALUE;
float ttime = Float.MAX_VALUE;
float btime = Float.MAX_VALUE;
if (start.x - radius < L && end.x + radius > L) {
ltime = ((L - radius) - start.x) / dx;
}
if (start.x + radius > R && end.x - radius < R) {
rtime = (start.x - (R + radius)) / -dx;
}
if (start.y - radius < T && end.y + radius > T) {
ttime = ((T - radius) - start.y) / dy;
}
if (start.y + radius > B && end.y - radius < B) {
btime = (start.y - (B + radius)) / -dy;
}
Now we try to see if it's strictly a side intersection (and not corner). If the point of collision lies on the side then return the intersection:
if (ltime >= 0.0f && ltime <= 1.0f) {
float ly = dy * ltime + start.y;
if (ly >= T && ly <= B) {
return new Intersection( dx * ltime + start.x, ly, ltime, -1, 0 );
}
}
else if (rtime >= 0.0f && rtime <= 1.0f) {
float ry = dy * rtime + start.y;
if (ry >= T && ry <= B) {
return new Intersection( dx * rtime + start.x, ry, rtime, 1, 0 );
}
}
if (ttime >= 0.0f && ttime <= 1.0f) {
float tx = dx * ttime + start.x;
if (tx >= L && tx <= R) {
return new Intersection( tx, dy * ttime + start.y, ttime, 0, -1 );
}
}
else if (btime >= 0.0f && btime <= 1.0f) {
float bx = dx * btime + start.x;
if (bx >= L && bx <= R) {
return new Intersection( bx, dy * btime + start.y, btime, 0, 1 );
}
}
We've gotten this far so we know either there's no intersection, or it's collided with a corner. We need to determine the corner:
float cornerX = Float.MAX_VALUE;
float cornerY = Float.MAX_VALUE;
if (ltime != Float.MAX_VALUE) {
cornerX = L;
} else if (rtime != Float.MAX_VALUE) {
cornerX = R;
}
if (ttime != Float.MAX_VALUE) {
cornerY = T;
} else if (btime != Float.MAX_VALUE) {
cornerY = B;
}
// Account for the times where we don't pass over a side but we do hit it's corner
if (cornerX != Float.MAX_VALUE && cornerY == Float.MAX_VALUE) {
cornerY = (dy > 0.0f ? B : T);
}
if (cornerY != Float.MAX_VALUE && cornerX == Float.MAX_VALUE) {
cornerX = (dx > 0.0f ? R : L);
}
Now we have enough information to solve for the triangle. This uses the distance formula, finding the angle between two vectors, and the law of sines (twice):
double inverseRadius = 1.0 / radius;
double lineLength = Math.sqrt( dx * dx + dy * dy );
double cornerdx = cornerX - start.x;
double cornerdy = cornerY - start.y;
double cornerdist = Math.sqrt( cornerdx * cornerdx + cornerdy * cornerdy );
double innerAngle = Math.acos( (cornerdx * dx + cornerdy * dy) / (lineLength * cornerdist) );
double innerAngleSin = Math.sin( innerAngle );
double angle1Sin = innerAngleSin * cornerdist * inverseRadius;
// The angle is too large, there cannot be an intersection
if (Math.abs( angle1Sin ) > 1.0f) {
return null;
}
double angle1 = Math.PI - Math.asin( angle1Sin );
double angle2 = Math.PI - innerAngle - angle1;
double intersectionDistance = radius * Math.sin( angle2 ) / innerAngleSin;
Now that we solved for all sides and angles, we can determine time and everything else:
// Solve for time
float time = (float)(intersectionDistance / lineLength);
// If time is outside the boundaries, return null. This algorithm can
// return a negative time which indicates the previous intersection.
if (time > 1.0f || time < 0.0f) {
return null;
}
// Solve the intersection and normal
float ix = time * dx + start.x;
float iy = time * dy + start.y;
float nx = (float)((ix - cornerX) * inverseRadius);
float ny = (float)((iy - cornerY) * inverseRadius);
return new Intersection( ix, iy, time, nx, ny );
Woo! That was fun... this has plenty of room for improvements as far as efficiency goes. You could reorder the side intersection checking to escape as early as possible while making as few calculations as possible.
I was hoping there would be a way to do it without trigonometric functions, but I had to give in!
Here's an example of me calling it and using it to calculate the new position of the circle using the normal to reflect and the intersection time to calculate the magnitude of reflection:
Intersection inter = handleIntersection( bounds, start, end, radius );
if (inter != null)
{
// Project Future Position
float remainingTime = 1.0f - inter.time;
float dx = end.x - start.x;
float dy = end.y - start.y;
float dot = dx * inter.nx + dy * inter.ny;
float ndx = dx - 2 * dot * inter.nx;
float ndy = dy - 2 * dot * inter.ny;
float newx = inter.x + ndx * remainingTime;
float newy = inter.y + ndy * remainingTime;
// new circle position = {newx, newy}
}
And I've posted the full code on pastebin with a completely interactive example where you can plot the starting and ending points and it shows you the time and resulting bounce off of the rectangle.
If you want to get it running right away you'll have to download code from my blog, otherwise stick it in your own Java2D application.
EDIT:
I've modified the code in pastebin to also include the collision point, and also made some speed improvements.
EDIT:
You can modify this for a rotating rectangle by using that rectangle's angle to un-rotate the rectangle with the circle start and end points. You'll perform the intersection check and then rotate the resulting points and normals.
EDIT:
I modified the code on pastebin to exit early if the bounding volume of the path of the circle does not intersect with the rectangle.
Finding the moment of contact isn't too hard:
You need the position of the circle and rectangle at the timestep before the collision (B) and the timestep after (A). Calculate the distance from the center of the circle to the line of the rectangle it collides with at times A and B (ie, a common formula for a distance from a point to a line), and then the time of collision is:
tC = dt*(dB-R)/(dA+dB),
where tC is the time of collision, dt is the timestep, dB is the distance to line before the collision, dA is the distance after the collision, and R is the radius of the circle.
This assumes everything is locally linear, that is, that your timesteps are reasonably small, and so that the velocity, etc, don't change much in the timestep where you calculate the collision. This is, after all, the point of timesteps: in that with a small enough timestep, non-linear problems are locally linear. In the equation above I take advantage of that: dB-R is the distance from the circle to the line, and dA+dB is the total distance moved, so this question just equates the distance ratio to the time ratio assuming everything is approximately linear within the timestep. (Of course, at the moment of collision the linear approximation isn't its best, but to find the moment of collision, the question is whether it's linear within a timestep up to to moment of collision.)
It's a non-linear problem, right?
You take a time step and move the ball by its displacement calculated using velocity at the start of the step. If you find overlap, reduce the step size and recalculate til convergence.
Are you assuming that the balls and rectangles are both rigid, no deformation? Frictionless contact? How will you handle the motion of the ball after contact is made? Are you transforming to a coordinate system of the contact (normal + tangential), calculating, then transforming back?
It's not a trivial problem.
Maybe you should look into a physics engine, like Box2D, rather than coding it yourself.
Top of the morning to ye people on various surfaces of earth.
The problem: How to get the angle of direction from the arrow keys.
Preamble: The standard way to move in a basic top-down game is to add to x and/or y from within an update method, depending on the direction.
if (moveUp) playerY -= delta * speed;
if (moveDown) playerY += delta * speed;
if (moveLeft) playerX -= delta * speed;
if (moveRight) playerX += delta * speed;
This is elegant for 4-direction movement (I believe) because no matter what key combinations are pressed, the direction of movement will be consistent. Eg pressing up-down-left will move left, as up and down cancel out. But when moving diagonally, the steps will be too large. If speed is 20, moving left will move left by 20 per second, up will move up by 20 per second. But moving up-left will move by a little over 28.24 per second.
The solution here is to use cos and sin to get the new x and y, which is easy once you know the angle:
playerX += Math.cos(Math.toRadians(angle)) * delta * speed;
playerY -= Math.sin(Math.toRadians(angle)) * delta * speed; //y is inverted
But, for me at least, this raises a new problem: what's the angle? In my KeyListener I'm currently setting/clearing booleans for each arrow key. I can use a bulky set of if statements:
if (moveUp) angle = 90;
if (moveDown) angle = 270;
if (moveRight) angle = 0;
if (moveLeft) angle = 180;
if (moveUp && moveLeft) angle = 135;
if (moveUp && moveRight) angle = 45;
if (moveDown && moveLeft) angle = 225;
if (moveDown && moveRight) angle = 315;
//...etc... for all combinations
For the life of me, I cannot find a sexy way to get the movement angle from what direction keys are pressed down. It strikes me like this should be a common problem, game design 101, but intense googling hasn't led me to anything (made harder by the fact that it's difficult to put the problem into words). In all instances of examples, either they just retained the diagonal-is-faster functionality (as with my first snippet), or know the angle ahead of time (ie. move towards the mouse), or are 2D side scrollers.
Surely there's a sexy mathy way (or something) to work it out in a few lines? Or am I approaching this completely wrong?
Edit: Post-answer code (as posted by korona below):
double x=0, y=0;
if (moveLeft) x -= 1;
if (moveRight) x += 1;
if (moveUp) y -= 1;
if (moveDown) y += 1;
double length = Math.sqrt(x * x + y * y);
if (length != 0) {
x /= length;
y /= length;
x *= delta*speed;
y *= delta*speed;
playerX += x;
playerY += y;
}
Use a 2-dimensional vector. Something like this:
movement = new Vector2D();
if (moveLeft) movement.x += 1;
if (moveRight) movement.x -= 1;
if (moveUp) movement.y -= 1;
if (moveDown) movement.y += 1;
movement.normalize(); // Caps the movement vector at a length of one, even when it's at an odd angle
movement *= desiredMovementSpeed * frameDeltaTime; // Plug in suitable values here
// FIXME: Do some collision detection here, probably
playerX += movement.x;
playerY += movement.y;
I assume there's a suitable 2D vector class available for you. If not, normalizing a vector is as easy as dividing all of its components by its length, as such:
length = sqrt(this.x * this.x + this.y * this.y);
this.x /= length;
this.y /= length;
I have created a projectile motion simulation in Java with a user interface.
The program allows the user to enter in initial values to calculate the projectile of the object. I don't have anything currently set up to draw the projectile onto the screen.
I have a separate spring worker thread handling the simulation code in the background.
I also have added in collision detection so that when the object hits the ground it will bounce and continue doing so until the loop exits.
The equations that I have in place are not correct for what I am trying to achieve.
With the following initial conditions, here is what a plot of the outputted data yields:
Initial Conditions:
Angle: 30 degrees;
Initial Speed 8.66 m/s;
Height: 50 m;
Elasticity of object: .5 coefficient of restitution in the y direction;
Acceleration: -9.8 m/s^2;
No acceleration in the x direction
It appears that once the simulation begins, y just gets bigger and bigger, so the loop will never exit by itself.
Here is the code:
//This class will handle all time consuming activities
class Simulation extends SwingWorker<Void, Void>
{
//Execute time consuming task
protected Void doInBackground() throws Exception
{
FileWriter fstream = new FileWriter("output.txt");
BufferedWriter out = new BufferedWriter(fstream);
double angle = Double.valueOf(angleText.getText());
double radians = angle * (Math.PI/180);
double vel = Double.valueOf(speedText.getText());
double mass = Double.valueOf(massText.getText());
double y = Double.valueOf(heightText.getText());
double x = 0;
double epX = Double.valueOf(epxText.getText());
double epY = Double.valueOf(epyText.getText());
double ax = Double.valueOf(accxText.getText());
double ay = Double.valueOf(accyText.getText());
int numBounces = 0;
double deltaTime = .00000001;
double total_velocity = 0.0;
double time = 0.0;
String fs;
angle = angle * Math.PI / 180;
while(numBounces < 10)
{
//Increment Time
time = time + deltaTime;
//Calculate new values for velocity[x] and velocity[y]
double vx = (vel*Math.cos(angle)) + ax*time;;
double vy = (vel*Math.sin(angle)) + ay*time;
//Calculate new values for x and y
x = x + vx*time;
y = y + vy*time + .5*ay*(time*time);
System.out.format("%.3f\n", y);
fs = String.format("%f\t %f\t %f\t %f\t %f\t %f\t %f\t\n", ax, ay, x, y, vx, vy, time);
out.write(fs);
//If ball hits ground: y < 0
if(y < 0)
{
numBounces++;
System.out.println("Number of Bounces: " + numBounces);
//Why is this statement needed if the velocity in the y direction is already being reversed?
vy = -vy - ay*time; // vy = -vy - ay*time;
//Calculate angle
angle = Math.atan(vy/vx);
angle = angle * Math.PI / 180;
//Calculate total velocity
total_velocity = Math.sqrt((vy*vy) + (vx*vx));
//Velocity with elasticity factored in
total_velocity = Math.sqrt((epY) * total_velocity);
//New velocities for when ball makes next trip
vy = total_velocity*Math.sin(angle);
vx = total_velocity*Math.cos(angle);
out.write(fs);
}
//Draw projectile
//Thread.sleep(.00001); //Sleep for deltaTime - 10 nanoseconds or draw after n number of points
}
out.close();
return null;
}
//SwingWorker lets you execute code on the event dispatching thread. Also allows you to update the GUI
public void done()
{
try
{
/*
rangeText.setText(" " + x);
heightTText.setText(" " + y);
timeText.setText(" " + time);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
What could be the possible problem?
My guess is that it might have something to do with the angle. In a previous version of the code, where I did not factor in an angle, it worked fine. Also, I am not sure if bounds on the GUI have to be set up so that y won't go on forever.
I also have a NullPointerException.
The first problem I see is here:
//Calculate angle
angle = Math.atan(vy/vx);
angle = angle * Math.PI / 180;
Math.atan returns a value in radians already:
Returns the arc tangent of a value; the returned angle is in the range -pi/2 through pi/2.
So the * Math.PI / 180 is not going to do you any favors.
The second problem is here:
//Calculate new values for velocity[x] and velocity[y]
double vx = (vel*Math.cos(angle)) + ax*time;;
double vy = (vel*Math.sin(angle)) + ay*time;
Every pass through the loop, these values are reinitialized. Because angle, ax, ay, and time cannot change during the loop, that means you always end up with the same vx and (positive) vy. vy should be getting smaller with each loop pass, something more like:
//Calculate initial values for velocity[x] and velocity[y]
double vx = (vel*Math.cos(angle)) + ax*time;
double vy = (vel*Math.sin(angle)) + ay*time;
while(numBounces < 10) {
//Increment Time
time = time + deltaTime;
//Calculate new values for x and y
x = x + vx*time;
y = y + vy*time + .5*ay*(time*time);
//Calculate new values for velocity[x] and velocity[y]
vx += ax * time;
vy += ay * time;
You need to learn to use a debugger - in Eclipse, for instance. Then you can stop wherever you want and examine variables until you figure out exactly where you're taking a wrong turn (or not taking a right one, in this case). You'll be able to figure this out in a minute or so.
If that's not an option, start putting in console printlns of key data.
Code always has errors, and you often can't figure them out just by looking at it - no matter how hard and how long.