Newton's Method for finding Complex Roots in Java - java

I got a project in my Java class which I'm having trouble with.
The project is basically marking coordinates on the screen, making a (complex) polynomial out of them, then solving the polynomial with Newton's method using random guesses and drawing the path of the guesses on the screen.
I don't have a problem with any of the drawing, marking, etc.
But for some reason, my Newton's method algorithm randomly misses roots. Sometimes it hits none of them, sometimes it misses one or two. I've been changing stuff up for hours now but I couldn't really come up with a solution.
When a root is missed, usually the value I get in the array is either converging to infinity or negative infinity (very high numbers)
Any help would be really appreciated.
> // Polynomial evaluation method.
public Complex evalPoly(Complex complexArray[], Complex guess) {
Complex result = new Complex(0, 0);
for (int i = 0; i < complexArray.length; i++) {
result = result.gaussMult(guess).addComplex(complexArray[complexArray.length - i - 1]);
}
return result;
}
> // Polynomial differentation method.
public Complex[] diff(Complex[] comp) {
Complex[] result = new Complex[comp.length - 1];
for (int j = 0; j < result.length; j++) {
result[j] = new Complex(0, 0);
}
for (int i = 0; i < result.length - 1; i++) {
result[i].real = comp[i + 1].real * (i + 1);
result[i].imaginary = comp[i + 1].imaginary * (i + 1);
}
return result;
}
> // Method which eliminates some of the things that I don't want to go into the array
public boolean rootCheck2(Complex[] comps, Complex comp) {
double accLim = 0.01;
if (comp.real == Double.NaN)
return false;
if (comp.real == Double.NEGATIVE_INFINITY || comp.real == Double.POSITIVE_INFINITY)
return false;
if (comp.imaginary == Double.NaN)
return false;
if (comp.imaginary == Double.NEGATIVE_INFINITY || comp.imaginary == Double.POSITIVE_INFINITY)
return false;
for (int i = 0; i < comps.length; i++) {
if (Math.abs(comp.real - comps[i].real) < accLim && Math.abs(comp.imaginary - comps[i].imaginary) < accLim)
return false;
}
return true;
}
> // Method which finds (or attempts) to find all of the roots
public Complex[] addUnique2(Complex[] poly, Bitmap bitmapx, Paint paint, Canvas canvasx) {
Complex[] rootsC = new Complex[poly.length - 1];
int iterCount = 0;
int iteLim = 20000;
for (int i = 0; i < rootsC.length; i++) {
rootsC[i] = new Complex(0, 0);
}
while (iterCount < iteLim && MainActivity.a < rootsC.length) {
double guess = -492 + 984 * rand.nextDouble();
double guess2 = -718 + 1436 * rand.nextDouble();
if (rootCheck2(rootsC, findRoot2(poly, new Complex(guess, guess2), bitmapx, paint, canvasx))) {
rootsC[MainActivity.a] = findRoot2(poly, new Complex(guess, guess2), bitmapx, paint, canvasx);
MainActivity.a = MainActivity.a + 1;
}
iterCount = iterCount + 1;
}
return rootsC;
}
> // Method which finds a single root of the complex polynomial.
public Complex findRoot2(Complex[] comp, Complex guess, Bitmap bitmapx, Paint paint, Canvas canvasx) {
int iterCount = 0;
double accLim = 0.001;
int itLim = 20000;
Complex[] diffedComplex = diff(comp);
while (Math.abs(evalPoly(comp, guess).real) >= accLim && Math.abs(evalPoly(comp, guess).imaginary) >= accLim) {
if (iterCount >= itLim) {
return new Complex(Double.NaN, Double.NaN);
}
if (evalPoly(diffedComplex, guess).real == 0 || evalPoly(diffedComplex, guess).imaginary == 0) {
return new Complex(Double.NaN, Double.NaN);
}
iterCount = iterCount + 1;
guess.real = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).real;
guess.imaginary = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).imaginary;
drawCircles((float) guess.real, (float) guess.imaginary, paint, canvasx, bitmapx);
}
return guess;
}
> // Drawing method
void drawCircles(float x, float y, Paint paint, Canvas canvasx, Bitmap bitmapx) {
canvasx.drawCircle(x + 492, shiftBackY(y), 5, paint);
coordPlane.setAdjustViewBounds(false);
coordPlane.setImageBitmap(bitmapx);
}
}

