Isometric map drawing, generating [closed] - java

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am making an isometric game and I only managed to create a zigzag isometric map. My original idea was diamond shape but I cant manage to do so.
Diamond:
coobird.net/img/tile-diamond-good-order.png
Zigzag:
coobird.net/img/tile-zigzag-compact.png
Here is a bit of my code to show you what is happening:
World:
public void chunkGenerate() {
moduleX = ((ListManager.getTileWidth()*8));
moduleY = ((ListManager.getTileHeight()*8));
for (int x = 0; x <= width; x++) {
for (int y = 0; y <= height; y++) {
if ((x%moduleX) == 0) {
if ((y%moduleY) == 0) {
chunkList.add(new Chunk(x,y));
}
}
}
}
}
Chunk:
public void Generate() {
for (int x = 0; x < 8; x++) {
for (int y = 0;y< 8; y++) {
tileList.add(new Tile(location.getX()+(x*ListManager.getTileWidth()),location.getY()+(y*ListManager.getTileHeight()),0));
}
}
}
Rendering:
for (Chunk c : w.getChunkList()) {
g2d = (Graphics2D) g.create();
for (int i = 0; i<c.getTileList().size(); i+=2) {
g2d.drawImage(test2, (c.getTileList().get(i).getLocation().getX()+c.getTileList().get(i).getOffset().getxOffset()), (c.getTileList().get(i).getLocation().getY()+c.getTileList().get(i).getOffset().getyOffset()+w.getvOffset()), this);
g2d.drawImage(test2, (c.getTileList().get(i).getLocation().getX()), (c.getTileList().get(i).getLocation().getY()+w.getvOffset()), this);
}
for (int i = 1;i<c.getTileList().size(); i+=2) {
g2d.drawImage(test2, (c.getTileList().get(i).getLocation().getX()), (c.getTileList().get(i).getLocation().getY()+w.getvOffset()), this);
g2d.drawImage(test2, (c.getTileList().get(i).getLocation().getX()+c.getTileList().get(i).getOffset().getxOffset()), (c.getTileList().get(i).getLocation().getY()+c.getTileList().get(i).getOffset().getyOffset()+w.getvOffset()), this);
}
}
I need help with making the map into a diamond, instead of zigzag. If you need further information on the code, comment below. Also one bug with this code is that there is like a 1 pixel wide space every couple of tiles. I don't know why.. I tried adjusting the offsets, didn't help..
Current offsets: (Tile constructor)
offset = new IsometricOffset(21,11);
Closest I got to having no space was 20,10 but there was still a tiny space
here is a pic:
http://img845.imageshack.us/img845/6242/picbz.png
Thanks for the help!
edit:
Apparently two of the tiles on the screen are actually only 1 tile in the engine. I am working on fixing it.
EDIT:
Changed and got this:
img526.imageshack.us/img526/3121/test333.png
drawing:
for (Chunk c : w.getChunkList()) {
/*for (int i = 0; i<c.getTileList().size(); i++) {
g2d.drawImage(test2, (c.getTileList().get(i).getLocation().getX()), (c.getTileList().get(i).getLocation().getY()+w.getvOffset()), this);
}*/
for (int i = 0;i<c.getTileList().size(); i++) {
g2d.drawImage(test2, (c.getTileList().get(i).getLocation().getX()+c.getTileList().get(i).getOffset().getxOffset()), (c.getTileList().get(i).getLocation().getY()+c.getTileList().get(i).getOffset().getyOffset()+w.getvOffset()), this);
}
}
(I tried drawing without the offsets it drew the same thing as the picture)
Generating:
for (int x = 0; x < 8; x++) {
for (int y = 0;y< 8; y++) {
tileList.add(new Tile(location.getX()+(x*ListManager.getTileWidth()/2),location.getY()+(y*ListManager.getTileHeight()/2),0));
}
location.setX(location.getX()+ListManager.getTileWidth()/2);
location.setY(location.getY()+ListManager.getTileHeight()/2);
}
After experimenting:
Generate:
public void Generate() {
for (int x = 0; x < 8; ++x) {
for (int y = 0;y< 8; ++y) {
tileList.add(new Tile(location.getX()+(y*ListManager.getTileWidth()/2),location.getY()-(y*ListManager.getTileHeight()/2),0));
}
location.setX(location.getX()+ListManager.getTileHeight()/2);
location.setY(location.getY()+ListManager.getTileWidth()/2);
}
}
result: This is the closest i got:
http://img814.imageshack.us/img814/3450/bombombom.png

