Projectile Motion of an Object - java

My object is currently only going in a straight line at the set angle using the following code:
this.time = this.time + deltaTime;
// Vertical : Speed * Sine * Angle
double vy = (this.speed * Math.sin(this.angle)) + this.ax*this.time ;
// Horizontal : Speed * Cosine * Angle
double vx = (this.speed * Math.cos(this.angle)) + this.ay*this.time;
this.x = this.x + vx*this.time;
this.y = this.y + vy*this.time + this.ay*(this.time*this.time);
vx += this.ax * this.time;
vy += this.ay * this.time;
I'm assuming I have made some kind of math error in relation to the calculations as it seems the x value is correct, though the y value is not coming back down.
Here are my initial values in case you are wondering:
this.time = 0.0;
this.deltaTime = .0001;
this.x = 1.0;
this.y = 10;
this.speed = 60.0;
this.ay = -9.8;
this.angle = 45;
this.ax = 0.0;
Is this a stupid mistake I made causing this, or am I missing some key concept here?
GamePanel.java : https://gist.github.com/Fogest/7080df577d07bfe895b6
GameLogic : https://gist.github.com/Fogest/36aba3e1a7fc30984e4e

You are misapplying the fundamental equations of motion here. In the example above you are in effect, cancelling out the effect of gravity by adding it back in.
The entirety of the effect of gravity is already taken into account by updating your velocity. Additionally, it doesn't make sense to be using absolute time in your incremental calculations and pretty much every instance of this.time should be replaced by deltaTime.
Also on a conceptual level you are evaluating a differential equation, and so this should all be in a loop. Additionally, you are way overcomplicating things.
Fixed example:
this.speed = 60.0;
this.deltaTime = 0.0001;
this.endTime = 10.0;
this.x = 1.0;
this.y = 10;
this.ay = -9.8;
this.ax = 0;
this.angle = 45;
this.vx = this.speed*Math.cos(this.angle*(Math.PI/180.0))
this.vy = this.speed*Math.sin(this.angle*(Math.PI/180.0))
double time = 0.0;
while (time < this.endTime){
time += this.deltaTime;
this.x += this.vx*this.deltaTime;
this.y += this.vy*this.deltaTime;
this.vx += this.ax*this.deltaTime;
this.vy += this.ay*this.deltaTime;
}
Over time that will be a projectile in motion. Let me know if you have any questions.
Oh, looks like you implemented the code mostly right, the error is now in the way you're making your 2d Point and returning from your method. I'm not sure what IDE you're using, but it should really be giving you a compile error.
Point2D p = new Point2D.Double(x,y);
return p;
Should be replaced with:
return new Point2d.Double(this.x, this.y)

You must convert your angle from degrees to radians before using the angle in trigonometric methods. From the Math.sin Javadocs:
Parameters:
a - an angle, in radians.
Multiply by Math.PI and then divide by 180 to convert degrees to radians.

In these lines, I think you accidentally swapped ax and ay
// Vertical : Speed * Sine * Angle
double vy = (this.speed * Math.sin(this.angle)) + this.ax*this.time ;
// Horizontal : Speed * Cosine * Angle
double vx = (this.speed * Math.cos(this.angle)) + this.ay*this.time;
Since ax is zero (due to objects not gaining horizontal velocity in projectile motion), the typo makes vy constant.

Related

I have a point that follows the mouse, how would I give it a limited turning rate?

I have a point that follows the mouse that I made in Processing.
void move() {
double slope = (y - mouseY)/(x-mouseX);
double atanSlope = atan(slope);
if (slope < 0 && mouseY < y ) {
x += cos(atanSlope)*(speed);
y += sin(atanSlope)*(speed);
} else if (slope >= 0 && mouseY < y) {
x -= cos(atanSlope)*(speed);
y -= sin(atanSlope)*(speed);
} else if (slope > 0) {
x += cos(atanSlope)*(speed);
y += sin(atanSlope)*(speed);
} else {
x -= cos(atanSlope)*(speed);
y -= sin(atanSlope)*(speed);
}
}
How could I change this or add to this to make the point have a limited turning rate? What I had in mind would be similar to the missiles in this game. https://scratch.mit.edu/projects/181364872/
I don't know how I'd even start to limit the turning rate of the point. Any help would be appreciated.
(I tagged java too, because though this is in Processing, Processing is pretty much Java with built in methods at times.)
One way to do this is to keep the object current direction. You can then use the cross product of the vector to the mouse, and the vector along the object's direction to find the angle it needs to turn to point to the mouse. You can then limit the turn and add the change to get the new direction.
double direction = ?; // the current direction of object in radians
double x = ?; // the current position
double y = ?;
double maxTurn = ?; // Max turn speed in radians
double speed = ?;
void move() {
double mvx = mouseX - x; // get vector to mouse
double mvy = mouseY - y;
double dist = Math.sqrt(mvx * mvx + mvy * mvy); // get length of vector
if(dist > 0){ // must be a distance from mouse
mvx /= dist; // normalize vector
mvy /= dist;
double ovx = Math.cos(direction); // get direction vector
double ovx = Math.sin(direction);
double angle = Math.asin(mvx * ovy - mvy * ovx); // get angle between vectors
if(-mvy * ovy - mvx * ovx < 0){ // is moving away
angle = Math.sign(angle) * Math.PI - angle; // correct angle
}
// angle in radians is now in the range -PI to PI
// limit turn angle to maxTurn
if(angle < 0){
if(angle < -maxTurn){
angle = -maxTurn;
}
}else{
if(angle > maxTurn){
angle = maxTurn;
}
}
direction += angle; // turn
// move along new direction
x += Math.cos(direction) * speed;
y += Math.sin(direction) * speed;
}
}