Error 1
The lines
guess.real = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).real;
guess.imaginary = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess))).imaginary;
first introduce a needless complication and second introduce an error that makes it deviate from Newton's method. The guess used in the second line is different from the guess used in the first line since the real part has changed.
Why do you not use, like in the evaluation procedure, the complex assignment in
guess = guess.subtractComplex(evalPoly(comp, guess).divideComplex(evalPoly(diffedComplex, guess)));
Error 2 (Update)
In the computation of the differentiated polynomial, you are missing the highest degree term in
for (int i = 0; i < result.length - 1; i++) {
result[i].real = comp[i + 1].real * (i + 1);
result[i].imaginary = comp[i + 1].imaginary * (i + 1);
It should be either i < result.length or i < comp.length - 1. Using the wrong derivative will of course lead to unpredictable results in the iteration.
On root bounds and initial values
To each polynomial you can assign an outer root bound such as
R = 1+max(abs(c[0:N-1]))/abs(c[N])
Using 3*N points, random or equidistant, on or close to this circle should increase the probability to reach each of the roots.
But the usual way to find all of the roots is to use polynomial deflation, that is, splitting off the linear factors corresponding to the root approximations already found. Then a couple of additional Newton steps using the full polynomial restores maximal accuracy.
Newton fractals
Each root has a basin or domain of attraction with fractal boundaries between the domains. In rebuilding a similar situation to the one used in
I computed a Newton fractal showing that the attraction to two of the roots and ignorance of the other two is a feature of the mathematics behind it, not an error in implementing the Newton method.
Different shades of the same color belong to the domain of the same root where brightness corresponds to the number of steps used to reach the white areas around the roots.

Related

Battleship Game - Random Ship Placement

I have to do a Battleship game. The game should have some kind of AI. The AI CAN place ships with a hard coded pattern, but i want to take things a step further and make the ship placement random.
I have implemented a "trial and error" method, where ships get randomly placed on the field with a random rotation, until the algorithm runs out of either ships to be placed or fields to place the ships in. In the second case the recursive implementation allows to try out other ship/field/rotation combos, until the first condition is reached. So to speak: try all possible ship/rotation/field combo's (picked randomly) until you find one valid one, where all ships are placed.
As you can imagine, this is a terrible effort, when it comes to runtime.
The size of the "board" can be 5x5 up to 30x30 with exactly 30% of the fields beeing occupied by a ship.
Now, Runtime isn't my concern for sizes up to 14x14, but then runtime increases so badly, that i have to think of a way to reduce runtime.
Any suggestions? (I would like to get general thinking advice/idea's, not code)
In case, my explenation wasn't enough: Here's the class that tries to place the ships on the field:
public class RandomShipFactory {
private int size;
private Game game;
private ArrayList<Ship> toBeCheckedShips = new ArrayList<Ship>();
private ArrayList<Position> toBeCheckedPositions = new ArrayList<Position>();
public RandomShipFactory(int size, Game game) {
this.size = size;
this.game = game;
this.toBeCheckedShips.addAll(game.ownBoard.getShips());
for(int i = 0; i < this.size; i++) {
for(int j = 0; j < this.size; j++) {
this.toBeCheckedPositions.add(new Position(i,j));
}
}
}
public void makeRandomShipPlacements() {
this.makeRandomShipPlacements(this.toBeCheckedPositions, this.toBeCheckedShips);
game.ownBoard.printBoard();
}
private boolean makeRandomShipPlacements(ArrayList<Position> currentPositions, ArrayList<Ship> currentShips) {
if(currentPositions.isEmpty()) {
return false;
}
ArrayList<Position> checkedPositionsInThisRun = new ArrayList<Position>();
Random r = new Random();
boolean success = false;
while(!success && !currentShips.isEmpty() && !currentPositions.isEmpty()) {
int randomPositionIndex = r.nextInt(currentPositions.size());
Position randomPosition = currentPositions.remove(randomPositionIndex);
checkedPositionsInThisRun.add(randomPosition);
ArrayList<Ship> currentShipQueue = new ArrayList<Ship>();
currentShipQueue.addAll(currentShips);
while(!success && !currentShipQueue.isEmpty()) {
Ship currentShip = currentShipQueue.remove(0);
boolean shouldRotate = r.nextBoolean();
if(shouldRotate) {
currentShip.rotate();
}
boolean canPlaceShip = this.game.placeShipOnOwnBoard(currentShip, randomPosition.x, randomPosition.y);
if(canPlaceShip) {
currentShips.remove(currentShip);
ArrayList<Position> boxPositions = removeBoxSquarePositions(currentPositions, currentShip, randomPosition);
if(currentShips.isEmpty()) {
success = true;
}else {
boolean recursiveSuccess = this.makeRandomShipPlacements(currentPositions, currentShips);
if(!recursiveSuccess) {
this.game.removeShipFromOwnBoard(currentShip);
currentPositions.addAll(boxPositions);
currentShips.add(currentShip);
}else {
success = true;
}
}
}else {
currentShip.rotate();
canPlaceShip = this.game.placeShipOnOwnBoard(currentShip, randomPosition.x, randomPosition.y);
if(canPlaceShip) {
currentShips.remove(currentShip);
ArrayList<Position> boxPositions = removeBoxSquarePositions(currentPositions, currentShip, randomPosition);
if(currentShips.isEmpty()) {
success = true;
}else {
boolean recursiveSuccess = this.makeRandomShipPlacements(currentPositions, currentShips);
if(!recursiveSuccess) {
this.game.removeShipFromOwnBoard(currentShip);
currentPositions.addAll(boxPositions);
currentShips.add(currentShip);
}else {
success = true;
}
}
}
}
}
}
currentPositions.addAll(checkedPositionsInThisRun);
return success;
}
private ArrayList<Position> removeBoxSquarePositions(ArrayList<Position> positionList, Ship ship, Position pos) {
ArrayList<Position> boxPositions = new ArrayList<Position>();
for(int i = 0; i < ship.length + 2; i++) {
for(int j = 0; j < 3; j++) {
int nextX, nextY;
switch(ship.getRotation()) {
case HORIZONTAL:
nextX = pos.x - 1 + i;
nextY = pos.y - 1 + j;
break;
case VERTICAL:
nextX = pos.x - 1 + j;
nextY = pos.y - 1 + i;
break;
default:
nextX = pos.x - 1 + j;
nextY = pos.y - 1 + i;
break;
}
if(nextX >= 0 && nextX < this.size && nextY >= 0 && nextY < this.size) {
Position currentPosition = Position.findPosInList(positionList, nextX, nextY);
if(currentPosition != null) {
positionList.remove(currentPosition);
boxPositions.add(currentPosition);
}
}
}
}
return boxPositions;
}
}
Multiple things to consider here, where improvement can take place:
This point is INVALID, because the OP has actually accounted for that. But this is still a basic thing to keep in mind: NEVER try to hit positions with random addresses. As soon as the field has a few ships, this will decrease speed drastically. In addition, 'random' functions can be really really slow, depending on their implementation
a) Your code is also slow because you search items in linear lists, so in average your additional effort will be (list size) / 2. Use HashMaps or TreeMaps or HeapMaps, or their Set version.
b) Your code uses remove(anyIndex). In ArrayLists, this will start to copy (on average) half of the array data to another position on every call.
And it does not play a role, whether you 'pop' from the very top (index 0) or not.
Worst of all, you use this remove() in loops, exploding your runtime.
Use an unstable removal (order will not be maintained), or LinkedLists, or some Map.
a) instead of targeting random positions, build a map of ALL available spaces (on a 30x30 board, this will add 900 entries to the hashmap).
The advantage of this approach is that build-up is slow, but all other operations are linear or minimized.
have a parameter for the size of a ship
create the HashMap (should be its own method, because we might need this at different locations in the code):
iterate over all positions, add the free ones (where you could validly place a ship of required length and rotation) to a hashmap, use coordinates as key
alternatively, if you expect coverage to be less than 85%, add ALL positions, then iterate over already placed ships and remove their positions from the HashMap
placement collisions for future placements would be possible at this point, but get removed once we hit (y)
place the ships:
x) selecting a random 'index' from a hashmap is a little challenge here, but you'll figure that out
y) once you start placing ships, remove all affected positions from the hashmap (include the ship's length and orientation in your calculations)
resume at (x)
b) extension of that algorithm - improvement for differing sizes
if you run this algorithm for ships with differing sizes, calculate the available positions for the longest ships first, then you can also re-use the created hashmap for shorter ones. if the hashmap is empty but there are still ships remaining: when you run the 'create hashmap of valid positions' algorithm again, adjust/reduce the searched ship length to the currently required one. (This then will not be 'truly random' anymore, but random enough that no player will ever realize it. But in cryptography for example, this here would break the algorithm)
this will greatly increase speed while coverage is below ~80%
A little hint on switches: use fall-through for combined code blocks:
Your code is
switch(ship.getRotation()) {
case HORIZONTAL:
nextX = pos.x - 1 + i;
nextY = pos.y - 1 + j;
break;
case VERTICAL:
nextX = pos.x - 1 + j;
nextY = pos.y - 1 + i;
break;
default:
nextX = pos.x - 1 + j;
nextY = pos.y - 1 + i;
break;
}
it can easily be reduced to
switch(ship.getRotation()) {
case HORIZONTAL:
nextX = pos.x - 1 + i;
nextY = pos.y - 1 + j;
break;
case VERTICAL: // fall-through to default, as VERTICAL seems to be the default^^
default:
nextX = pos.x - 1 + j;
nextY = pos.y - 1 + i;
break;
}

