Want to generate random set of coordinates (Java/Swing) - java

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;
}
}
}
}

Related

Java 2D Polygon - Polygon Collision Detection

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

Java - Detecting collisions via Array-stored collision

I am currently working on collision for my 2D game. I did some research and deducted that I should use the method of storing alpha value pixels into a "mask" of the image of the entity, and the same for the other. Then, I take both entitys' x & y co-ords, as well as height and width, and make a Rectangle object and use the method Rectangle.intersects(Rectangle r) to check if they do infact collide inorder to make it more efficent instead of going through 2 for loops.
IF they intersect, I then make a new Array with the dimensions :
int maxLengthY = Math.max(thisEntity.getMask().length, e.getMask().length);
int maxLengthX = Math.max(thisEntity.getMask()[0].length, thisEntity.getMask()[0].length);
int minX = Math.min(thisEntity.getX(), e.getX());
int minY = Math.min(thisEntity.getY(), e.getY());
int[][] map = new int[maxLengthX + minX][maxLengthY + minY];
and then add the other two masks onto this one with their corresponding y & x "boundaries", like so:
for(int curX = 0; curX < maxLengthX + minX; curX++) { //only loop through the co-ords that area affected
for(int curY = 0; curY < maxLengthY + minY; curY++) {
int this_x = thisEntity.getX();
int this_width = thisEntity.getImage().getWidth();
int this_y = thisEntity.getY();
int this_height = thisEntity.getImage().getHeight();
int[][] this_mask = thisEntity.getMask();
if(curX < (this_x + this_width) && curX < this_x) {//check that the co-ords used are relevant for thisEntity's mask
if(curY < (this_y + this_height) && curY < this_y) {
map[curX][curY] = this_mask[Math.abs(curX - this_x)][Math.abs(curY - this_y)]; // store data from mask to map
}
}
int other_x = e.getX();
int other_width = e.getImage().getWidth();
int other_y = e.getY();
int other_height = e.getImage().getHeight();
int[][] other_mask = e.getMask();
if(curX < (other_x + other_width) && curX > other_x) { //check that the co-ords used are relevant for e's mask
if(curY < (other_y + other_height) && curY > other_y) {
if(map[curX][curY] == 1) { //check if this segment is already written by thisEntity
map[curX][curY] = 2; //if yes, set to 2 instead of e's value to show collision
} else {
map[curX][curY] = other_mask[curX][curY]; // the minus to nullify minX and minY "requirements"
}
}
}
}
}
resulting in the Array "map" looking like SO:
(excuse my 1337 paint skills)
This is the code in all it's beauty:
public Entity[] collisions(Entity thisEntity) {
ArrayList<Entity> list = new ArrayList<Entity>();
try {
for (Entity e : getLevel().getEntities()) {
System.out.println("rect contains = "+thisEntity.getRect().contains(e.getRect()));
if (!thisEntity.equals(e)) {
Rectangle r = e.getRect();
r = thisEntity.getRect();
if (thisEntity.getRect().intersects(e.getRect())) {
//get variables to create a space designated for the intersection areas involved
int maxLengthY = Math.max(thisEntity.getMask().length, e.getMask().length);
int maxLengthX = Math.max(thisEntity.getMask()[0].length, thisEntity.getMask()[0].length);
int minX = Math.min(thisEntity.getX(), e.getX());
int minY = Math.min(thisEntity.getY(), e.getY());
int[][] map = new int[maxLengthX + minX][maxLengthY + minY]; //create a matrix which merges both Entity's mask's to compare
for(int curX = 0; curX < maxLengthX + minX; curX++) { //only loop through the co-ords that area affected
for(int curY = 0; curY < maxLengthY + minY; curY++) {
int this_x = thisEntity.getX();
int this_width = thisEntity.getImage().getWidth();
int this_y = thisEntity.getY();
int this_height = thisEntity.getImage().getHeight();
int[][] this_mask = thisEntity.getMask();
if(curX < (this_x + this_width) && curX > this_x) {//check that the co-ords used are relevant for thisEntity's mask
if(curY < (this_y + this_height) && curY > this_y) {
map[curX][curY] = this_mask[Math.abs(curX - this_x)][Math.abs(curY - this_y)]; // store data from mask to map
}
}
int other_x = e.getX();
int other_width = e.getImage().getWidth();
int other_y = e.getY();
int other_height = e.getImage().getHeight();
int[][] other_mask = e.getMask();
if(curX < (other_x + other_width) && curX > other_x) { //check that the co-ords used are relevant for e's mask
if(curY < (other_y + other_height) && curY > other_y) {
if(map[curX][curY] == 1) { //check if this segment is already written by thisEntity
map[curX][curY] = 2; //if yes, set to 2 instead of e's value to show collision
} else {
map[curX][curY] = other_mask[curX][curY]; // the minus to nullify minX and minY "requirements"
}
}
}
}
}
}
}
}
} catch (Exception excp) {
excp.printStackTrace();
}
return list.toArray(new Entity[1]);
}
Also, here is the method getMask() :
public int[][] getMask() {
return mask;
}
...
private void createMask(BufferedImage image) {
final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += 4) {
int alpha = pixels[pixel];
if(alpha != 0) {
result[row][col] = 1;
} else {
result[row][col] = 0;
}
if (col == width) {
col = 0;
row++;
}
}
}
mask = result;
}
However... this code does not work as intended, and in some cases at all as when adding the individual masks to the map I get IndexOutOfBounds even though it should work so it's probably just me overlooking something...
So, to conclude, I need help with my code:
What is wrong with it?
How can I fix it?
Is there a more efficent way of doing this type of collision?
Do you recommend other types of collision? If so, what are they?
When you create Entities, do you create their masks from images of the exact same size? Because otherwise entity's mask and image map would be using different coordinate systems (entity.mask[0][0] might be is at its corner, when map[0][0] is at the corner of the "world"), and you're comparing same indices at the line:
map[curX][curY] = other_mask[curX][curY];
(above in the code you're actually getting those to the same coordinate system with Math.abs(a-b))
As for more efficient ways to detect collisions, you can look into binary space partitioning and more on collision detection in general on Wikipedia.

For loops creating black screen without reading integer array

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?

2D elastic collision not working properly

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?

Processing/Line Graphing - Help

I posted something similar yesterday, but got nothing. I spent a few hours today problem-solving, but didn't progress any.
I'm using Processing (the language) and trying to implement a method that draws a line between two points. (I don't want to use the library's line() method.)
My lineCreate method works great for positive slopes, but fails with negative slopes. Can you help figure out why?
Here's the lineCreate() code:
void createLine(int x0, int y0, int x1, int y1){
//...
// Handle slanted lines...
double tempDX = x1 - x0;
double tempDY = y1 - y0; // Had to create dx and dy as doubles because typecasting dy/dx to a double data type wasn't working.
double m = (-tempDY / tempDX); // m = line slope. (Note - The dy value is negative
int deltaN = (2 * -dx); // deltaX is the amount to increment d after choosing the next pixel on the line.
int deltaNE = (2 * (-dy - dx)); // ...where X is the direction moved for that next pixel.
int deltaE = (2 * -dy); // deltaX variables are used below to plot line.
int deltaSE = (2 * (dy + dx));
int deltaS = (2 * dx);
int x = x0;
int y = y0;
int d = 0; // d = Amount d-value changes from pixel to pixel. Depends on slope.
int region = 0; // region = Variable to store slope region. Different regions require different formulas.
if(m > 1){ // if-statement: Initializes d, depending on the slope of the line.
d = -dy - (2 * dx); // If slope is 1-Infiniti. -> Use NE/N initialization for d.
region = 1;
}
else if(m == 1)
region = 2;
else if(m > 0 && m < 1){
d = (2 * -dy) - dx; // If slope is 0-1 -> Use NE/E initialization for d.
region = 3;
}
else if(m < 0 && m > -1){
d = (2 * dy) + dx; // If slope is 0-(-1) -> Use E/SE initliazation for d.
region = 4;
}
else if(m == -1)
region = 5;
else if(m < -1){
d = dy + (2 * dx); // If slope is (-1)-(-Infiniti) -> Use SE/S initialization for d.
region = 6;
}
while(x < x1){ // Until points are connected...
if(region == 1){ // If in region one...
if(d <= 0){ // and d<=0...
d += deltaNE; // Add deltaNE to d, and increment x and y.
x = x + 1;
y = y - 1;
}
else{
d += deltaN; // If d > 0 -> Add deltaN, and increment y.
y = y - 1;
}
}
else if(region == 2){
x = x + 1;
y = y - 1;
}
else if(region == 3){ // If region two...
if(d <= 0){
d += deltaE;
x = x + 1;
}
else{
d += deltaNE;
x = x + 1;
y = y - 1;
}
}
else if(region == 4){ // If region three...
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaE;
x = x + 1;
}
}
else if(region == 5){
x = x + 1;
y = y + 1;
}
else if(region == 6){ // If region four...
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaS;
y = y + 1;
}
}
point(x, y); // Paints new pixel on line going towards (x1,y1).
}
return;
}
Have a look at this page. It explains the whole theory behind line drawing with code examples.
There are a number of known algorithm for line drawing. Read about them here.

Categories