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've been given a 2D array of pixels and I am suppose to rotate this image based off of the pixel array about it's centermost point. I've tried to implement code which rotates the image based off of the rotation matrix, but I haven't been successful so far.
Current 2D Array Rotation Code:
int width = originalImage.length;
int height = originalImage[0].length;
final double angle = 90;
int[][] array = new int[width][height];
double c = Math.cos(Math.toRadians(angle));
double s = Math.sin(Math.toRadians(angle));
int x = width / 2;
int y = height / 2;
for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy++) {
int xp = xx - x;
int yp = yy - y;
int xa = (int)((float)((float)xp * c - (float)yp * s));
int ya = (int)((float)((float)xp * s + (float)yp * c));
xa += x;
ya += y;
xp += x;
yp += y;
if(xa < width && ya < height) array[xa][ya] = originalImage[xp][yp];
//System.out.print("\n"+xa+" "+ya);
}
}
I've also tried this:
int[][] array = new int[originalImage.length][originalImage[0].length];
int xx = 0, yy = 0;
for (int x = originalImage.length - 1; x >= 0; x--) {
xx = 0;
for (int y = 0; y < originalImage[x].length; y++) {
//System.out.println(array[yy][xx]);
//System.out.println(originalImage[y][x]);
if (y < originalImage.length && x < originalImage[x].length) {
array[yy][xx] = originalImage[y][x];
//System.out.print(array[yy][xx]);
}
xx++;
}
yy++;
}
Are there any suggestion to how I can improve my code, or how this should be done?
since you are rotating by 90 degrees you can skip a bit
// origin to center point
int xp = xx - x;
int yp = yy - y;
// rotation and origin back to (0,0)
int x_rotated = -yp + y;
int y_rotated = xp + x;
//
array[x_rotated][y_rotated] = originalImage[xx][yy];
If you want to rotate in a different direction change
int x_rotated = yp + y;
int y_rotated = -xp + x;
i want to paint black and white stripes on the image, switching every 20th column both horizontally and vertically on top of an image while staying inside it's borders. so far i can get a black square with 1 pixel wide vertical stripes. i've tried to at least get skinny white stripes on my horizontal lines by switching things around but it's still vertical.
public void zebraStripes() {
Image img = ImageViewer.getImage();
double numPixelsWide = img.getWidth();
int numPixelsHigh = img.getHeight();
Color c = Color.WHITE;
Color b = Color.BLACK;
double i = numPixelsWide;
if (i % 20 == 0) {
for (int x = 0; x < numPixelsHigh; x++) {
for (int y = 0; y < i; y++) {
img.setPixelColor(y, x, b);
}
for (int z = 19; z < i; z = z + 20) {
img.setPixelColor(z, x, c);
}
}
}
}
// paint black and white stripes (left to right) on the image, switching
// every 20th row
public void jailBird() {
Image img = ImageViewer.getImage();
double numPixelsWide = img.getWidth();
double numPixelsHigh = img.getHeight();
Color c = Color.WHITE;
Color b = Color.BLACK;
double i = numPixelsHigh;
if (i % 20 == 0) {
for (int x = 0; x < numPixelsHigh; x++) {
for (int y = 0; y < i; y++) {
img.setPixelColor(y, x, b);
}
for (int z = 19; z < i; z = z + 20) {
img.setPixelColor(z, x, c);
}
}
}
}
}
how do i get the white stripes to be 20 pixels wide and horizontal?
Not tested! Hope it gets you going.
// paint a 20 pixels wide horizontal line for every 40 pixels
for (int y = 0; y < numPixelsHigh; y += 40) {
// paint a stripe
for (int ys = y; ys < y + 20; ys++) {
for (int x = 0; x < numPixelsWide; x++) {
img.setPixelColor(x, ys, Color.BLACK);
}
}
}
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
I have a sprite sheet which has each image centered in a 32x32 cell. The actual images are not 32x32, but slightly smaller. What I'd like to do is take a cell and crop the transparent pixels so the image is as small as it can be.
How would I do that in Java (JDK 6)?
Here is an example of how I'm currently breaking up the tile sheet into cells:
BufferedImage tilesheet = ImageIO.read(getClass().getResourceAsStream("/sheet.png");
for (int i = 0; i < 15; i++) {
Image img = tilesheet.getSubimage(i * 32, 0, 32, 32);
// crop here..
}
My current idea was to test each pixel from the center working my way out to see if it is transparent, but I was wondering if there would be a faster/cleaner way of doing this.
There's a trivial solution – to scan every pixel. The algorithm bellow has a constant performance of O(w•h).
private static BufferedImage trimImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int top = height / 2;
int bottom = top;
int left = width / 2 ;
int right = left;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (image.getRGB(x, y) != 0){
top = Math.min(top, y);
bottom = Math.max(bottom, y);
left = Math.min(left, x);
right = Math.max(right, x);
}
}
}
return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
}
But this is much more effective:
private static BufferedImage trimImage(BufferedImage image) {
WritableRaster raster = image.getAlphaRaster();
int width = raster.getWidth();
int height = raster.getHeight();
int left = 0;
int top = 0;
int right = width - 1;
int bottom = height - 1;
int minRight = width - 1;
int minBottom = height - 1;
top:
for (;top <= bottom; top++){
for (int x = 0; x < width; x++){
if (raster.getSample(x, top, 0) != 0){
minRight = x;
minBottom = top;
break top;
}
}
}
left:
for (;left < minRight; left++){
for (int y = height - 1; y > top; y--){
if (raster.getSample(left, y, 0) != 0){
minBottom = y;
break left;
}
}
}
bottom:
for (;bottom > minBottom; bottom--){
for (int x = width - 1; x >= left; x--){
if (raster.getSample(x, bottom, 0) != 0){
minRight = x;
break bottom;
}
}
}
right:
for (;right > minRight; right--){
for (int y = bottom; y >= top; y--){
if (raster.getSample(right, y, 0) != 0){
break right;
}
}
}
return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
}
This algorithm follows the idea from pepan's answer (see above) and is 2 to 4 times more effective. The difference is: it never scans any pixel twice and tries to contract search range on each stage.
The worst case of the method's performance is O(w•h–a•b)
This code works for me. The algorithm is simple, it iterates from left/top/right/bottom of the picture and finds the very first pixel in the column/row which is not transparent. It then remembers the new corner of the trimmed picture and finally it returns the sub image of the original image.
There are things which could be improved.
The algorithm expects, there is the alpha byte in the data. It will fail on an index out of array exception if there is not.
The algorithm expects, there is at least one non-transparent pixel in the picture. It will fail if the picture is completely transparent.
private static BufferedImage trimImage(BufferedImage img) {
final byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
int width = img.getWidth();
int height = img.getHeight();
int x0, y0, x1, y1; // the new corners of the trimmed image
int i, j; // i - horizontal iterator; j - vertical iterator
leftLoop:
for (i = 0; i < width; i++) {
for (j = 0; j < height; j++) {
if (pixels[(j*width+i)*4] != 0) { // alpha is the very first byte and then every fourth one
break leftLoop;
}
}
}
x0 = i;
topLoop:
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
if (pixels[(j*width+i)*4] != 0) {
break topLoop;
}
}
}
y0 = j;
rightLoop:
for (i = width-1; i >= 0; i--) {
for (j = 0; j < height; j++) {
if (pixels[(j*width+i)*4] != 0) {
break rightLoop;
}
}
}
x1 = i+1;
bottomLoop:
for (j = height-1; j >= 0; j--) {
for (i = 0; i < width; i++) {
if (pixels[(j*width+i)*4] != 0) {
break bottomLoop;
}
}
}
y1 = j+1;
return img.getSubimage(x0, y0, x1-x0, y1-y0);
}
I think this is exactly what you should do, loop through the array of pixels, check for alpha and then discard. Although when you for example would have a star shape it will not resize the image to be smaller be aware of this.
A simple fix for code above. I used the median for RGB and fixed the min() function of x and y:
private static BufferedImage trim(BufferedImage img) {
int width = img.getWidth();
int height = img.getHeight();
int top = height / 2;
int bottom = top;
int left = width / 2 ;
int right = left;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (isFg(img.getRGB(x, y))){
top = Math.min(top, y);
bottom = Math.max(bottom, y);
left = Math.min(left, x);
right = Math.max(right, x);
}
}
}
return img.getSubimage(left, top, right - left, bottom - top);
}
private static boolean isFg(int v) {
Color c = new Color(v);
return(isColor((c.getRed() + c.getGreen() + c.getBlue())/2));
}
private static boolean isColor(int c) {
return c > 0 && c < 255;
}
[Hi I tried the following. In the images file idle1.png is the image with a big transparent box while testing.png is the same image with minimum bounding box
'BufferedImage tempImg = (ImageIO.read(new File(fileNPath)));
WritableRaster tempRaster = tempImg.getAlphaRaster();
int x1 = getX1(tempRaster);
int y1 = getY1(tempRaster);
int x2 = getX2(tempRaster);
int y2 = getY2(tempRaster);
System.out.println("x1:"+x1+" y1:"+y1+" x2:"+x2+" y2:"+y2);
BufferedImage temp = tempImg.getSubimage(x1, y1, x2 - x1, y2 - y1);
//for idle1.png
String filePath = fileChooser.getCurrentDirectory() + "\\"+"testing.png";
System.out.println("filePath:"+filePath);
ImageIO.write(temp,"png",new File(filePath));
where the get functions are
public int getY1(WritableRaster raster) {
//top of character
for (int y = 0; y < raster.getHeight(); y++) {
for (int x = 0; x < raster.getWidth(); x++) {
if (raster.getSample(x, y,0) != 0) {
if(y>0) {
return y - 1;
}else{
return y;
}
}
}
}
return 0;
}
public int getY2(WritableRaster raster) {
//ground plane of character
for (int y = raster.getHeight()-1; y > 0; y--) {
for (int x = 0; x < raster.getWidth(); x++) {
if (raster.getSample(x, y,0) != 0) {
return y + 1;
}
}
}
return 0;
}
public int getX1(WritableRaster raster) {
//left side of character
for (int x = 0; x < raster.getWidth(); x++) {
for (int y = 0; y < raster.getHeight(); y++) {
if (raster.getSample(x, y,0) != 0) {
if(x > 0){
return x - 1;
}else{
return x;
}
}
}
}
return 0;
}
public int getX2(WritableRaster raster) {
//right side of character
for (int x = raster.getWidth()-1; x > 0; x--) {
for (int y = 0; y < raster.getHeight(); y++) {
if (raster.getSample(x, y,0) != 0) {
return x + 1;
}
}
}
return 0;
}'[Look at Idle1.png and the minimum bounding box idle = testing.png][1]
Thank you for your help regards Michael.Look at Idle1.png and the minimum bounding box idle = testing.png]images here
If your sheet already has transparent pixels, the BufferedImage returned by getSubimage() will, too. The default Graphics2D composite rule is AlphaComposite.SRC_OVER, which should suffice for drawImage().
If the sub-images have a distinct background color, use a LookupOp with a four-component LookupTable that sets the alpha component to zero for colors that match the background.
I'd traverse the pixel raster only as a last resort.
Addendum: Extra transparent pixels may interfere with collision detection, etc. Cropping them will require working with a WritableRaster directly. Rather than working from the center out, I'd start with the borders, using a pair of getPixels()/setPixels() methods that can modify a row or column at a time. If a whole row or column has zero alpha, mark it for elimination when you later get a sub-image.