Dynamic OBB Collision Detection (Separating Axis Theorem): Find the Time That Collision Occurred?

Right now, I am trying use the separating axis theorem to implement a dynamic 3-D OBB collision test in Java. I'm trying to find the time from 0 to 1 of intersection for the entities for each separating axis, with 0 being the beginning of the frame and 1 being the end of the frame.
Here is my code:
private float calculateITime(OBB obb,
Vector3f axis /*the separating axis we are testing*/,
Vector3f d /*Current OBB's origin minus other OBB's origin*/,
float ra /*the first obb's projection*/,
float rb /*the second obb's projection*/,
float r /*what I understand to be the total length of the combined projections*/) {
//Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected.
float intersectionLength = r - Math.abs(ra) - Math.abs(rb); //The measure of how much the two projections overlap
Vector3f aVelocity = this.getCollisionPacket().getVelocity();
Vector3f bVelocity = obb.getCollisionPacket().getVelocity();
double aMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(aVelocity, d));
double bMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(bVelocity, d));
double totalDistanceCovered = 0;
if(aMagnitude <= 0 && bMagnitude <= 0) {
totalDistanceCovered = Math.abs(aMagnitude - bMagnitude);
} else if((aMagnitude >= 0 && bMagnitude <= 0) || (aMagnitude <= 0 && bMagnitude >= 0)) {
totalDistanceCovered = Math.abs(aMagnitude + bMagnitude);
} else if(aMagnitude >= 0 && bMagnitude >= 0) {
totalDistanceCovered = Math.abs(aMagnitude - bMagnitude);
}
System.out.println("PotentialITime: " + Math.abs(intersectionLength / totalDistanceCovered));
return (float) Math.abs(intersectionLength / totalDistanceCovered);
}
However, I'm getting values way above one. Where am I going wrong, assuming that I'm even properly understanding how to properly implement the separating-axis theorem?
If you think you have an answer but it would be helpful if I posted the rest of the class (although it's pretty long), let me know and I'll do it for you. Thanks!
Final Notes:
This function is in the OBB class. As such, "this" refers to the OBB, and "obb" refers to the other OBB.
collisionPacket.getVelocity() returns the total displacement that will occur in a single frame should there be no collision.
"Mathematics" is my own static class. Assume it works properly. I didn't realize Vector3f had all those useful functions until after I made it.
This is the PDF I'm using. I'm getting stuck at page 9, at 2.3.1.
A few weeks later, I figured out how to do what I was trying to do. I actually came up with this a couple weeks ago, but I just now thought to post my solution.
private boolean determineCollision(OBB obb, Vector3f separatingAxis, double velocityMagnitude, float ra, float rb, float r) {
//Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected.
//If r is negative, the first OBB is to the "right." Otherwise, it is to the "left."
collisionRightSide.add(r < 0);
boolean currColRightSide = collisionRightSide.get(collisionRightSide.size() - 1);
double timeRange[] = new double[2]; //From 0 (beginning of frame) to 1 (end of frame)
//Perform a regular static test if there is no movement for optimization's sake
boolean noStaticOverlap = Math.abs(r) > (ra + rb);
if(velocityMagnitude == 0) {
timeRange[0] = 0; timeRange[1] = 1;
axisTimes.add(timeRange);
return !noStaticOverlap;
}
double spaceBetweenProjections = Math.abs(r) - Math.abs(ra) - Math.abs(rb);
//Note that if velocity magnitude is negative, the first OBB is moving "right," and the other way for positive.
if(currColRightSide) {
if(velocityMagnitude < 0) {
if(noStaticOverlap) {
// System.out.println("(Right side) OBBs are moving away");
return false;
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs(spaceBetweenProjections / velocityMagnitude);
}
} else if(velocityMagnitude > 0) {
if(noStaticOverlap) {
timeRange[0] = Math.abs(spaceBetweenProjections / velocityMagnitude);;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
}
}
} else {
if(velocityMagnitude > 0) {
if(noStaticOverlap) {
// System.out.println("(Left side) OBBs are moving away");
return false;
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs(spaceBetweenProjections / velocityMagnitude);
}
} else if(velocityMagnitude < 0) {
if(noStaticOverlap) {
timeRange[0] = Math.abs(spaceBetweenProjections / velocityMagnitude);
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
}
}
}
//Clamp values
if(timeRange[0] < 0) timeRange[0] = 0;
if(timeRange[1] > 1) timeRange[1] = 1;
//Switch so that the greater value comes last
if(timeRange[0] > timeRange[1]) {
double temp = timeRange[0];
timeRange[0] = timeRange[1];
timeRange[1] = temp;
}
if(timeRange[0] > 1 && timeRange[1] < 0) return false;
axisTimes.add(timeRange);
return true;
}
Thanks to StackOverflow for giving me the Tumbleweed badge for this question. If someone comes up with a better or more optimized way of doing this, please let me know. Thanks! :D

Douglas-Peucker point count tolerance

I am trying to implement Douglas-Peucker Algorithm with point count tolerance. I mean that i specifies that i want 50% compression. I found this algorithm on this page http://psimpl.sourceforge.net/douglas-peucker.html under Douglas-Peucker N. But i am not sure how this algorithm is working. Is there any implementation of this in java or some good specification about this version of algorithm?
What i dont understand from psimpl explanation is what will happend after we choose fist point into simplification? We will broke the edge into two new edges and rank all points and choose best point from both edges?
DP searches the polyline for the farthest vertex from the baseline. If this vertex is farther than the tolerance, the polyline is split there and the procedure applied recursively.
Unfortunately, there is no relation between this distance and the number of points to keep. Usually the "compression" is better than 50%, so you may try to continue the recursion deeper. But achieving a good balance of point density looks challenging.
Combine the Douglas-peucker algorithm with iteration, and consider the remained points as a judge criteria.
Here is my algorithm, array 'points' stores the points of the trajectory.Integer 'd' is the threshold.
public static Point[] divi(Point[] points,double d)
{
System.out.println("threshold"+d);
System.out.println("the nth divi iteration");
int i = 0;
Point[] p1 = new Point[points.length];
for (i = 0;i<points.length;i++)
p1[i] = points[i];
compress(p1, 0,p1.length - 1,d); //first compression
int size = 0;
for (Point p : p1) //trajectory after compression
if(p != null)
size ++;
System.out.println("size of points"+size);
if(size<=200 && size>=100)
return p1;
else if(size>200)
return divi(p1,d + d/2.0);
else
return divi(points,d/2.0);
}
public static void compress(Point[] points,int m, int n,double D)
{
System.out.println("threshold"+D);
System.out.println("startIndex"+m);
System.out.println("endIndex"+n);
while (points[m] == null)
m ++;
Point from = points[m];
while(points[n] == null)
n--;
Point to = points[n];
double A = (from.x() - to.x()) /(from.y() - to.y());
/** -
* 由起始点和终止点构成的直线方程一般式的系数
*/
double B = -1;
double C = from.x() - A *from.y();
double d = 0;
double dmax = 0;
if (n == m + 1)
return;
List<Double> distance = new ArrayList<Double>();
for (int i = m + 1; i < n; i++) {
if (points[i] ==null)
{
distance.add(0.0);
continue;
}
else
{
Point p = points[i];
d = Math.abs(A * (p.y()) + B * (p.x()) + C) / Math.sqrt(Math.pow(A, 2) + Math.pow(B, 2));
distance.add(d);
}
}
dmax= Collections.max(distance);
if (dmax < D)
for(int i = n-1;i > m;i--)
points[i] = null;
else
{
int middle = distance.indexOf(dmax) + m + 1;
compress(points,m, middle,D);
compress(points,middle, n,D);
}
}

What's wrong with my collection algorithm for my AI when it's trying to gather points? It gets confused and goes back and forth

I'm trying to write a basic AI for a game where the character collects points on a grid. The points are randomly generated on the grid and my AI just has to move onto that coordinate on the grid.
The AI can't see the full grid however, it can only see a 5x5 grid with it at the center as it moves around each "turn". (So it's at coordinate (2, 2) each turn.)
My algorithm is basic, but it basically scans the 5x5 grid and tries to find the closest point, then it moves the character toward that direction. Then the next turn that point will be even closer (as we just moved even closer to it) so it will choose to keep approaching it until it finds gets to the desired coordinate.
Here it is in Java:
Field[][] fields = gameboard.getFields();
int centerX = 2;
int centerY = 2;
// Large numbers that points will always be closer than
int nearestPointX = 1000;
int nearestPointY = 1000;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
Field field = fields[i][j];
if (field.getType() == 0 && field.hasPoint()) {
int distanceX = Math.abs(i - centerX);
int distanceY = Math.abs(j - centerY);
int totalDistance = distanceX + distanceY;
int totalBestDistance = nearestPointX + nearestPointY;
if (totalDistance < totalBestDistance) {
nearestPointX = i;
nearestPointY = j;
}
}
}
}
Field northField = fields[centerX][centerY-1];
Field southField = fields[centerX][centerY+1];
Field eastField = fields[centerX+1][centerY];
Field westField = fields[centerX-1][centerY];
String move = previousMove;
// If there's a point nearby
if (nearestPointX != 1000) {
if (nearestPointX > centerX) {
move = "E";
} else if (nearestPointX < centerX) {
move = "W";
} else if (nearestPointY > centerY) {
move = "S";
} else if (nearestPointY < centerY) {
move = "N";
}
}
But under certain conditions it will approach an area with multiple points, seemingly get confused and just pulsate back and forth over two blocks. It also seems sporadic with choosing the exact best block sometimes, which I assume is related.
I've read it over a million times and tried to debug it, but I just can't figure out what is causing the bug. Can anyone pinpoint what I'm doing wrong in finding the closest point?
Look at the comparison you're doing. totalDistance is equal to the number of steps from your current location to the point being considered, but totalBestDistance is the in-frame x,y coordinates of the previous "best point". So (for example) if you had points at (2, 4) and (3, 0), your code would:
Evaluate (2, 4) - distanceX is 0, distanceY is 2, totalDistance is 2. This updates
nearestPointX to 2 and nearestPointY to 4.
Evaluate (3, 0) - distanceX is 1, distanceY is 2. totalDistance is 3. totalBestDistance then becomes nearestPointX + nearestPointY, which is 6. So (3, 0) becomes your new "best point", even though your previous one was closer (actual distance was 2).
You problem is in totalBestDistance it should be updated in if and updated with totalDistance value. And declared outside of loops.
int totalBestDistance = MAX_INT;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
Field field = fields[i][j];
if (field.getType() == 0 && field.hasPoint()) {
int distanceX = Math.abs(i - centerX);
int distanceY = Math.abs(j - centerY);
int totalDistance = distanceX + distanceY;
if (totalDistance < totalBestDistance) {
totalBestDistance = totalDistance;
nearestPointX = i;
nearestPointY = j;
}
}
}
}

