I am trying to make holdable items for my slick2d game, I figured a good way to do this would be to have a hand on the player, to do this i have 1 pixel a unique colour, allowing me to locate that colour, and the x +y.
It worked perfectly until i tried to scale up the image and i get this crazy out of bounds exeception.
this is my code to find the x and y:
public int[] getLocation(Image i, Color c){
Image scaled = i.getScaledCopy(getWidth(), getHeight());
for(int x = 0; x < scaled.getWidth(); x++){
for(int y = 0; y < scaled.getHeight(); y++){
if(scaled.getColor(x, y).r == c.r && scaled.getColor(x, y).g == c.g && scaled.getColor(x, y).b == c.b){
int[] xy = {x,y};
return xy;
}
}
}
return null;
}
and this is how i use it
float x = (float) (getLocation(walkLeft.getCurrentFrame(), new Color(1, 1, 1))[0] + getX());
float y = (float) (getLocation(walkLeft.getCurrentFrame(), new Color(1, 1, 1))[1] + getY());
g.fillRect(x, y, 2, 2);
the exception is:
java.lang.ArrayIndexOutOfBoundsException: 16384
and it leads me back to this line:
if(i.getColor(x, y).r == c.r && i.getColor(x, y).g == c.g && i.getColor(x, y).b == c.b){
in the getLocation method..
I have a feeling its dead easy, yet its stumped me. Thanks to anyone to responds.
The loop(s) in getLocation loop over the dimensions of a 2x scaled copy of the Image, but then attempt to access the pixels of the original. Given the original is half the size, when you are half-way through the loop you will be out of bounds of the image dimensions. Either:
Don't scale the Image
If you must scale the Image, check the pixel value of the scaled image rather than the original.
As an aside, the code posted contains redundant calls...a) in getLocation if you are going to scale, consider scaling the image once rather than placing that code within the loop itself b) no need to call getLocation twice with the same parameters. Call it once and just use the returned array
Related
This is part of a project for my computer science class. One of the tasks is to take an image and reflect it. I've already initialized a picture called image. When I run this method, instead of reflecting the picture it mirrors it.
public void reflect()
{
//Creating a for loop to get all of the x values for the image object
for(int x = 0; x < image.getWidth(); x++)
{
//Creating a nested for loop to get all of the y values for each x value
for(int y = 0; y < image.getHeight(); y++)
{
//Getting a pixel object for the given x and y value
Pixel pixelObj = image.getPixel(x, y);
//I'm pretty sure this next line is where I'm screwing up.
//It's probably really simple, but I can't figure it out.
Pixel newPixel = image.getPixel(image.getWidth()-x-1, y);
//This sets the color values of the new pixel to the ones of the old pixel
newPixel.setRed(pixel0bj.getRed());
newPixel.setGreen(pixel0bj.getGreen());
newPixel.setBlue(pixel0bj.getBlue());
}
}
image.show();
}
You have to swap the corresponding pixel values. Currently, you are overwriting the right half of the image before saving their pixel values in a reference for putting them to the left half.
Below I've illustrated what I mean by "swapping" value instead of just assigning them uni-directionally:
//Getting a pixel object for the given x and y value
Pixel pixelObj = image.getPixel(x, y);
Pixel oppositePixel = image.getPixel(image.getWidth()-x-1, y);
//Store the RGB values of the opposite pixel temporarily
int redValue = oppositePixel.getRed();
int greenValue = oppositePixel.getGreen();
int blueValue = oppositePixel.getBlue();
//This swaps the color values of the new pixel to the ones of the old pixel
oppositePixel.setRed(pixel0bj.getRed());
oppositePixel.setGreen(pixel0bj.getGreen());
oppositePixel.setBlue(pixel0bj.getBlue());
pixelObj.setRed(redValue);
pixelObj.setGreen(greenValue);
pixelObj.setBlue(blueValue);
If you swap pixels both ways in each round, it's sufficient to loop from 0 to image.getWidth() / 2.
Have a look how it's done in ImageJ's ImageProcessor class as a reference.
Another solution is to use a matrix transformation and scale by -1 in the x direction. See the ImageJ scale op for a more elaborate example using the ImgLib2 library for image processing in Java.
I'm creating a game and I have a JFrame with a custom Canvas in it. The weird thing is that when I set the JFrame to BE RESIZABLE, the rendering result looks like this:
But when I set the JFrame to NOT BE RESIZABLE, the result looks like this:
The method which adds the texture's pixel array to the BufferedImage's pixel array looks like this:
// DRAW A TEXTURE ON THE CANVAS
public void drawTexture(Texture texture, Vector2i location) {
// Store the current texture coordinates
int tx = 0, ty = 0;
// Scroll through each pixel on the screen horizontally (begin at the X coordinate specified by the 'location')
for(int x = location.x; (x < getWidth() && x < location.x + texture.getWidth()); x++) {
// Scroll through each pixel on the screen vertically (begin at the Y coordinate specified by the 'location')
for(int y = location.y; (y < getHeight() && y < location.y + texture.getHeight()); y++) {
// Set each pixel to the color of the corresponding pixel on the Texture
pixels[x + y * getWidth()] = texture.getPixels()[tx + ty * texture.getWidth()];
// Add one to the texture Y coordinate
ty++;
}
// Reset the ty variable
ty = 0;
// Add one to the texture X coordinate
tx++;
}
}
And the BufferedImage is drawn inside of a loop in the run method of my custom canvas.
The custom canvas class (extends Canvas offcourse) implements Runnable, and it also contains an own Thread for rendering.
I wonder if anyone know why this happens, and maybe how to fix it, because I can't figure it out...
Well, I found the working answer here, because I found out that the Canvas was bigger than what I had set it to, so I googled for that, and that answer fixed both problems.
Quote from the answer to the other question:
Swap the pack and setResizable calls, so that pack is the second call.
and
This is a known "issue"
Question here.
Some Context:
I am creating an Android game which draws a maze onto a canvas against a background image, this uses a square block and therefore the maze is always automtically zoomed in to a 5 x 5 square, of a maze that may be 20 x 20. The maze is drawn by simply running through a set of for loops and then drawing lines in the relevent places. This is all working perfectly, however I am having an issue with getting my onDraw to work smoothly. This is occuring due to the fact that everytime I invalidate I have to re-run the for look and run various if statements to check positions (unfortunetly this process cannot be improved).
The Question:
I am looking to re-write the way my maze is drawn onto the canvas, below are the 3 main features I need to implement:
1 - Draw the whole maze onto the canvas (this is easy enough)
2 - Zoom in on the maze so only a 5 x 5 is shown
3 - Move the character (who is always centered on the screen) and draw the next seciton of the maze
Now as mentioned above drawing the whole maze is easy enough and will make the onDraw signifcatly quicker as their is no need to run the for loop on invaldate, it can be done once when the level is first loaded up.
In terms of point 2 & 3, the way I see this working is the charcacter to be drawn in the middle of the canvas then a 2d birdseye view camera to be attached / linked to the characters movement. This camera would also need to be zoomed in to an extent that it only displays a 5 x 5 of the overall maze grid. Then as the charcater moves the camera moves with the character and displays the next section of the maze which has already been drawn. I have tried a few things and done some reasearch however I have never worked with canvas before and no idea really where to start and if this is even possible.
So to sum up the main part of the question is whether their is a way to link a birdseye view camera to a character which is zoomed in and moves with the character image.
Below is a snippet as to how the maze is currently drawn, using 2 sets of for loops checking against 2 sets of boolean arrays[][], which simply store the vertical and horixaonl lines to be drawn.
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawRect(0, 0, width, 100, background);
RectBackground.set(0,0, FullScreenWidth, FullScreenWidth);
canvas.drawBitmap(gameBackground, null, RectBackground, null);
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
float x = j * totalCellWidth;
float y = i * totalCellHeight;
indexY = i + currentY;
indexX = j + currentX;
// Draw Verticle line (y axis)
if (indexY < vLength && indexX < vLines[indexY].length && vLines[indexY][indexX])
{
RectOuterBackground.set((int)x + (int)cellWidth, (int)y, (int)x + (int)cellWidth + 15, (int)y + (int)cellHeight + 15);
canvas.drawBitmap(walls, null, RectOuterBackground, null);
}
// Draws Horizontal lines (x axis)
if (indexY < hLength && indexX < hLines[indexY].length && hLines[indexY][indexX])
{
RectOuterBackground.set((int)x, (int)y + (int)cellHeight,(int)x + (int)cellWidth + 15,(int)y + (int)cellHeight + 15);
canvas.drawBitmap(walls, null, RectOuterBackground, null);
}
}
}
}
To make the drawing faster, you can double buffer the canvas by drawing directly into a bitmap and flashing the bitmap into the canvas like this. It's very fast.
private void init()
{
//variables below are class-wide variables
b = Bitmap.createBitmap(cwidth, cheight, Bitmap.Config.ARGB_8888);
bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapPaint.setStyle(Paint.Style.STROKE);
bitmapPaint.setStrokeWidth(3);
myPaint.setColor(0xff000000);
myCanvas = new Canvas(b);
}
protected void onDraw(Canvas c)
{
super.onDraw(c);
c.drawBitmap(b, 0, 0, myPaint);
for(int i = 0; i < number lines; i++)
{
//draw here using myPath
}
if(b != null)
c.drawBitmap(b, 0, 0, myPaint);
myCanvas.drawPath(myPath, bitmapPaint);
}
Then, to "move around" I would suggest using a crop box. What this means is that a 1:1 scale, the image is larger than the viewport displayed on the screen. Really what's happening when someone "moves" is the bitmap is being moved beneath the crop box.
You could use BitmapRegionDecoder and display only the region the character is in (this might be slowish) or by using
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
The src parameter here allows you to specify a small region of the bitmap to display. It is effectively a crop box.
To zoom in and out you need to multiply the coordinates by a number( zoom factor)
int x1 = (int)x + (int)cellWidth;
int y1 = (int)y;
int x2 = (int)x + (int)cellWidth + 15;
int y2 = (int)y + (int)cellHeight + 15;
RectOuterBackground.set(x1*zoom, y1*zoom, x2*zoom, y2*zoom);
note that zoom must be a floating point number, using zoom=2 that makes everything twice as big.
if you want to put the camera on top of the cell (xc, yc) you need to do this:
RectOuterBackground.set( (x1-xc)*zoom, (y1-yc)*zoom, (x2-xc)*zoom, (y2-yc)*zoom);
Try first drawing the whole maze, and soon you will figure out how to only draw the bit of the maze that is only inside the screen
I hope this helps and let me know if you have any questions :)
I'm looking for a way to find the dimensions of the visible part of an image is. The image I'm displaying in my ImageView is .png format, it has a portion that is "visible" and the rest is an invisible background.
Example Image:
←that box isn't visible on the real image, it's just to illustrate my point
So in this image there is only a small red wedge shape which is visible, but the full .png is really a rectangle of larger dimensions, thus I can't use something like bitmap.getWidth();
So:
How can I find out if a particular pixel in an image is "invisible" or not? Note: I know I can use bitmap.getPixel(x, y); to get a pixel, but I don't know what to do with it once I have it; is a test for 0 sufficient?
Is there a better way of finding the max width/height of the "visible" portion other than iterating through every pixel looking for the visible "end points"?
How can I find out if a particular pixel in an image is "invisible" or not? Note: I know I can use bitmap.getPixel(x, y); to get a pixel, but I don't know what to do with it once I have it; is a test for 0 sufficient?
Use image.getPixel(x, y) != Color.TRANSPARENT to check whether the pixel is visible or not.
Is there a better way of finding the max width/height of the "visible" portion other than iterating through every pixel looking for the visible "end points"?
There is no built in functions. You can use the below function to get the image in square shape leaving the transparent pixels out.
public static Bitmap removeTransparentPixels(Bitmap image) {
int x1 = image.getWidth();
int y1 = image.getHeight();
int width = 0, height = 0;
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
if (image.getPixel(x, y) != Color.TRANSPARENT) {
if (x < x1) {
x1 = x;
} else if (x > width) {
width = x;
}
if (y < y1) {
y1 = y;
} else if (y > height) {
height = y;
}
}
}
}
width = width - x1;
height = height - y1;
return Bitmap.createBitmap(image, x1, y1, width, height);
}
Make sure that your image doesn't contain only the transparent pixels. If the image has only transparent pixels then the statement Bitmap.createBitmap(image, x1, y1, width, height); will through exception.
There are probably some form of image processing libraries that you would need to take advantage of in order to achieve what you are requesting in order to keep the processing down if that is a concern such as OpenCV or ImageMagick that would probably get that information back to you in a quick manner via specific function calls.
As far as I know, there wouldn't be a built in way to determine that through a standard call into the image libraries that exist within Android. You would probably need to do some sort of heuristic check for transparent pixels as you mentioned with your original thought.
I'm using LWJGL and Slick2D for a game I'm making. I can't seem to get it to draw the way I want it to be draw so I came up with an idea just to make my own drawing method. Basically it takes a image, a x, and a y and it goes through each pixel in the image, gets the color, then draws the image with the parameter x plus the x pixel it's on to get the position that the pixel is suppost to be drawn on. Same idea with the y. Although if the alpha channel isn't 255 for the pixel it doesn't draw it, although I'll fix that later. The problem is that whenever I run my code I get "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -2044". I'm really confused. I'm hoping someone can figure out why this is happening.
private void DrawImage(Image image, int xP, int yP)
{
//xP And yP Are The Position Parameters
//Begin Drawing Individual Pixels
glBegin(GL_POINTS);
//Going Across The X And The Y Coords Of The Image
for (int x = 1; x <= image.getWidth(); x++)
{
for (int y = 1; y <= image.getHeight(); y++)
{
//Define A Color Object
Color color = null;
//Set The Color Object And Check If The Color Is Completly Solid Before Rendering
if ((color = image.getColor(x, y)).a == 255)
{
//Bind The Color
color.bind();
//Draw The Color At The Coord Parameters And The X/Y Coord Of The Individual Pixel
glVertex2i(xP + x - 1, yP + y - 1);
}
}
}
glEnd();
}
My answer is assuming that the texture is an array of data.
I have a feeling it is the getColor() method. Your for loop runs through and will use the height and width values. An array usually starts off with 0 and width and height are just array counts typically. So I can see when you reach HEIGHT, that the texture array will throw an exception.
Try removing the <= part and replace it with <
EXAMPLE:
for (int x = 1; x < image.getWidth(); x++)
It may also help you to start off with zero so you can get the entire image.
EXAMPLE
for (int x = 0; x < image.getWidth(); x++)
Here is a link on arrays.
This way, when you ask for the color at whatever position, it will never ask for a color reaching beyond what is in the texture array. Hopefully I made sense.