Try to imagine your map rotated by 45 degree.
(0, 3)
(0, 2) (1, 2)
(0, 1) (1, 1) (2, 2)
(1, 0) (2, 1)
(2, 0)
And the rendering cycle must be like that:
x = 0, y = 100,
for (dx = 0; dx < 3; ++dx) {
for (dy = 0; dy < 3; ++dy) {
drawTile(x + dy * width / 2, y - dy * height / 2);
}
x += width / 2;
y += height / 2;
}
UPD: Proof of working.
Code (actionscript, but there is no difference for algorithm):
var x:Number = 100, y:Number = 100,
dx:Number, dy:Number, px:Number, py:Number,
halfWidth:Number = 40, halfHeight:Number = 20,
s:Sprite = new Sprite(),
g:Graphics = s.graphics;
g.lineStyle(1, 0xffffff);
for (dx = 0; dx < 3; ++dx) {
for (dy = 0; dy < 3; ++dy) {
px = x + dy * halfWidth;
py = y - dy * halfHeight;
g.moveTo(px - halfWidth , py);
g.lineTo(px, py - halfHeight);
g.lineTo(px + halfWidth, py);
g.lineTo(px, py + halfHeight);
g.lineTo(px - halfWidth, py);
}
x += halfWidth;
y += halfHeight;
}
addChild(s);
Result:

Related

How to layer graphics in java?

I am trying to make my own version of checkers and I have currently written the code to store draw the board and the pieces.
Every time I run the code I get a different result because the board is being drawn over some pieces. How do I get all the pieces to appear over the board all the time? I understand similar questions have been asked but they don't provide any useful help.
Here's the code that is draws the board:
public void paint(Graphics gr) {
Graphics2D gr2D = (Graphics2D) gr;
gr2D.setColor(color1);
BasicStroke stroke = new BasicStroke(strokeThickness,
BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND);
gr2D.setStroke(stroke);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
gr.setColor((gr.getColor() == color2)
? color1 : color2);
gr.fillRect((int) (start + CHANGEVAL * i),
(int) (start + CHANGEVAL * j),
(int) CHANGEVAL,
(int) CHANGEVAL);
}
gr.setColor((gr.getColor() == color2)
? color1 : color2);
}
}
And here's the code that draws the pieces:
public static void setPieces() {
posX = 0;
posY = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
aryPiecePos[posX][posY] = SQUARE_STATE_RED;
board.repaint(board.getCoordX(posX), board.getCoordY(posY), Color.RED);
posX += 2;
}
posX = (posX == 8 ? 1 : 0);
posY += 1;
}
posX = 1;
posY = 5;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
aryPiecePos[posX][posY] = SQUARE_STATE_BLACK;
board.repaint(board.getCoordX(posX), board.getCoordY(posY), Color.BLACK);
posX += 2;
}
posX = (posX == 8 ? 1 : 0);
posY += 1;
}
}
Also here's a link to all my code:
Here's a hyperlink to what I have currently: https://drive.google.com/open?id=0B2uJqRSB8ckHYW53NmZsZDdxWWs
What you draw first will be in a deeper layer so to speak.
g.setColor(Color.BLUE);
g.fillRect(x, y, width, height);
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
With the above code the blue rectangle will not be visible, since the green one is drawn over it.
Therefore to solve your problem you need to draw the board first, then all the pieces.

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

Won't Draw Tiles?