.intersects always returning true?

I've been working on a game with a mix of awt and slick2d (Rendering is done via awt). Anyway, i'm having a problem with collision. Inside of entity class, I have a collision method:
public boolean colidesWithWall(int idx, int idy) {
//if(Level.solid)
wall = new Rectangle(idx, idy, Tile.Size, Tile.Size);
if (this.getBoundingBox() == null) {
return false;
}
return this.getBoundingBox().intersects(wall);
}
Outside of this in my "Core.java" file, I have a for loop iterate the tiles through the colidesWithWall method. I also have an if statement in here so it will only check the tiles that are on the collision layer. (My map has four layers, Background, Collision, Items and Enemies).
for (int i = 0; i < entities.size(); i++) {
Entity me = entities.get(i);
for (int k = 0; k < 100; k++) {
for (int l = 0; l < 100; l++) {
if (Level.getColision(k, l)) {
Entity entity = entities.get(i);
if (entity.colidesWithWall(k, l)) {
entity.collidedWithWall();
frameCounter = 0;
}
}
}
}
}
Well anyway, what happens is, the game always detects a collision going on. Also, the players X&Y coordinates are defined by this:
((int) ((rouge.screenSize.width) / 2 - Tile.Size / 2 + rouge.oX)) / Tile.Size, ((int((rouge.screenSize.height) / 2 - Tile.Size / 2 + rouge.oY))/Tile.size
rouge.oY and rouge.oX are my camera offsets
Tile.Size is the size of my Tiles: 32
Here's a Screenshot of what happens: http://i.imgur.com/zYONBOC.png
The grey tiles and the tree are supposed to be causing collision, where as the brown ones are not.
Here is what I have for my game. I hope it somehow helps you as I'm not sure how I can help with just what you've given.
Getting the player's bounds:
private static Rectangle getPlayerBounds() {
return new Rectangle((int)player.getPositionX(), (int)player.getPositionY(), playerTexture.getImageWidth(), playerTexture.getImageHeight());
}
Getting the entity(in my case enemy)'s bounds:
private static Rectangle getEnemyBounds(Enemy e) {
return new Rectangle(e.getEnemyPosX(), e.getEnemyPosY(), enemyTexture.getImageWidth(), enemyTexture.getImageHeight());
}
then I have my checkCollision():
public static void checkCollisions() {
for(int i = 0; i < getEnemyList().size(); i++) {
Enemy tempEnemy = getEnemyList().get(i);
if (getPlayerBounds().intersects(getEnemyBounds(tempEnemy))) {
getEnemyList().remove(tempEnemy);
}
}
}
and in the end I just call it in my Movement.java:
MovementChecks.checkCollisions();

Categories

Resources