How do I calculate the coordinates of the points of an helix?

The following code is called every 50ms.
// Start point
private double x;
private double y;
private double z;
private double y1;
#Override
public void run() {
double x1 = Math.cos(y1);
double z1 = Math.sin(y1);
double y2 = 4D - y1;
double x2 = Math.sin(y2);
double z2 = Math.cos(y2);
// First new point
double pX1 = x + x1;
double pY1 = y + y1;
double pZ1 = z + z1;
// Second new point
double pX2 = x + x2;
double pY2 = y + y2;
double pZ2 = z + z2;
if (y1 > 4D) {
y1 = 0D;
} else {
y1 = y1 + 0.1D;
}
}
Here is the output in a game. It generates two helices.
I cannot control more than the radius.
I am looking for code I can easily customize to fit my preferences.
How do I control the following aspects?
How fast the helix rises.
Where the helix begins.
helix is circular shape with 'linear' movement of the plane
you use plane xz as helix base and y axis as height
so you need:
r - radius
d - distance between two screws (the y movement after full circle)
t - parameter <0,1> determining the position on helix
h0,h1 - start end height of helix (y-axis)
a0 - angular start position [rad]
Now how to get the point on helix as function of parameter these parameters
aa=fabs(h1-h0)*2.0*M_PI/d; // angular speed coefficient
// if you need opposite angular direction then add aa=-aa;
x=r*cos(a0+aa*t);
z=r*sin(a0+aa*t);
y=h0+((h1-h0)*t);
aa can be precomputed once
now if t=0.0 then you get the start point of helix
if t=1.0 then you got the endpoint of helix
so speed is just how much you add to t during animation per timer cycle
d controls number of screw loops
h1-h0 is the helix height
code is in C++ (sorry I am not a JAVA coder)
One part of the helix begins at:
(x, y, z) = (1.0, 0.0, 0.0)
And the other at:
(x, y, z) = (-0.8, 4.0, -0.7)
And the particle rises at a rate of 0.1 (from y1 = y1 + 0.1D).
So, to control how fast the particles rise, just change this value.
To control where the helix begins you need to change the angle. For example, add some value to the sines and cosines. Like this:
Math.cos(y1 + dy);
To make more rotations before restarting from the ground you can multiply the angle. Make it twice as fast:
Math.cos(2 * y1);
Helix is circular shape with progressive Y value.
// Start point
private double x;
private double y;
private double z;
private double degree;
private double rY;
#Override
public void run() {
// We use the same formula that is used to find a point of a circumference
double rX = Math.cos(degree);
double rZ = Math.sin(degree);
// New point
double pX = x + rX;
double pY = y + rY;
double pZ = z + rZ;
if (degree > 2D * Math.PI) {
degree = 0D;
} else {
degree = degree + 0.2D;
}
if (pY > 2D) {
pY = 0D;
} else {
pY = pY + 0.02D;
}
}

How do I check the collision between a ball and a line

I want to check if the ball and a specific line (zijde) collide. I want to do this by making the line function of the line. Than check if the coordinates that come out of the function are equal to the ball's coordinates. This is the code i'm using so far and I don't know what I'm doing wrong. Zijde z is the line that the ball needs to collide with and has the functions getStartPoint (getStartPunt) and getEndPoint (getEindpunt).
public Boolean CheckCollision(Zijde z)
{
/**
* y = ax + b
* a = delta y / delta x
* b = y - ax
*/
double deltay = z.getEindpunt().getY() - z.getStartPunt().getY();
double deltax = z.getEindpunt().getX() - z.getStartPunt().getX();
double a = deltay / deltax;
double b = z.getEindpunt().getY() - a * z.getEindpunt().getX();
double yf = a * this.x + b;
return yf == this.y;
}
Assuming there are no problems with the math, I'd change the last line to
return Math.abs(yf - this.y) < SOME_SMALL_CONSTANT;
since, given the imprecise nature of floating point arithmetics, your method would probably never return true.
I'd play with the value of SOME_SMALL_NUMBER to see what give you decent results.