Well, I'm making a relatively simple platformer game with java and I have a method that generates the level, but the tiles won't draw.
public void generateDungeon() {
int y = 30;
for(int x = 0; x < block[0].length; x++) {
block[x][y] = new Block(new Rectangle(x * Tile.tileSize, y * Tile.tileSize, Tile.tileSize, Tile.tileSize), Tile.basic);
}
}
I want the Y to stay the same so that's why it has a set value.
That is where I think the problem lies, but here's the console message
Exception in thread "Thread-2" java.lang.NullPointerException
at mineandbuild.Player.isCollidingWithBlock(Player.java:82)
at mineandbuild.Player.tick(Player.java:22)
at mineandbuild.Component.tick(Component.java:89)
at mineandbuild.Component.run(Component.java:110)
at java.lang.Thread.run(Unknown Source)
The console says the problem is at this line of code:
public boolean isCollidingWithBlock(Point pt1, Point pt2) {
for(int x = (int) (this.x / Tile.tileSize); x < (int) (this.x / Tile.tileSize + 3); x++) {
for(int y = (int) (this.y / Tile.tileSize); y < (int) (this.y / Tile.tileSize + 3); y++) {
if(x >= 0 && y >= 0 && x < Component.dungeon.block.length && y < Component.dungeon.block[0].length)
This line ---> if(Component.dungeon.block[x][y].id != Tile.air) {
if(Component.dungeon.block[x][y].contains(pt1) || Component.dungeon.block[x][y].contains(pt2)) {
return true;
}
}
}
}
return false;
}
Thanks!
Try printing out the x and y values for
if(Component.dungeon.block[x][y].id != Tile.air) {
You say that in the code before the value of y should stay the same, which means for every other index of y in the 2-d array they're set to null, but in the forloop you have this
for(int y = (int) (this.y / Tile.tileSize); y < (int) (this.y / Tile.tileSize + 3); y++) {
which leads me to believe that you're trying to access indices that are null, then trying to access the "id" field, except that that object doesn't exist.
block[x][y] might not have been initialized for all y values... as in genrateDunegeon() method you are initializing block[x][30] for all values of x.
So question is what for other values of y... did you initialized it in your not shown code snippet.
Until you will not initialize, exception will generate.
I think this may work.....(although not sure..)
public void generateDungeon()
{
for(int x = 0; x < block[0].length; x++)
{
for (int y=0; /*your termination condition like y<n */; y++)
if(y == 30)
block[x][y] = new Block(new Rectangle(x * Tile.tileSize, y * Tile.tileSize, Tile.tileSize, Tile.tileSize), Tile.basic);
else
block[x][y] = new Block(null);
}
}
and handle null value in Block constructor.

What's wrong with this Java code for Android?

I have written this piece of code to break an image into 9 pieces and it gives me runtime error. There is no error in LogCat and I am stuck. The error comes at line 7 line from bottom (Bitmap.createBitmap(...);).
public Bitmap[] getPieces(Bitmap bmp) {
Bitmap[] bmps = new Bitmap[9];
int width = bmp.getWidth();
int height = bmp.getHeight();
int rows = 3;
int cols = 3;
int cellHeight = height / rows;
int cellWidth = width / cols;
int piece = 0;
for (int x = 0; x <= width; x += cellWidth) {
for (int y = 0; y <= height; y += cellHeight) {
Bitmap b = Bitmap.createBitmap(bmp, x, y, cellWidth,
cellHeight, null, false);
bmps[piece] = b;
piece++;
}
}
return bmps;
}
It is a limitation of android framework which doesn't give proper error message. The ideal solution would be to wrap your code in try / catch block and log the exception to console and fix your code accordingly, but use it only for debugging purposes.
try {
// Code
}
catch (Exception e) {
Log.e("ERROR", "ERROR IN CODE:"+e.toString());
}
The above code extracted from here:
http://moazzam-khan.com/blog/?p=41
Instead of
for (int x = 0; x <= width; x += cellWidth) {
for (int y = 0; y <= height; y += cellHeight) {
use
for (int x = 0; x+cellWidth < width; x += cellWidth) {
for (int y = 0; y+cellHeight < height; y += cellHeight) {
to avoid fetching parts of the image that (at least partly) don't exist.
In your code, piece can be greater than 8, so you are getting index out of bounds on bmps. You need to rewrite it so that the right-most and bottom-most pieces just have all of the extra and aren't necessarily the same size.
Or, if you need them to be the same size, drop the extra rows/cols. To make sure, I would formulate my for loop like this
for (int cellX = 0; cellX < 3; cellX++) {
int x = cellX * cellWidth;
for (int cellY = 0; cellY < 3; cellY++) {
int y = cellY * cellHeight;
// find the cellWidth/Height that doesn't overflow the original image
Bitmap b = // get the bitmap
bmps[piece] = b;
piece++;
}
}

Crop image to smallest size by removing transparent pixels in java

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.

Categories