I've been trying to chop up a larger picture and use it as tiles for a game. I had the program working using fillRect() to simulate the image. However, when I replace the fillRect code, it crashes. Here is what I've been using:
buffer.drawImage(section[i][j].getSectionImage(i, j),
sectionSize * i + OFFSETx,
sectionSize * j + OFFSETy,
this);
public class Section{
private static ImageIcon ii;
private static Image mainImage;
private Image sectionImage;
public Section(){
if (ii == null){
ii = new ImageIcon(this.getClass().getResource("images/Mossy_rocks.png"));
mainImage = ii.getImage();
}
}
public Image getSectionImage(int x, int y){
sectionImage = createImage(new FilteredImageSource(mainImage.getSource(),
new CropImageFilter(1,1,20,20))); //test values
return sectionImage;
}
}
I tried "extends JApplet/JFrame/JComponent" for the Section Class, but it didn't seem to help.
Edit: I would also like to mention that if I would just return mainImage from getSectionImage(), I get the image. I think the biggest problem is the rest of that function... but I'm not sure, so I included everything I needed to add when replacing fillRect().
I found a much better way to crop this image. Here is how I did it:
screenImage.drawImage(Image sprite,
int (x position on screen),
int (y position on screen),
int (x position on screen + width),
int (y position on screen + height),
int (x position from sprite),
int (y position from sprite),
int (x position from sprite + width),
int (y position from sprite + height),
null);
Related
Faced a problem while trying to handle clicking on a moving image.
I used InputAdapter.touchDown() to handle the click and created Sprite for the image. Then I set the borders through Sprite.setBounds(). Further, in fact, the problem: if the coordinates in setBounds() are unchanged - the click is handled correctly. But if you change them (position.x++, for example) - the object comes into motion, but clicks are not read.
I can’t understand where the reason.
I tried to make a alterable variable outside the method, but this also didn't bring any result.
I tried using batch.draw(img) instead of img.draw(batch) - the effect is the same.
I tried to relocate Gdx.input.setInputProcessor() to the render() method, after img.setBounds() - nothing changed.
I even compared the coordinates of the Img and the Bounds area online, in motion - they are the same, as it should be.
Img and handler in constructor:
img = new Sprite(new Texture(finSize));
centerX = Gdx.graphics.getWidth()/2-img.getWidth()/2;
centerY = Gdx.graphics.getHeight()/2-img.getHeight()/2;
startPosition = new Vector2(centerX, centerY);
Gdx.input.setInputProcessor(new InputAdapter(){
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if(img.getBoundingRectangle().contains(screenX, screenY))
System.out.println("Image Clicked");
return true;
}
});
Render:
public void render(SpriteBatch batch, float radius, float boost) {
speed+=boost;
nextX = radius * (float) Math.cos(speed); // Offset step X
nextY = radius * (float) Math.sin(speed); // Offset step Y
// Img is moving, but clicks is not handling
img.setBounds(startPosition.x+ nextX, startPosition.y + nextY, 100, 100);
// Handling clicks fine, but img is motionless
img.setBounds(startPosition.x, startPosition.y, 100, 100);
img.draw(batch);
// Checking coordinates - all's fine
System.out.println(img.getBoundingRectangle().getX());
System.out.println(startPosition.x + nextX);
System.out.println(img.getBoundingRectangle().getY());
System.out.println(startPosition.y + nextY);
}
So, I sequentially compared the XY coordinates of the image and the mouse click point and came to the conclusion that InputAdaper and Sprite consider Y differently - from above and from below. Therefore, X always coincided, and Y had a big difference in values.
As a result, I entered two corrected coordinates xPos \ yPos (Y subtracted from the total field height) for the center of the pic and in the touchDown() method, instead of comparing with BoundRectangle, simply compared the difference in the coordinates of the pic and the click modulo. If the result into the image size range - everything is ok.
Now clicks on the moving image works correctly.
public void render(SpriteBatch batch, float radius, float boost) {
speed+=boost; // rotational speed
nextX = radius * (float) Math.cos(speed); // Offset step X
nextY = radius * (float) Math.sin(speed); // Offset step Y
// set image size and position
img.setBounds(startPosition.x+nextX, startPosition.y+nextY, 100, 100);
img.draw(batch);
// Corrected coordinates of the image for InputAdapter coordinate system
xPos = img.getX()+img.getWidth()/2;
yPos = Gdx.graphics.getHeight()-img.getY()- img.getHeight()/2;
// Check the coincidence of the coordinates of the image area and the click point
Gdx.input.setInputProcessor(new InputAdapter(){
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if((Math.abs(xPos-screenX)<=img.getWidth()) && (Math.abs(yPos-screenY)<=img.getHeight()))
{System.out.println("Image Clicked");}
return true;
}
});
}
Hi there and thanks for reading,
I have a Map initialized as follows:
static HashMap<Point, Tile> map = new HashMap<Point, Tile>();
a Tile is a small class that holds an image and a function called addFloor(int tileCode):
class Tile {
BufferedImage img;
int imgHeight, imgWidth;
public Tile(BufferedImage img) {
this.img = img;
imgHeight = img.getHeight();
imgWidth = img.getWidth();
}
public Tile addFloor(int tileCode) {
BufferedImage newImg = Helper.joinBufferedImageFloor(this.img, Map.buildings.get(tileCode).img);
Tile newTile = new Tile(newImg);
return newTile;
}
}
The addFloor(int tileCode) function just puts an image obtained by another map via the tileCode as key (Map is just another class that holds the map of Tiles and maps of asset images, and also some unimportant functions for now) on top of the Tile image (this.img) with an offset.
(Are you still with me or do i need to give more info?)
and now:
Tile tileDebug = Map.map.get(new Point(10, 10));
Map.map.replace(new Point(10, 10), Map.map.get(new Point(10, 10)).addFloor(tileCode)); //I've also tried map.put()
tileDebug = Map.map.get(new Point(10, 10)); //MARK 1
panel.repaint();
I checked via eclipse debugger and I checked the addFloor(int tileCode) function seperated:
-the addFloor(int tileCode) function works perfectly. It creates a new image and returns a completely new Tile with the correct image.
-using the debugger I saw that the Tile updated, it changed its image and has another hash now (same as returned by addFloor(int tileCode)).
-Currently the paintComponent(Graphics g) function has just one call to drawMap(Graphics2D g2d) which draws Tile by Tile.
-Since the map.replace() call the map hasn't been edited.
private void drawMap(Graphics2D g2d) {
if (map != null) {
for (int y = 1; y <= 100; y++) {
for (int x = 1; x <= 100; x++) {
Tile currentTile = Map.map.get(new Point(x, y)); //MARK 2
if (x == 10 && y == 10) {
//This line is just so I can add a breakpoint to debug the tile currentTile
System.out.println("");
} //Unimportant from here, just positioning and drawing, that works perfectly
int dx = 350, dy = 0;
dx += Main.viewX;
dy += Main.viewY;
int posX, posY;
posX = (int) ((x * 64 + y * -64));
posY = (int) ((x * 32 + y * 32));
posX -= currentTile.imgWidth;
posY -= currentTile.imgHeight;
g2d.drawImage(currentTile.img, posX + dx, posY + dy, this);
}
}
}
}
The problem is that the drawn Tile isn't the old Tile, it isn't the Tile that got returned by addFloor(int tileCode). The drawn Tile is a new one, with its own hash and image. The image that is drawn is the second image passed to joinBufferedImageFloor(BufferedImage img1, BufferedImage img2) (the one obtained via the tileCode in addFloor(int tileCode).
I followed my entire program from //MARK 1 to //MARK 2, but the map never got explicitly edited but the return value of
Map.map.get(new Point(10, 10))
changed from the correct Tile (MARK 1) to the third Tile (MARK 2)
Is it because the Map is static? (Note: Only 2 Threads explicitly edit the Map, the Main Thread and a KeyListener Thread, but in this use case this Thread wasn't involved)
Whats wrong here?
Am I getting something wrong about Java Maps?
Any help appreciated thanks in advance
Edit 1min after posting it:
I think I described it a bit confusing here and there so please ask any question that might be unanswered in this description.
On wish I can also provide you with the full Project setup etc...
Edit few Hours after:
Edited the Question according to the how-to-ask section of StackOverflow
Edit for anyone interested the joinBufferedImageFloor(BufferdImage img1, BufferedImage img2) function:
public static BufferedImage joinBufferedImageFloor(BufferedImage img1, BufferedImage img2) {
int offsetX = 16;
int offsetY = -32;
int width = img1.getWidth();
int height = img1.getHeight() - offsetY;
BufferedImage newImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = newImage.createGraphics();
Color oldColor = g2.getColor();
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, width, height);
g2.setColor(oldColor);
g2.drawImage(img1, null, 0, -offsetY);
g2.drawImage(img2, null, offsetX, 0);
g2.dispose();
return newImage;
}
I am making a game in Android that requires a list of sprites to running from right to left so I try to flip the image using the code below.
It slows the game speed down so much, moves fast running to the right but slows down so much running to the left.
public void Draw(Canvas spriteBatch, int X, int Y, int imageIndex,int flip)
{
int drawY = (imageIndex / columns);
int drawX = imageIndex - drawY * columns;
int spriteX = drawX * spriteWidth;
int spriteY = drawY * spriteHeight;
Rect src = new Rect( spriteX, spriteY,spriteX + spriteWidth, spriteY + spriteHeight);
Rect dst = new Rect(X, Y, X + spriteWidth,Y + spriteHeight);
location.X = X;
location.Y = Y;
if(flip == 1)
{
//here image is flipped
spriteBatch.save();
spriteBatch.scale(-scaleX, scaleY, X, Y);
spriteBatch.drawBitmap(texture2D,src,dst, paint);
spriteBatch.restore();
//Use simple use this to flip image canvas.scale(-1, 1)
}
else if(flip == 0)
{
//draws sprite without flipping
spriteBatch.save();
spriteBatch.scale(scaleX, scaleY, X, Y);
spriteBatch.drawBitmap(texture2D,src,dst, paint);
spriteBatch.restore();
}
this.SetFrame(imageIndex);
}
I can flip using matrix but I can't draw a sprite using matrix.
Is there a way to draw sprite using matrix and would it make it faster?
matrix.reset();
matrix.setTranslate(location.X, location.Y);
matrix.setScale(-scaleX,scaleX);
matrix.postTranslate(location.X + texture2D.getWidth(), location.Y);
Or is there another way that is faster?
So I think that the matrix solution should will work perfectly the canvas object includes it's own built in matrix which if you manipulate will affect the output of all graphics after that point. So you just set the matrxi and then do the draw.
You're solution is okay but you're doing it wrong - rather do this part ONCE:
Create the left-ward facing sprite as you do at the beginning and then store it. Then EACH FRAME: Use this 'cached' copy of the inverted bitmap that you created.
A third solution (which I haven't tried but might work) is to manipulate the destination rectangle so that the left and right edges are swapped - the canvas docs say, "Draw the specified bitmap, scaling/translating automatically to fill the destination rectangle." - I suspect that this might include negative scaling to fit the space where the right edge is smaller than the left although the docs do not explicitly say so.
What I want is might be separated into several or one methods, whatever is best.
I have four values that are set (as fields):
Width of image the whole image (canvas so to speak)
Height of the whole image (height of the canvas)
Padding (how many pixels I want to have as padding)
How many images in i want in the width and height separately (can be separate values)
What I want is to have a whole image, that I'm putting small images inside (these are the bitmap sizes I want to get from the method).
I basically want to have the size of the images inside, both the width and height.
And coordinates in of the small images in the whole image view.
A small example might be:
The width of the image is 200 and I want a padding of 4, and I want to have 3 images on one row of the image.
The calculation would might look like this:
(200 - (4*(3+1))) / 3 = 61,33;
The 3+1 is only because I want to have padding on either side of the small images.
But this is only for width, i would like to have a universal solution that applies to height as well.
And calculate the height and width of every image that is inside the canvas-image.
And just to put some sugar on top.
I would like to have the x and y coordinates of every image that is inside.
How can this be done?
And how do I get every value?
The bitmaps (I'm developing android) is stored in an ArrayList.
Basically I want this, a basic grid layout:
http://developer.android.com/images/ui/gridview.png
The values I have based on this image:
I have the size of the light-blue area,
including the space between the dark-blue images (padding)
and how many dark blue spots I want in every
row and column.
What I want is the size (width and height of the dark-blue spots),
and the coordinates of those images (where they should be placed in the light-blue area, x and y coordinates).
Anybody have a good solution for this?
UPDATED THE TEXT FOR CLARITY
This is the code of what I'm doing and wanted to do.
If anyone has ideas how to improve the code I will change my accepted answer.
public class ClassName {
public static int bitmapSizeWidth;
public static int bitmapSizeHeight;
public static final int bitmapPadding = 8;
public static final int howManyImagesColumn = 3;
public static final int howManyImagesRows = 2;
public static Bitmap folderBitmap(ArrayList<Bitmap> bitmapArray, int imageViewWidth, int imageViewHeight) {
bitmapSizeWidth = imageViewWidth;
bitmapSizeHeight = imageViewHeight;
Bitmap b = Bitmap.createBitmap(bitmapSizeWidth, bitmapSizeHeight, Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
//Lets do it in a set coordinate system now
if (bitmapArray.size() >= 1)
c.drawBitmap(bitmapArray.get(0), bitmapPadding, bitmapPadding, paint);
if (bitmapArray.size() >= 2)
c.drawBitmap(bitmapArray.get(1), calculateSecondCoord().xPos, bitmapPadding, paint);
if (bitmapArray.size() >= 3)
c.drawBitmap(bitmapArray.get(2), calculateThirdCoord().xPos, bitmapPadding, paint);
if (bitmapArray.size() >= 4)
c.drawBitmap(bitmapArray.get(3), bitmapPadding, calculateSecondCoord().yPos, paint);
if (bitmapArray.size() >= 5) {
c.drawBitmap(bitmapArray.get(4), calculateSecondCoord().xPos, calculateSecondCoord().yPos, paint);
}
if (bitmapArray.size() >= 6) {
c.drawBitmap(bitmapArray.get(5), calculateThirdCoord().xPos, calculateSecondCoord().yPos, paint);
}
return b;
}
public static BitmapSize calculateSingleBitmapSize(int imageViewWidth, int imageViewHeight) {
bitmapSizeWidth = imageViewWidth;
bitmapSizeHeight = imageViewHeight;
BitmapSize bsize = new BitmapSize();
bsize.widthSize = (int) (bitmapSizeWidth -
(bitmapPadding * (howManyImagesColumn + 1))) / howManyImagesColumn;
bsize.heightSize = (int) (imageViewHeight - (bitmapPadding * (howManyImagesRows + 1))) / howManyImagesRows;
return bsize;
}
/*
* First coord = padding
* Second coord (bitmapPadding) + calculateSingleBitmapSize(bitmapSizeWidth);
* Third coord (bitmapPadding * 3) + (calculateSingleBitmapSize(bitmapSizeWidth) * 2)
* The math is supposed to be correct but can perhaps be done in a more efficient way
*/
private static BitmapCoord calculateSecondCoord() {
BitmapCoord bCoord = new BitmapCoord();
bCoord.xPos = (int) (bitmapPadding * (howManyImagesColumn - 1)) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).widthSize;
bCoord.yPos = (int) (bitmapPadding * (howManyImagesRows)) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).heightSize;
return bCoord;
}
private static BitmapCoord calculateThirdCoord() {
BitmapCoord bCoord = new BitmapCoord();
bCoord.xPos = (int) (bitmapPadding * howManyImagesColumn) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).widthSize * 2;
bCoord.yPos = (int) (bitmapPadding * howManyImagesRows - 1) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).heightSize * 2;
return bCoord;
}
public static class BitmapSize {
public int widthSize;
public int heightSize;
}
static class BitmapCoord {
int xPos;
int yPos;
}
}
What you're describing is what game developers call spritesheets, tilesheets, tilesets, or whatever.
The general idea behind all of these is you have one image file of a certain type and inside that image you create subimages which can be pulled out and used individually in your program. Usually in video games these are of a consistent size but they don't have to be.
Check out the answer on this link: How to extract part of this image in Java? The answer here explains how to split an image up into several parts.
If you can't find what you're looking for there look up how game developers handle spritesheets for example to get an idea of how they do it.
I have another question, this is also extra credit and not homework. This time I need to create a border with out using java2d. The instructions are...
Write a method called drawRectangleBorder having six parameters which does not use the graphics package. It draws a rectangular border starting at the x and y coordinates given as the first two parameters, having a width and height given by the third and fourth parameters, the width of the border given by the fifth parameter in the color given by the sixth parameter. The parameter list is: x, y, width, height, borderWidth, color
I used a previous method I made to create a border around the outside of a picture but the best I can make it do now is a couple scattered boxes. The most recent version will not show anything
public void drawRectangleBorder(
int x, int y, int width, int height, int border, Color newColor) {
int startX = 0;
int startY = 0;
// top and bottom
for (startX = x; x < width; x++) {
for (startY = y; y < border; y++) {
// top pixel
this.getPixel(startX, startY).setColor(newColor);
// bottom pixel
this.getPixel(startX + width, startY + height).setColor(newColor);
} // for-y
} // for-x
// left and right
for (startX = x; x < border; x++) {
for (startY = y; y < height; y++) {
// left pixel
this.getPixel(startX, startY).setColor(newColor);
// right pixel
this.getPixel(startX + width, StartY + height).setColor(newColor);
} // for-y
} // for-x
return;
} // end drawRectangleBorder
Again I thank you for any input.
You can alter the pixels in a java.awt.BufferedImage as shown here.
I might be too sleepy but I think your forgetting to set the pixel back into this (whatever this is ^^)
I'm guessing this.getPixel sends your back a copy so you might want to do something like
Pixel p = this.getPixel( startX, startY );
p.setColor(newColor);
this.setPixel(startX, startY, p);