For a project I need to make a map in Java that a robot can navigate through. Preferably, I'd like to store the map in a 2D-array, but I don't know how to go from the 1 bit bitmap to an array in Java. Can you help me out?
You can use the ImageIO.read() method to load your bitmap in a BufferedImage instance. Then, call BufferedImage.getRGB(int x, int y) to get the color value of a particuliar pixel of your map.
Assuming a 10 by 10 grid, then you would create an array such as
Image[][] grid = new Image[10][10];
Then
for (int x = 0; X < grid.length; X++) {
for (int y = 0; y < grid[x].length; y++) {
grid[x][y] = theImageForThisPosition;
}
}
However, as you are storing 1 bit bitmaps, it would be much more efficient to store Color objects, rather than Image objects.
Related
I want to take out a card from my deck image. How can I do that without downloading every single card separately? I don't want to initialize all 52 cards in my class.
Right now, I randomize colour and value and then it finds the picture in my source folder. But is it possible to only take one card out from my single deck image?
bild = ImageIO.read(new File("source folder/" + colour + value + ".png"));
You should initialize them all but you don't have to do it by hands.
You should create one image that contains every single card and load it. BufferedImage class provides you a getSubImage(int x, int y, int w, int h); and is returning a piece (a card) of your BufferedImage.
You can populate an array of card while looping through the image of your deck.
for(int i = 0; i<4; i++){
for(int j = 0; j < 13; j++){
deckArray[13 * i + j] == image.getSubImage(i * cardWidth,
j * cardHeight,
cardWidth,
cardHeight);
}
}
Something like this. Note that I'm assuming 4*13 images os sheet and no space between them.
You will have to find a way to track you cards, which one is which in your array no matter how you store them, because what you definietly don't want is loading an image every time you want to use it.
It's not tested and not 100% sure I did all the math corretly, just a quick reference how could you achive something like this.
You still have to load the entire image but when you're drawing, just use
g.drawImage(Image img, int dstx1, int dsty1, int dstx2, int dsty2, int srcx1, int srcy1, int srcx2, int srcy2, ImageObserver observer);
The src (=source) values will be the upper left und lower right coordinates within your image that define the part you want to draw while the dst (=destination) values will decide where it will be drawn.
I have made a map on an image which I load in the game like this:
List<Block> tempBlocks = new ArrayList<Block>();
BufferedImage level = levels.get(currentLevel);
for (int x = 0; x < level.getWidth(); x++) {
for (int y = 0; y < level.getHeight(); y++) {
tempBlocks.add(new Block(x, y, new Color(level.getRGB(x, y))));
}
}
blocks = tempBlocks;
isLoading = false;
The array blocks is an array with all 1-pixel-blocks. Every single block renders like this:
g.setColor(color);
g.drawLine(x, y, x, y);
I call them like this:
for (int i = 0; i < getCurrentScene().blocks.size(); i++)
getCurrentScene().blocks.get(i).render(g);
It's 1280x720 blocks... Is it a better way to render this insane amount of blocks? Because I want it to load from an image, which is 1280x720. I get like 3 FPS now...
For what you're doing now, if you do that for every frame, you're creating new objects all over the place for every single frame, and only using them once before discarding and allowing the garbage collector to pick them up.
Create enough objects to represent how the screen is now.
Create enough objects to represent how the screen should be next.
Don't lose those. Don't create any more.
For the Color(int int int) thing you're doing? You can just do Color(int); new color(level.getRGB(x, y)) should work just fine; the java.awt.Color class can take a single int instead of three.
That said, you'd still be initializing Color a million times. If you have a limited number of Colors, it may be beneficial to call them directly or cache them in some way, instead of continually recreating new Color objects on the heap.
Shepard solved it in the comments. What I did was to render the image as g.drawImage(image, x, y); instead of rendering all of the pixels. I still use the blocks for collision detection, but that is way more efficient.
I am trying to make a memory game with Java. The game is basically going to be some squares in a grid that is 4x4 at the moment just for testing purposes. I have created my Square class, and programmed what i want them to do in that class, and then created a square object in another Class that handles the "Normal Mode" of the game. Now since i have a 4x4 grid of squares I need to make 16 different Squares (Or at least that's what i'm thinking at the moment). I also need to draw the Squares in their corresponding place.
My Question: What is the most efficient way of creating 16 of these Square objects while still being able to manipulate them individually? (Sort of like each having their own name; Square, Square1, Square2, etc).
I am also using the Slick2D library.
As mentioned above, Square[][] squareGrid = new Square[4][4] is a good way to go about this;
then you can initialize all 16 of them using:
for (int i = 0; i < squareGrid.length; i++)
for(int j = 0; j < squareGrid[i].length; j++)
squareGrid[i][j] = new Square();
now each square automatically has its own unique (row, col) id.
for example,
squareGrid[1][2].callSomeFunctionInSquareClass();
can be used to manipulate the square at 2nd row, 3rd column.
This way you will avoid scanning through all the squares to get the one at a particular cell on the grid, thus making it much more efficient.
happy coding :)
You can try Square[][] grid = new Square[4][4]
I would use a Square[][] array, e.g. Square[][] squares = new Square[4][4], and then initialise it with all 16 Squares in two nested loops:
for (int x = 0; x < squares.length) x++)
for (int y = 0; y < squares[x].length; y++)
squares[x][y] = new Square(x, y);
I am using slick for java since a few days and got a serious problem.
If i run a completely empty apllication (it just shows the fps) with a solution of 800x600 i get a fps count between 700 and 800.
If I now draw an array with 13300 entries as a grid of green and white rectangles, the fps drop to something around 70.
With more entries in the array it becomes really slow.
For example in a solution of 1024x768 and an array with 21760 entries the fps drop to 40.
How i draw a single entry:
public void draw(Graphics graphics){
graphics.setColor(new Color(getColor().getRed(), getColor().getGreen(), getColor().getBlue(), getColor().getAlpha()));
graphics.fillRect(getPosition().x, getPosition().y, getSize().x, getSize().y);
Color_ARGB white = new Color_ARGB(Color_ARGB.ColorNames.WHITE);
graphics.setColor(new Color(white.getRed(), white.getGreen(), white.getBlue(), white.getAlpha()));
}
And this is how I draw the complete array:
public void draw(Graphics graphics) {
for (int ix = 0; ix < getWidth(); ix++) {
for (int iy = 0; iy < getHeight(); iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
In my opinion 21760 is not that much.
Is there anything wrong with my code or is slick just too slow to draw so much rectangles?
You only want to draw rectangles that are on the screen. If your screen bounds go from 0 to 1024 in the x direction and from 0 to 768 in the y direction, then you only want to loop through rectangles that are inside those bounds and then only draw those rectangles. I can't imagine you are trying to draw 21760 rectangles inside those bounds.
If you are, then try creating one static rectangle and then just try drawing that ONE in all of the different positions you need to draw it at rather than creating a new one every time. For example, in a game I am making, I might have 1000 tiles that are "grass" tiles, but all 1000 of those share the same static texture. So I only need to reference one image rather than each tile creating its own.
Each rectangle can still have a unique state. Just make your own rectangle class and have a static final Image that holds a 5*5 image. Each rectangle will use this image when it needs to be drawn. You can still have unique properties for each rectangle. For example, private Vector2f position, private boolean isAlive, etc
You're probably not going to be able to draw individual rectangles any faster than that.
Games that render millions of polygons per second do so using vertex buffer objects (VBO). For that, you'll probably need to code against the OpenGL API (LWJGL) itself, not a wrapper.
Not sure if Slick will allow it, but if this thing looks anything like a chessboard grid... you could draw just 4 rectangles, grab them and use the resulting image as a texture for your whole image. I'm not even a java programmer just trying to come up with a solution.
Since you're only repeatedly using just a few colors creating a new Color object for every single one is bound to be slow... use new only once for each different color used and store the re-usable colors somewhere in your class, than call the functions with those, constantly allocating and freeing memory is very slow.
And while this might not be as much a benefit as not using new each time but have you considered caching the results of all those function calls and rewriting code as
public void draw(Graphics graphics) {
int ixmax = getWidth();
int iymax = getHeight();
for (int ix = 0; ix < ixmax; ix++) {
for (int iy = 0; iy < iymax; iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Or if you'd prefer not to declare new variables
public void draw(Graphics graphics) {
for (int ix = getWidth() - 1; ix >= 0; ix--) {
for (int iy = getHeight() - 1; iy >= 0; iy--) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Just noticed in another answer you have an integral size grid (5x5) ... in this case the fastest way to go about this would seem to be to draw each item a single pixel (you can do this directly in memory using a 2-dimensional array) and scale it to 500% or use it as a texture and draw a single rectangle with it the final size you desire ... should be quite fast. Sorry for all the confusion caused by previous answers, you should have said what you're doing more clearly from the start.
If scaling and textures are not available you can still draw in memory using something like this (written in c++, please translate it to java yourself)
for( int x = 0; x < grid.width(); x++ ) {
for( int y = 0; y < grid.height(); y++ ) {
image[x*5][y*5] = grid.color[x][y];
image[x*5][y*5 + 1] = grid.color[x][y];
image[x*5][y*5 + 2] = grid.color[x][y];
image[x*5][y*5 + 3] = grid.color[x][y];
image[x*5][y*5 + 4] = grid.color[x][y];
}
memcpy(image[x*5+1], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+2], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+3], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+4], image[x*5], grid.height() * sizeof(image[0][0]) );
}
I'm not sure, but perhaps for graphics the x and y might be represented in the reversed order than used here, so change the code accordingly if it that's the case (you'll figure that out as soon as a few iterations run), also your data is probably structured a bit differently but I think the idea should be clear.
I need to extract a pixel region described by (2n+1) x (2m+1) centred on leftimage (xl,yl). n and m are user input parameters and xl and yl are already defined. Thus far I have this code:
for(int xl = n; xl < picOneGreyScale.getWidth() - n; xl++) {
for(int yl = m; yl < picOneGreyScale.getHeight() - m; yl++) {
//extract (2n+1) x (2m+1) pixel region centred on leftimage (xl,yl);
for(int nArea = xl-n; nArea < xl+n+1; nArea++) {
for(int mArea = yl-m; mArea < yl+m+1; mArea++) {
*code here*
}
}
I'm uncertain as to how to continue. I have defined a BufferedImage called leftRegion:
BufferedImage leftRegion = new BufferedImage((2*n+1),(2*m+1),BufferedImage.TYPE_BYTE_GRAY);
which I intend to use to "extract" my pixel region into. My thoughts thus far are, for where it says code here to extract the pixel at the current location (using getRGB?) and then nesting another for loop to place this pixel within the correct x, y coordinates for leftRegion. I'm not sure how to do this however or if I'm thinking too complex. Alternatively it may be possible to use getRGB with extended arguments:
getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
instead of the two inner for loops but again I'm not so hot on how to implement this. Finally there is a method for BufferedImage called copyData which looks like it might be relevant but I'm not sure how to use it. What's the best way to implement this? Many thanks as always.
Additional Information:
Okay so I'm trying to use the getSubImage method of the BufferedImage class:
leftRegion = picOneGreyScale.getSubimage(xl, yl, (2*n+1), (2*m+1));
only I'm getting an error "(y + height) is outside of Raster". How does getSubImage work exactly? Will the image be centered around xl, yl with the width and height being extended equally either side, or does it work differently? Am I even following the right path?
I figured it out. I simply replaced the two inner for loops with this:
leftRegion = picOneGreyScale.getSubimage(xl-n, yl-n, (2*n+1), (2*m+1));