How do I take out a specific card from a deck image? - java

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.

Related

How to scale a pixel-drawing function in Java

In Java, I have a function like this:
public void setPixel(int x, int y, boolean on);
It sets a virtual black and white pixel, given whether it is on or not.
How can I call this function so the resulting display will be four times larger?
I tried this:
int x = 3;
int y = 3;
setPixel(x, y, true);
setPixel(x+1, y+1, true);
setPixel(x+2, y+2, true);
setPixel(x+3, y+3, true);
But naturally, it overlapped when I tried to draw something. How should I call the method?
While I'm tagging this Java, the concept could apply to any language.
Answering on these assumptions: setPixel sets a single pixel to white or black (if on is true, to black, else to white). You want to use this function to get a B&W image and make it four times larger. The code you provided is wrong and just makes a diagonal instad of a 4x4 block. Is this correct? If so:
A way to draw a 4 times larger image would then be, for example, to have a "getPixel(x,y)" which gets you whether the pixel at (x,y) is on in the original image and then start painting somewhere else in 4x4 blocks. Whenever you move by one pixel in either X or Y direction when getting the values of your original image, you move by 4 in your new image to scale. So then what you intended to do maybe was something like this?
void setBlock(int x, int y, boolean on, int scale)
for(int i=0; i < scale; i++){
for(int j=0; j < scale; j++){
setPixel(scale*x + i, scale*y + j, on);
And then iterate over your original image's coordinates doing something like this?
setBlock(x, y, getPixel(x, y), 4);

Java tile puzzle - how to place each separate piece in the correct location?

I am new to programming and in the process of working my way through a Java book and I am trying to learn about Swing and how to create simple GUIs etc.
I am trying to create a puzzle game that holds 9 tiles which are pieces of a puzzle. I have created a buffered image from which i am using the getSubImage method but i cannot figure out how to place each tile in the correct position, I know it should be a simple task but i just keep on creating the sub image in the same position - I am not sure how to move each piece into the correct location. I understand this is simple logic and i should know this!
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
BufferedImage b= bimg.getSubimage(j * w, i * h, w, h);
g.drawImage(b,0,0,w,h,this); //0,0 are the problem
}
}
It looks like you already had it partially down when you set the image:
BufferedImage b= bimg.getSubimage(j * w, i * h, w, h);
I'm referring to j*w and i*h
So why not draw them in the correct spot as well?
Changing:
g.drawImage(b,0,0,w,h,this);
Into:
g.drawImage(b, j*w , i*h ,w,h,this);

2D Dynamic Lighting in Java

I am making a game that has campfire objects. What I want to do is to brighten all pixels in a circle around each campfire. However, looping through every pixel and changing those within the radius is not all that efficient and makes the game run at ~7 fps. Ideas on how to either make this process efficient or simulate light differently?
I haven't written the code for the fires but this is the basic loop to check each pixel/change its brightness based on a number:
public static BufferedImage updateLightLevels(BufferedImage img, float light)
{
BufferedImage brightnessBuffer = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
brightnessBuffer.getGraphics().drawImage(img, 0, 0, null);
for(int i = 0; i < brightnessBuffer.getWidth(); i++)
{
for(int a = 0; a < brightnessBuffer.getHeight(); a++)
{
//get the color at the pixel
int rgb = brightnessBuffer.getRGB(i, a);
//check to see if it is transparent
int alpha = (rgb >> 24) & 0x000000FF;
if(alpha != 0)
{
//make a new color
Color rgbColor = new Color(rgb);
//turn it into an hsb color
float[] hsbCol = Color.RGBtoHSB(rgbColor.getRed(), rgbColor.getGreen(), rgbColor.getBlue(), null);
//lower it by the certain amount
//if the pixel is already darker then push it all the way to black
if(hsbCol[2] <= light)
hsbCol[2] -= (hsbCol[2]) - .01f;
else
hsbCol[2] -= light;
//turn the hsb color into a rgb color
int rgbNew = Color.HSBtoRGB(hsbCol[0], hsbCol[1], hsbCol[2]);
//set the pixel to the new color
brightnessBuffer.setRGB(i, a, rgbNew);
}
}
}
return brightnessBuffer;
}
I apologize if my code is not clean, I'm self taught.
I can give you lots of approaches.
You're currently rendering on the CPU, and you're checking every single pixel. That's hardcore brute force, and brute force isn't what the CPU is best at. It works, but as you've seen, the performance is abysmal.
I'd point you in two directions that would massively improve your performance:
Method 1 - Culling. Does every single pixel really need to have its lighting calculated? If you could instead calculate a general "ambient light", then you could paint most of the pixels in that ambient light, and then only calculate the really proper lighting for pixels closest to lights; so lights throw a "spot" effect which fades into the ambient. That way you're only ever performing checks on a few of the pixels of the screen at a time (the circle area around each light). The code you posted just looks like it paints every pixel, I'm not seeing where the "circle" dropoff is even applied.
Edit:
Instead, sweep through the lights, and just loop through local offsets of the light position.
for(Light l : Lights){
for(int x = l.getX() -LIGHT_DISTANCE, x< l.getX() + LIGHT_DISTANCE, y++){
for(int y = l.getY() - LIGHT_DISTANCE, y < l.getY() + LIGHT_DISTANCE, y++){
//calculate light
int rgb = brightnessBuffer.getRGB(x, y);
//do stuff
}
}
You may want to add a check with that method so overlapping lights don't cause a bunch of rechecks, unless you DO want that behavior (ideally those pixels would be twice as bright)
Method 2 - Offhand calculation to the GPU. There's a reason we have graphics cards; they're specifically built to be able to number crunch those situations where you really need brute force. If you can offload this process to the GPU as a shader, then it'll run licketysplit, even if you run it on every pixel several times over. This will require you to learn graphics APIs however, but if you're working in java, LibGDX makes it very painless to render using the GPU and pass off a couple shaders to the GPU.
I am uncertain about the way in which you are going about calculating light values, but I do know that using the BufferedImage.getRGB() and BufferedImage.setRGB() methods is very slow.
I would suggest accessing the pixels of the BufferedImage directly from an array (much faster IMO)
to do this:
BufferedImage lightImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
Raster r = lightImage.getRaster();
int[] lightPixels = ((DataBufferInt)r.getDataBuffer()).getData();
Now, changing any pixel in this array will show on your image. Note that the values used in this array are color values in the format of whatever format you defined your image with.
In this case it is TYPE_INT_ARGB meaning you will have to include the alpha value in the number when setting the coloar (RRGGBB*AA*)
Since this array is a 1D array, it is more difficult to access pixels using x and y co-ordinates. The following method is an implementation of accessing pixels from the lightPixels array more easily.
public void setLight(int x, int y,int[] array,int width, int value){
array[width*y+x] = value;
}
*note: width is the width of your level, or the width of the 2D array your level might exist as, if it was a 2D array.
You can also get pixels from the lightPixels array with a similar method, just excluding the value and returning the array[width*y+x].
It is up to you how you use the setLight() and getLight() methods but in the cases that I have encountered, using this method is much faster than using getRGB and setRGB.
Hope this helps

Slick is getting very slow but only drawin rectangles

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.

Extracting a rectangular pixel region from an image

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

Categories