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.
Related
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;
}
}
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.
Here's the code in question:
public void calculate() {
// Center of circle is at (250, 250).
//THIS ALGORITHM IS NOW PROVEN TO BE WORSE THAN I FEARED...
/* What it does:
* Moves object around in a circle.
* Does not move the object towards the center.
* Object always stays on the rim of the circle.
*
* Algorithm I used. (DOES NOT WORK):
* N is normalized vector.
* R = -2*(V dot N)*N + V
*/
vx += Accelero.X * 0.1;
vy += Accelero.Y * 0.1;
double nx = x - 250;
double ny = y - 250;
double nd = Math.hypot(nx, ny);
if (nd == 0)
nd = 1;
nx /= nd;
ny /= nd;
double dotProduct = vx * nx + vy * ny;
vx += (float) (-2 * dotProduct * nx);
vy += (float) (-2 * dotProduct * ny);
x -= vx * 2;
y -= vy * 2;
vx *= 0.99;
vy *= 0.99;
}
And this is what happens.
The black line you see is where the purple object (box) moves. It just so happens to be right on the circle line I drew with Canvas.drawCircle().
I don't understand why reflection didn't work. If an object is to hit a circular wall, shouldn't it reflect the object's direction of velocity, which is what the algorithm was meant to be? Or I used the wrong algorithm?
Any help is appreciated. Thanks in advance.
Can you do bouncing off a straight wall of arbitrary angle? That should be the first step. (You may find that a polar representation of the velocity vector is easier to work with.)
Once you've got that working, it should be fairly straightforward: bouncing off a circle is like bouncing off a tangent of that circle that touches it at the point of contact.
You can calculate this tangent by observing that it's perpendicular to the radius vector in the point of contact (that is the vector that points from where the object is to the centre of the circle)
Is there a vector-based implementation of this, without relying on angles?
Yes, see 2-Dimensional Elastic Collisions without Trigonometry, illustrated in this KineticModel. Your implementation appears to be missing the tangential component. See Ensemble#collideAtoms() for details.
This is what I've got, and I'm going to share my findings to all of you.
public void calculate() {
// Center of circle is at (250, 250). Radius is 40.
//THIS ALGORITHM IS PROVEN TO BE BETTER THAN I FEARED...
/* What it does:
* Moves object around in a circle, if object is
* inside of circle.
* Does not move the object towards the center,
* nor outwards. This is crucial.
* Object always stays on the rim of the circle,
* if the collision detection allows it to.
*
* Algorithm I used. (DOES WORK, NOT EXPECTING THIS THOUGH.):
* N is normalized vector.
* R = -2*(V dot N)*N + V
*/
double nx = x - 250;
double ny = y - 250;
double nd = Math.hypot(nx, ny);
if (nd < 40){
vx += Accelero.X * 0.1;
vy += Accelero.Y * 0.1;
x -= vx;
y -= vy;
vx *= 0.9;
vy *= 0.9;
return;
}
vx += Accelero.X * 0.1;
vy += Accelero.Y * 0.1;
if (nd == 0)
nd = 1;
nx /= nd;
ny /= nd;
double dotProduct = vx * nx + vy * ny;
vx += (float) (-2 * dotProduct * nx);
vy += (float) (-2 * dotProduct * ny);
x -= vx * 2;
y -= vy * 2;
vx *= 0.99;
vy *= 0.99;
}
I embedded a collision detection inside my function, basically making this function not as efficient as possible. Ignore that, for it's not the main focus.
The circle's radius is 40, the (x,y) position is (250,250).
Only when the object is either on the circle, or further away from the center of circle, should we calculate the collision response, which is given by the algorithm R = -2*(V dot N)*N + V, where normal vector N is already normalized.
The algorithm is indeed correct, it's the boolean condition of my collision detection is what causes the object to stay on the rim of the circle and go round-a-bout on it.
I didn't say the other algorithm, which #trashgod had provided is wrong. It's because of some weird issue that somehow causes the object to move unusually. I would guess it's the API I'm using's fault, which it didn't allow doubles, but I may be incorrect. I just couldn't find the source of the problem. Which I'm also happy to not look into it further anymore.
The collision detection boolean condition itself could change everything, if it was slightly altered. If it wasn't for #n.m. pointing that I somehow seemed to forget a minus sign (in this case, a NOT sign), I probably would never realized how trivial it would be.
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.
I'm trying to move a sprite across the screen in a straight line, towards on the location where've I touched the screen, what i did was upon the update() in each loop , it checks to see if the current sprite's location x y is == to the destination x ,y . if it hasn't sprite's x++ and y++...
the thing is ..it ain't moving in a straight line... as there are cases where the x or y coordinate reaches the destination x or y first... how do i changed it so that the both x and y meets the destination together?
my current pseudo code for the sprite object
destX = destination X
destY = destination Y
posX = current X
posY = current Y
public void update(){
if(destX > posX && destY < posY)
{
posX++;
posY--;
}
else if (destX > posX && destY > posY){
posX++;
posY++;
}
else if(destX < posX && destY > posY)
{
posX--;
posY++;
}
else if(destX < posX && destY < posY){
posX--;
posY--;
}
else if(destX < posX)
posX--;
else if(destX > posX)
posX++;
else if(destY < posY)
posY--;
else if(destY > posY)
posY++;
Check out: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
This simple algorithm will tell you each X,Y coordinate on a line between two points. You could use this algorithm to compute all of the positions it needs to visit, store the coordinates in an array, and iterate over the array as you update the position.
From the Article:
function line(x0, x1, y0, y1)
int deltax := x1 - x0
int deltay := y1 - y0
real error := 0
real deltaerr := abs (deltay / deltax) // Assume deltax != 0 (line is not vertical),
// note that this division needs to be done in a way that preserves the fractional part
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if error ≥ 0.5 then
y := y + 1
error := error - 1.0
This is the most primitive version. The article contains a better generalized algorithm that you should look at.
I am dealing with a similair problem as yours. (I have an arraylist holding the history of positions my player has gone and I want to use that to rewind the game.)
Instead of simply increasing x and y position with 1 you can:
Calculate the angle between the source postion and your destination
position.
Calculate the new direction using a variable which
represents the speed
Update your postion using calculated direction
I made a class of that. I hope it is usefull.
import java.awt.geom.Point2D;
public class MyVelocityCalculator {
public static void main(String[] args) {
Point2D.Double currentPosition = new Point2D.Double();
Point2D.Double destinationPosition = new Point2D.Double();
currentPosition.setLocation(100, 100);
destinationPosition.setLocation(50, 50);
Double speed = 0.5;
Point2D.Double nextPosition = MyVelocityCalculator.getVelocity(currentPosition, destinationPosition, speed);
System.out.println("player was initially at: "+currentPosition);
System.out.println("player destination is at: "+destinationPosition);
System.out.println("half seconds later player should be at: "+nextPosition);
}
public static final Point2D.Double getVelocity(Point2D.Double currentPosition, Point2D.Double destinationPosition, double speed){
Point2D.Double nextPosition = new Point2D.Double();
double angle = calcAngleBetweenPoints(currentPosition, destinationPosition);
double distance = speed;
Point2D.Double velocityPoint = getVelocity(angle, distance);
nextPosition.x = currentPosition.x + velocityPoint.x;
nextPosition.y = currentPosition.y + velocityPoint.y;
return nextPosition;
}
public static final double calcAngleBetweenPoints(Point2D.Double p1, Point2D.Double p2)
{
return Math.toDegrees( Math.atan2( p2.getY()-p1.getY(), p2.getX()-p1.getX() ) );
}
public static final Point2D.Double getVelocity(double angle, double speed){
double x = Math.cos(Math.toRadians(angle))*speed;
double y = Math.sin(Math.toRadians(angle))*speed;
return (new Point2D.Double(x, y));
}
}
Don't use integers. This is a very bad idea to work with ints. Use floats. The main concept is: define the number of steps you want to perform (s). Compute differences in X and Y (diffX and diffY). Don't take absolute values: Compute them this way
float diffX = destX - currentX;
Then compute the xMove and yMove values by dividing diffX and diffY by s (number of steps).
float moveX = diffX / s;
float moveY = diffY / s;
And now you have to add for each iteration the moveX and moveY values to the current position.
And for drawing it, you should use Graphics2D, which supports floating points. If you don't want to use Graphics2D, you can round the floats to ints, using Math.round(float).