Recently I have been using the Polygon class to create asteroids as well as bullets and a spaceship. I am currently trying to create the collision detection for the program however it appears that the collision detection only works around 1/5 of the time (no pattern appears as to why it works).
Here's the code..
Creating the Polygon:
void renderPoly() {
int j;
int s = sides;
double r, angle;
int x, y;
for (j = 0; j < s; j++) {
angle = 2 * Math.PI / s * j;
r = MIN_ROCK_SIZE + (int) (Math.random() * (MAX_ROCK_SIZE - MIN_ROCK_SIZE));
x = (int) (r * Math.cos(angle));
y = (int) (r * -Math.sin(angle));
cOM[0] += x;
cOM[1] += y;
pointData[j][0] = x;
pointData[j][1] = y;
}
cOM[0] /= asteroidShape.npoints;
cOM[1] /= asteroidShape.npoints;
for (int i = 0; i < asteroidShape.npoints; i++) {
pointData[i][0] += cOM[0];
pointData[i][1] += cOM[1];
}
}
rotating and moving the polygon:
void move() {
int x, y, i;
//change rotation
theta += rotVel;
//change x
asteroidData[0] += deltaX;
//change y
asteroidData[1] += deltaY;
for (i = 0; i < asteroidShape.npoints; i++) {
x = (int) (pointData[i][0] * Math.cos(theta) - pointData[i][1] * Math.sin(theta) );
y = (int) (pointData[i][0] * Math.sin(theta) + pointData[i][1] * Math.cos(theta) );
asteroidShape.xpoints[i] = x + asteroidData[0];
asteroidShape.ypoints[i] = y + asteroidData[1];
asteroidShape.invalidate();
}
}
check if touching bullet:
boolean hitBullet(Bullet b) {
this.asteroidShape.invalidate();
for (int i = 0; i < b.bulletShape.npoints; i++)
if (this.asteroidShape.contains(b.bulletShape.xpoints[i], b.bulletShape.ypoints[i]) )
return true;
for (int j = 0; j < this.asteroidShape.npoints; j++)
if (b.bulletShape.contains(this.asteroidShape.xpoints[j], this.asteroidShape.ypoints[j]) )
return true;
return false;
}
(the ship method is the same except the constructor requires a ship object)
as well as the loop that calls it in the 'game' class:
for (int i = 0; i < aArray.length-1; i++) {
if (aArray[i] != null) {
for (int j = 0; j < bArray.length-1; j++) {
if (bArray[j] != null) {
if (aArray[i].hitBullet(bArray[j])) {
aArray[i] = null;
bArray[j] = null;
i = aArray.length-1;
j = bArray.length-1;
}
}
else {
i = aArray.length-1;
j = bArray.length-1;
}
}
}
else {
i = aArray.length-1;
}
}
I have been looking around at alternative solutions such as the Separating Axis Theorem however I do have convex polygons at times and since this method (.contains()) already exists I would like to use it.
Any help would be appreciated, thanks!
The easy way to solve this that I've found is to convert Shapes (in your case Polygon(2D?)) into Areas. You can use Area.intersect(Area) to see if two Areas have collided
Related
I wrote a function which takes two parameters:
JPG image as 3D array
rotation degrees given by alpha
My approach was:
public static int[][] rotate(int[][] img, double alpha) {
double rad = Math.toRadians(alpha);
double sin = Math.sin(rad);
double cos = Math.cos(rad);
int height = img.length;
int width = img[0].length;
int[][] rotate = new int[height][width];
for(int i = 0; i < height; i++) {
for(int j = height - i - 1; j < width; j++) {
if(j < height && i < width) {
double i_new = Math.floor(cos * (img[i].length - i) - sin * (img[j].length - j)) + i;
double j_new = Math.floor(sin * (img[i].length - i) + cos * (img[j].length - j)) + j;
rotate[i][j] = img[(int)j_new][(int)i_new];
}
}
}
return rotate;
}
While fixing the index range, the output is a black image. What am I missing?
After a while I got to a solution.
Caution: Its not using any special pre-defined libraries.
The global function which run`s over the matrice:
public static int[][] rotate(int[][] img, double alpha) {
double rad = Math.toRadians(alpha); //construct of the relevant angles
double sin = Math.sin(rad);
double cos = Math.cos(rad);
int height = img.length;
int width = img[0].length;
int[][] rotate = new int[height][width];
int a = height / 2; //we will use the area of a and b to compare coordinates by the formula given
int b = width / 2;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
double i_new = Math.floor(cos * (i - a) - sin * (j - b)) + a; // following the conversion function
double j_new = Math.floor(sin * (i - a) + cos * (j - b)) + b;
if (i_new >= rotate.length || i_new < 0 || j_new >= rotate[0].length || j_new < rotate[0][0]) { // if out of scope of the conversion --> print none
System.out.print(""); //mainly cause 'continue' statements are not necessary in java and JS
} else {
rotate[(int) i_new][(int) j_new] = img[i][j]; //convert
}
}
}
return rotate;
}
The global function which rotates each 2D matrice:
public static int[][][] rotate_alpha(int[][][] img, double alpha) {
int height = img[0].length;
int width = img[0][0].length;
int[][][] rotated = new int[3][height][width];
for (int k = 0; k < 3; k++) {
rotated[k] = rotate(img[k], alpha);
}
return rotated;
}
Hope this topic is solved by now, and stands by all the standards of the clean code.
I have a program in Java like this one (https://www3.ntu.edu.sg/home/ehchua/programming/java/J8a_GameIntro-BouncingBalls.html). It is the object oriented one after Example 2 but with some slightly changes.
I want to generate random coordinates for the balls to spawn. But they are not allowed to intersect each other at spawning moment. The generated coordinates are the top left corner of an rectangle around the circle.
So the coordinates need a minimum distance of 2 * ballRadius.
I only got ether coordinates that have the distance of 2 * ballRadius but then there are only unique coordinates for x and y. So i only got one ball per available y coordinate.
Example There could be a Ball at the red circle but the one left to it "blocks" the y coordinate.
Every other coordinates i get are intersecting each other.
Thats my code so far.
int uniqueXY[][] = new int[ballCount][2];
for (int i = 0; i < ballCount; i++) {
int tempx = 0;
int tempy = 0;
Boolean foundX = true;
Boolean foundY = true;
while(foundX && foundY) {
tempx = (int) (Math.random() * field.maxX); // generate random number in range of filed
tempy = (int) (Math.random() * field.maxY);
for (int j = 0; j < ballCount; j++) { // Here it should check if the number is within the given rules
if ((uniqueXY[j][0] - (2 * ballRadius) > tempx) || (uniqueXY[j][0] + (2 * ballRadius) < tempx)) {
foundX = false;
} else {
foundX = true;
if ((uniqueXY[j][1] - (2 * ballRadius) > tempy) || (uniqueXY[j][1] + (2 * ballRadius) < tempy)) {
foundY = false;
foundX = false;
break;
} else {
foundY = true;
break;
}
}
}
}
uniqueXY[i][0] = tempx;
uniqueXY[i][1] = tempy;
So I have come up with some new Code with the similar problem.
It calculates the distance between every set coordinate and the temporay ones. For the most part it works fine, it just behaves akward if I strees the code and force large numbers of balls.Example with 400 balls Only the balls at the border get forced together.
int uniqueXY[][] = new int[ballCount][2];
for (int k = 0; k < ballCount; k++) {
Boolean found = true;
while(found) {
int tempX = (int) (Math.random() * field.maxX); //create rnd x/y in range of field
int tempY = (int) (Math.random() * field.maxY);
if (k == 0) { // first case gets set, because nothing to compare
uniqueXY[k][0] = tempX;
uniqueXY[k][1] = tempY;
found = false;
break;
}
for (int j = 0; j < k; j++) { //calculates distance between every set coordinate and the temp
int erg1 = (int) (Math.pow(uniqueXY[j][0] - tempX, 2));
int erg2 = (int) (Math.pow(uniqueXY[j][1] - tempY, 2));
int distance = (int) Math.sqrt(erg1 + erg2);
if (distance < 60) { // if distance between coordinates < 60 temp gets discarded
found = true;
break;
}
if (j == k - 1) { // if every set case is checked and distance was always fine, temp gets set
uniqueXY[k][0] = tempX;
uniqueXY[k][1] = tempY;
found = false;
}
}
}
}
I am new to Perlin noise and I have hit a roadblock. The perlin noise function I have translated from C++ seems to work correctly for one octave, however I have found that the lower octaves of noise aren't added to the original Perlin Noise. Here is my code:
public class Perlin {
float[][] generateWhiteNoise(int width, int height) {
Random random = new Random(0);
float[][] noise = new float[width][height];
for (int i = 0; i < noise.length; i++) {
for (int j = 0; j < noise[i].length; j++){
noise[i][j] = (float)random.nextDouble();
}
}
return noise;
}
float[][] generateSmoothNoise(float[][] baseNoise, int octave){
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][] smoothNoise = baseNoise;
int samplePeriod = (int) Math.pow(2,octave); // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;
for (int i = 0; i < width; i++) {
//calculate the horizontal sampling indices
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
for (int j = 0; j < height; j++){
//calculate the vertical sampling indices
int sample_j0 = (j / samplePeriod) * samplePeriod;
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
float vertical_blend = (j - sample_j0) * sampleFrequency;
//blend the top two corners
float top = interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
//blend the bottom two corners
float bottom = interpolate(baseNoise[sample_i0][sample_j1],
baseNoise[sample_i1][sample_j1], horizontal_blend);
//final blend
smoothNoise[i][j] = interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
float interpolate(float x0, float x1, float alpha){
return (float) ((float)(x0) * (float)(1 - alpha) + (float)(alpha * x1));
}
float[][] generatePerlinNoise(float[][] baseNoise, int octaveCount) {
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
float persistance = .5f;
//generate smooth noise
for (int i = 0; i<octaveCount; i++) {
System.out.println("Generating Smooth Noise: " + i);
smoothNoise[i] = generateSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[width][height];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--) {
amplitude *= persistance;
totalAmplitude += amplitude;
System.out.println("Adding smooth noise for octave: " + octave + " at amplitude: " + amplitude);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalization
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
public float[][] printVals(float[][] baseNoise){
baseNoise = generatePerlinNoise(generateWhiteNoise(800,800),6);
for(int i = 0; i<baseNoise.length; i++){
String row = "";
for(int j = 0; j<baseNoise[i].length;j++){
row+= (int)(baseNoise[i][j]*255) + " ";
}
System.out.println(row);
}
return baseNoise;
}
}
Here is the code in that I use to get values:
baseNoise = generatePerlinNoise(generateWhiteNoise(800,800),6);
Here are the outputs at octaves 1,2,3, and 4
Any help would be appreciated!
Edit:
Through trial and error, I have found that the most likely area for there to be problems is in the generatePerlinNoise() function. If I change the octaves, I get the desired noise level, which is what I want. That also means that the generateWhiteNoise() and generateSmoothNoise() works. So, somewhere within the generatePerlinNoise() blending there is a problem, but it seems like it should work.
I have found an answer. I had thought that the generateSmoothNoise() command was going to give me multi-octave perlin noise. However, I realized that I needed to build another command similar to what happens with the blending of the smooth noise to blend my different octaves of perlin noise.
public float[][] generateMultiOctavePerlinNoise(int octaves, double persistence, double dropoff, int width, int height){
float[][][]noise = new float[octaves][width][height];
for(int i = octaves - 1; i > 0;i--){
noise[i] = generatePerlinNoise(generateWhiteNoise(width,height),octaves - i);
}
float[][] multiOctave = new float[width][height];
for(int a= 0; a<noise.length; a++){
persistence*= dropoff;
for(int i = 0; i<multiOctave.length; i++){
for(int j = 0; j<multiOctave[i].length; j++){
multiOctave[i][j] += noise[a][i][j]*persistence;
}
}
}
return multiOctave;
}
Whenever I tried to get the pixel array in the ori class, which extends the Screen class, to render to the canvas (that, in turn, is written in the canvas in the main class) it just generated a black image over the canvas in the JFrame. This only happened when the 'for' loops are written as "x = 0" as opposed to "int x = 0". When the loops are written as "int x = 0" or "int y= 0", it did not generate anything, including the black screen.
This is from the origin method in the ori class:
if(x <= ax && y <= ay){
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
pixels[x + y * width] = 0xff00ff;
}
}
}
screen class:
void waves(){
rand = new Random();
for(y = 0; y < height; y++){
int r = 24 + 1;
int s = 10;
waves++;
if(waves == 75){
sel = rand.nextInt(2);
waves = 0;
}
if(sel == 0){
if(blue > 0){
float f = ray - r;
double uir = f * 0.0001;
u = blue *= uir;
}
else{
}
}
if(sel == 1){
if(blue > 0){
float f = ray + r;
double uir = f * 0.0001;
u = blue *= uir;
}
else{
}
}
for(x = 0; x < width; x++){
Color wacol = new Color(0, 0, u);
int water = wacol.getRGB();
pixels[x + y * width] = water;
orga.origin();
}
}
}
It appears that the 'for' loops written as "x = 0" are called upon and then, somehow, render without reading the pixel array. The same happens when "int x = 0" but with the opposite result. What is causing this and what is causing the code to ignore the pixel array?
I've have this code and the balls bounces around, but when I apply some gravity I want them to stay on top of each other. But instead they slowly fall through.
Screenshot
Here's my code.
for (int i = 0; i < balls.size(); i++) {
Ball curr = balls.get(i);
if (curr.getPos().getX() - curr.radius <= 0) {
curr.getVel().mul(-0.9, 1);
curr.getPos().set(curr.radius, curr.getPos().getY());
} else if (curr.getPos().getX() + curr.radius >= WIDTH) {
curr.getVel().mul(-0.9, 1);
curr.getPos().set(WIDTH - curr.radius, curr.getPos().getY());
}
if (curr.getPos().getY() - curr.radius <= 0) {
curr.getVel().mul(1, -0.9);
curr.getPos().set(curr.getPos().getX(), curr.radius);
} else if (curr.getPos().getY() + curr.radius >= HEIGHT) {
curr.getVel().mul(1, -0.9);
curr.getPos().set(curr.getPos().getX(), HEIGHT - curr.radius);
}
for (int j = 0; j < balls.size(); j++) {
if (j == i) continue;
Ball other = balls.get(j);
double xDist = curr.getPos().getX() - other.getPos().getX();
double yDist = curr.getPos().getY() - other.getPos().getY();
double distance = xDist * xDist + yDist * yDist;
if (distance <= (curr.radius + other.radius) * (curr.radius + other.radius)) {
double xVel = other.getVel().getX() - curr.getVel().getX();
double yVel = other.getVel().getY() - curr.getVel().getY();
double dot = xDist * xVel + yDist * yVel;
if (dot > 0) {
double colScale = dot / distance;
double xCol = xDist * colScale;
double yCol = yDist * colScale;
double mass = curr.mass + other.mass;
double weightCurr = 2 * other.mass / mass;
double weightOther = 2 * curr.mass / mass;
curr.getVel().add(weightCurr * xCol, weightCurr * yCol);
other.getVel().sub(weightOther * xCol, weightOther * yCol);
curr.getPos().add(curr.getVel().mul(DMP));
other.getPos().sub(other.getVel().mul(DMP));
}
}
}
}
Thanks!
A line should be inserted after this one:
for (int j = 0; j < balls.size(); j++) {
if( j == i ) continue;
Otherwise each ball is balling with itself.
Another potential source of error is the way balls are bounced against the four walls and each other: The first ball is wall-checked and then bounces against all others, and only then are all others wall-checked.
for (int i = 0; i < balls.size(); i++) {
Ball curr = balls.get(i);
// wall checks
} // wall-check done!
for (int i = 0; i < balls.size(); i++) {
Ball curr = balls.get(i);
for (int j = 0; j < balls.size(); j++) {
if( j == i ) continue;
// ball - ball check ...
}
}
Also, if ball 1 passes the check with ball 2, but ball 2 is then pushed away by ball 3 into the radius of ball 1, overlaps may occur. Not sure how to cope with this: repeat ball-ball until no corrections are necessary?