Circle to circle collision

I am trying to write a Java program to support off-lattice diffusion limited aggration simulation. Basic code to simulate a moving particle is in place, until said particle hits a static center particle. At that point I try to make sure the moving particle is just touching (tangeant to) the static one. However, for unknown reasons, it sometimes fails (the first 2 of 8 particles intersects, the 6 others are fine).
Here is the code:
boolean killed, collide;
double xp, yp, dx, dy, theta, xpp, ypp, length;
int xc = 200;
int yc = 200;
int killRadius = 200;
int releaseRadius = 150;
int partRadius = 14;
int partDiam = 2 * partRadius;
drawCircle(xc, yc, killRadius); // kill
drawCircle(xc, yc, releaseRadius); // release
drawCircle(xc, yc, partRadius); // center particle
//while (true) {
killed = false;
collide = false;
theta = Math.random() * Math.PI * 2;
xp = xc + releaseRadius * Math.cos(theta);
yp = yc + releaseRadius * Math.sin(theta);
while (true) {
theta = Math.random() * Math.PI * 2;
length = partDiam;
xpp = xp;
ypp = yp;
xp = xp + length * Math.cos(theta);
yp = yp + length * Math.sin(theta);
//drawCircle((int) xp, (int) yp, partRadius);
// Should it be killed ? (maybe could use a box to fasten
// computations...
// Would switching the test for kill w test for collision
// improve perf ?
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
killed = true;
break;
}
// Does it collide with center? replace by any particle...
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
collide = true;
break;
}
}
// Probably something is wrong here...
if (collide) {
// no absolute value because particles move at most by diameter
double depthPenetration = partDiam
- Math.sqrt((dx * dx) + (dy * dy));
dx = xpp - xp;
dy = ypp - yp;
// shorten distance travelled by penetration length to ensure
// that
// particle is tangeant
length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration;
xp = xpp + length * Math.cos(theta);
yp = ypp + length * Math.sin(theta);
drawCircle((int) xp, (int) yp, partRadius);
}
//}
Of course I checked many references before asking, but cannot find anything wrong with the code... Help would be appreciated.
I made some simple refactorings through your code, just to get a feeling what it does, what is happening.
Let me mention one thing at start: It's the revival of the sphaghetti-monster, isn't it? Do you like global variables? Long, superpotent let's do it all right now and here methoods?
If you introduce variables as late as possible, the reader of your code needn't search upwards, what this variable has been been before - if something is overridden, for example, if there is a ungood reuse.
If your variables don't change: Make them final. That simplifies reasoning about them. final int killRadius = 200; means, that get the type information, together with the value, and hopefully shortly before first usage, and that it will never get changed. Configuration only in source code. Probably not a too complicated candidate. In contrast to double dx - not initialized, because it get's initialized inside the loop,
static void foo () {
final int xc = 200;
final int yc = 200;
final int killRadius = 200;
final int releaseRadius = 150;
final int partRadius = 14;
drawCircle (xc, yc, killRadius); // kill
drawCircle (xc, yc, releaseRadius); // release
drawCircle (xc, yc, partRadius); // center particle
//while (true) {
boolean killed = false;
boolean collide = false;
double theta = Math.random() * Math.PI * 2;
double xp = xc + releaseRadius * Math.cos (theta);
double yp = yc + releaseRadius * Math.sin (theta);
double dx, dy, xpp, ypp;
while (true) {
theta = Math.random () * Math.PI * 2;
final int partDiam = 2 * partRadius;
final double length = partDiam;
xpp = xp;
ypp = yp;
xp += length * Math.cos (theta);
yp += length * Math.sin (theta);
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
killed = true;
break;
}
// Why again assign dx = xp -xc? Did any of these values change meanwhile?
// I don't think so.
// dx = xp - xc;
// dy = yp - yc;
if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
collide = true;
break;
}
}
if (collide) {
// no absolute value because particles move at most by diameter
double depthPenetration = partDiam - Math.sqrt((dx * dx) + (dy * dy));
dx = xpp - xp;
dy = ypp - yp;
// shorten distance travelled by penetration length to ensure
// that
// particle is tangeant
final double length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration;
xp = xpp + length * Math.cos (theta);
yp = ypp + length * Math.sin (theta);
drawCircle ((int) xp, (int) yp, partRadius);
}
If you structure your code like this, you not only see, that some value like xc is 200 and never changed - in the head of the while loop you see that theta is not declared inside the loop, so either it is used later outside the loop, or it is sequentially modified inside the loop. To do an x += 4; you can't initialize x in ever loop passing.
In the end of the big while, you have two similar blocks:
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) (OP) a OP b) {
c = true;
break;
}
but xp, xc and dx aren't changed meanwhile - nor the y-equivalents. Is this a mistake, or why do you assign them again?
Then, you can get rid of your endless while this way: Since both conditions terminate the while, put the conditions into the while - test, and call the second block (without repeating the assignment) only if the first wasn't entered - keyword to do so is else:
while (!killed && !collide) {
// ...
dx = xp - xc;
dy = yp - yc;
if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
killed = true;
}
else if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
collide = true;
}
}
What does it help in finding the error? Not so much. If two circles are placed wrongly, and the rest fine, a screenshot would be fine, and values, which lead to bad circles, and values which are alright.
I don't think I can debug your code, but I wrote some java.awt.Shape based collision routines many years ago (over a decade ago) that may help... check out the ShapeUtils.java from this:
http://www.cs101.org/psets/breakout/solns/breakout-src.jar
One of the very likely problems you may have is that java circles are spline curves with 4 points, and thus if you check if all the points defining the circle are inside another shape, you will still miss the case where the spline curve bulges into the other shape, but none of the points are actually inside the object. My solution (which might not be good enough for your case was to remake shapes until the distance between the points along their respective edges was smaller than the largest acceptable error:
/**
* Convert any AWT shape into a shape with a specified precision.
* The specified precision indicates the maximum tolerable distance
* between knot points. If the shape is already precise enough then
* it is returned unmodified.
*
* #param aShape the shape to be converted if necessary.
* #param precision the maximum tolerable distance between knot points.
* #return A more precise version of the shape, or the same shape if
* the precision is already satisfied.
*/
public static Shape getPreciseShape(Shape aShape, float precision) {
This precision along with the velocity of the simulated object, told me how often in the simulation I had to check for collisions (the max delta time)... fast moving simulated objects can zip right through solid objects in a single time interval if you don't scale the time interval to be less than the time it takes to travel your desired precision.
Basically in this way it became a direct trade off between calculation cost and precision of the result. In my case I just wanted the game to look good, and so I only needed to be so precise as to ensure that objects never overlapped by more than half a pixel or so.
Edit: Let me summarize my suggestion... in re-reading I realize I got lost in the details and never manage to point out the key concept... Java has lots of routines that work quite well for testing various implementations of Shape (including circles). My suggestion is use the java libraries as much as possible, and get results that you can verify are correct. Once you've got working code and methodology for checking that the code works, if you need more speed, start optimizing portions of it, preferably after profiling the running program (that produces correct results) to see what parts are limiting your performance.

How to make my Image move in a random direction?

I have an image that rotating in a counter clockwise direction. Now, I want it to move in a random direction during or whenever it touch the wall. The problem is I can't do it, please help me about this matter.
This is my code :
private double x;
private double y;
private double speed;
public void move(long dt)
{
double dt_s = dt / 1e9;
double dx = speed * dt_s;
double dy = speed * dt_s;
final double right_border = 100;
final double up_border = 100;
final double down_border = 0.0;
final double left_border = 0.0;
x += dx;
if (x >= right_border)
{
x = right_border;
if (y >= down_border)
{
y += dy;
}
}
if (y > up_border)
{
y = up_border;
if (x >= left_border)
{
speed *= -1;
}
}
if (x <= left_border)
{
x = left_border;
if (y <= up_border)
{
y += dy;
}
}
if (y < down_border)
{
y = down_border;
if (x <= right_border)
{
speed *= -1;
}
}
}
First you must solve the problem of your class being directionless - you have speed, but your direction is fixed at 45 degree north east (increment x and y the same).
Add direction to your class as follows:
...
private double speed;
private double angle; // in radians - makes math easier
public void move(long dt) {
...
double dx = speed * dt_s * Math.sin(angle);
double dy = speed * dt_s * Math.cos(angle);
...
Now to head in a random direction:
myObject.setAngle(Math.PI * 2 * Math.random()); // Math.PI * 2 = 360 degrees
If hitting a wall, you will have to limit your angle to an angle that's away from the wall you are hitting. I'll leave that to you, but it will take the form of:
myObject.setAngle(minAngle + ((maxAngle - minAngle) * Math.random()));
This is one possible solution.
Generate a random point (x,y) on one of the boundaries (other than the boundary that the image just hit), and make the image move towards that point. All you have to do is, find the slope between the point P1(x1,y1) it just hit, and the random point just generated P2(x2,y2). Using the slope you can find the equation of the line, it has to travel in. You're done!!

Categories

Resources