Smoothly Updating Bitmap - java

Just to add a surprise factor to my game, I have decided to invert the background colors randomly. When the player collects, let's say, 21 golden bacon strips the background changes. By modifying the bitmap's pixels, I have done this through the following code:
public void invert() {
int length = BackBitmap.getWidth() * BackBitmap.getHeight();
int[] array = new int[length];
BackBitmap.getPixels(array, 0, BackBitmap.getWidth(), 0, 0, BackBitmap.getWidth(), BackBitmap.getHeight());
int[] array2 = new int[length];
int a2 = 0;
for(int col = 0; col < BackBitmap.getHeight(); col++){
for (int row = 0; row < BackBitmap.getWidth();row++){
array2[a2] = BackBitmap.getPixel(row,col);
a2++;
}
}
for (int i=0;i<length;i++){
array[i] = 0xFFFFFF - array2[i];
}
BackBitmap = BackBitmap.copy(Bitmap.Config.ARGB_8888, true);
BackBitmap.setPixels(array, 0, BackBitmap.getWidth(), 0, 0, BackBitmap.getWidth(), BackBitmap.getHeight());
}
However once the colors are inverted, the game encounters major lag. To my surprise I thought this way of updating bitmap would be the most effective - memory-wise. What would be the right way to approach this error?

public void invert() {
int length = BackBitmap.getWidth() * BackBitmap.getHeight();
int[] array = new int[length];
int[] array2 = new int[length];
BackBitmap.getPixels(array2, 0, BackBitmap.getWidth(), 0, 0, BackBitmap.getWidth(), BackBitmap.getHeight());
for (int i=0;i<length;i++){
array[i] = 0xFFFFFF - array2[i];
}
BackBitmap = BackBitmap.copy(Bitmap.Config.ARGB_8888, true);
BackBitmap.setPixels(array, 0, BackBitmap.getWidth(), 0, 0, BackBitmap.getWidth(), BackBitmap.getHeight());
}
This is how I would write it. You were writing to array and then rewriting it without using it.
This may not reduce lag significantly but it may help to a degree.

Related

Java 2D Array Placing Value if Adjacent value is the same

There are some similar threads and I have tried some solutions but none are working to how my result is intended to be.
I have a 2d array (Which is a game board).
If i want to move a playerID to a position in the board I want to check if that position has an adjacent cell that is equal to the player ID. Otherwise it wont place it.
For example if i have a board:
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
If i try 1 in position [0][0] it should reject it but if i try put it in either: [0][7], [0][9], [1][6], [1][7],[1][8] (this includes diagonals).
My current code was a starting attempt I guess? But im not sure how I could do the clientID check:
public void move(int client, int x, int y) {
int startPosX = (x - 1 < MIN_X) ? x : x-1;
int startPosY = (y - 1 < MIN_Y) ? y : y-1;
int endPosX = (x + 1 > MAX_X) ? x : x+1;
int endPosY = (y + 1 > MAX_Y) ? y : y+1;
for (int rowNum=startPosX; rowNum<=endPosX; rowNum++) {
for (int colNum=startPosY; colNum<=endPosY; colNum++) {
if (storeArray[x][y] == EMPTY && client <= 5 && client >= 1) {
storeArray[x][y] = client;
int count = totals.containsKey(client) ? totals.get(client) : 1;
totals.put(client, count + 1);
}
}
}
So it goes through the rows and columns and if it's in any of the surrounding cells, it should place it. But I can still place it anywhere.
Is my code even close to doing what it's supposed to do?
What sort of things am i missing to match my criteria and can this code be modified to make it work?
If you can't store the coordinates of clients you can modify your if statement to the following. If you can store the coordinates I would definitely use Leo Leontev's answer.
/*I removed check for client to be between 1-5, can be re-added.
I would add the checks for the desired spot being empty and the client
being within 1-5 to the top of the method.
For loop iterates over the possible spaces where the client would be in range
check if client is in a space*/
if (storeArray[rowNum][colNum]==client) {
//storeArray[rowNum][colNum]=0;
storeArray[x][y] = client;
//unchanged
int count = totals.containsKey(client) ? totals.get(client) : 1;
totals.put(client, count + 1);
}
You can also simplify your startX,Y, endX,Y by using Math.min and Math.max to avoid any indexOutOfBounds errors that may be caused by trying to move the client outside of the board.
int startPosX = Math.max(x-1,0);
int startPosY = Math.max(y-1,0;
int endPosX = Math.min(x+1,storeArray.length-1);
int endPosY = Math.min(y+1,storeArray[0].length-1);
If you're not doing anything after the totals.put(client,count+1); call you can add a return; statement to exit the method. If you still need to do more work you can add a label to the outer for loop and then break out of the label. Either way will stop your count from counting more than once per move.
outerloop:
for(int rowNum=startPosX;rowNum<=endPosX;rowNum++){
for(int colNum=startPosY;colNum<=endPosY;colNum++){
if(...){
//code
totals.put(client, count+1);
break outerloop;
}
}
}
Here is the method as it is in my editor
public static move(int client, int x, int y){
if(storeArray[x][y]==client)
return;
int startPosX = Math.max(x-1,0), startPosY=Math.max(y-1,0);
int endPosX = Math.min(x+1,storeArray.length-1), endPosY = Math.min(y+1,storeArray[0].length-1);
outerloop:
for(int rowNum=startPosX;rowNum<=endPosX;rowNum++)
{
for(int colNum=startPosY;colNum<=endPosY;colNum++){
if(storeArray[rowNum][colNum]==client)
{
storeArray[x][y]=client;
System.out.println("Successful move");
int count = totals.getOrDefault(client, 1);
totals.put(client, count + 1);
break outerloop;
//could set colNum=endPosY+1 and rowNum=endPosX+1 if you don't want to use label/break
}
}
}
}
You can use an array to store the coordinates of clients:
ArrayList<int[]> clientCoords = new ArrayList<>;
And so the move method will look like that:
public void move(int client, int x, int y) {
int[] coords = clientCoords.get(client);
int old_x = coords[0], old_y = coords[1]; // previous coordinates of the client
// check that the new cell is adjacent
if(Math.abs(x - old_x) <= 1 && Math.abs(y - old_y) <= 1){
clientCoords.set(client, new int[2]{x, y});
// your code
int count = totals.containsKey(client) ? totals.get(client) : 1;
totals.put(client, count + 1);
}
}

tiled map in java from array

I am attempting to iterate through a 2D array of integers to generate a tiled map using Java's Graphics2D.
int[][] mapArray = {{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1}};
public void draw(Graphics2D g2d){
for(int y = 0; y < mapArray.length; y++){
for(int x = 0; x < mapArray[0].length; x++){
if(mapArray[x][y] == 1){
ImageIcon ic = new ImageIcon("/Textures/stone.jpg");
g2d.drawImage(ic.getImage(), x, y, null);
}
else if(mapArray[x][y] == 0){
ImageIcon ic = new ImageIcon("/Textures/water.jpg");
g2d.drawImage(ic.getImage(), x, y, null);
}
I just can't seem to wrap my head around the logic of iterating a 2D array. Ideally, each 0 would represent a water tile while each 1 would represent a stone tile. Every time I run this I get a NullPointerException.
x and y are wrong way around
public void draw(Graphics2D g2d){
for(int y = 0; y < mapArray.length; y++){
for(int x = 0; x < mapArray[y].length; x++){ //you want to use y here not 0
if(mapArray[y][x] == 1){ //first box is outer array second is inner one
ImageIcon ic = new ImageIcon("/Textures/stone.jpg");
g2d.drawImage(ic.getImage(), x, y, null);
} else if(mapArray[y][x] == 0){
ImageIcon ic = new ImageIcon("/Textures/water.jpg");
g2d.drawImage(ic.getImage(), x, y, null);
}
}
}
}
I could see potentially two big issues in your code, in your code "y" represents rows and "x" represents columns but in your if statement you are picking [column][row] and while having a dry run you are probabily counting [row][column] and secondly you are always counting columns that are present in first row. if your data structure is always nXn in such case it will work but in any other case you would have different results and you might encounter ArrayIndexOutofBound exception.

OutofBoundsException setpixels

I am trying to fill a rectangle of pixels, but I always get Arrayindexoutofbounds at the below line:
targetwr.setPixels(i, j, 3, 3, pixel);
Here is my code:
WritableRaster sourcewr = source.getRaster();
BufferedImage bi = new BufferedImage(source.getWidth(),
source.getHeight(), BufferedImage.TYPE_INT_ARGB);
WritableRaster targetwr = bi.getRaster();
for (int i = 0; i < sourcewr.getWidth() - rate; i += rate) {
for (int j = 0; j < sourcewr.getHeight() - rate; j += rate) {
int[] pixel = null;
pixel = sourcewr.getPixel(i, j, pixel);
System.out.println(i + " " + j);
targetwr.setPixels(i, j, 3, 3, pixel);
}
}
Pretty straightforward. The sourcewr raster is larger than the targetwr raster. You are iterating over the length and height of the sourcewr and never check to see if the coordinates are in-bounds for the targetwr.
You can check to see if i and j are within bounds or ensure that the rasters are the same size before the nested for loops. e.g.,
if(i < targetwr.getWidth() && j < targetwr.getHeight()) {
targetwr.setPixels(i, j, 3, 3, pixel);
}
This is obviously also affected by the variable rate, whatever that is. It's not defined in your code snippet.

Java Drawing a game board as a grid

Hey I am trying to draw a grid. I have dreated a 2D array and I am trying to fill it with Rectangle2D's. I would like the grid to be equal squares where a character can alk on. Here is my code:
public class GameWindow
{
public static int[][] map = {
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 2, 1, 0, 0}
};
public static double[][] board;
public static Rectangle2D setBoard()
{
Rectangle2D.Double tile = new Rectangle2D.Double(10, 10, 10, 10);
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
board[i][j] = tile;
}
}
}
public static int rows = 6;
public static int columns = 5;
public static int[][] next = new int[rows][columns];
public static void main(String[] args)
{
for(int i = 0; i < map.length; i++)
{
for(int j = 0; j < map[i].length; j++)
{
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
}
There is a compile error and it is not letting me store rectangles in this array. Also I have doubts that it would even make a grid.
Well, board is an array of double and you are trying to put a Rectangle in there!!! You need:
public static Rectangle2D[][] board = new Rectangle2D[10][10];
And you need to decide where exactly the Rectangles will be located on screen somehow. You should not create a single Rectangle and place it in each location of the board.
public static Rectangle2D setBoard()
{
Rectangle2D.Double tile;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
tile = new Rectangle2D.Double(x, y, w, h);//how will you determine x and y here
board[i][j] = tile;
}
}
}
The code within setBoard has a couple of errors. First, you are creating a single Rectangle2D.Double instance, which you then reuse many times when building the contents of board. This means that if you make a change to any entry in board, all of the entries will be changed - the array contains 100 references to the same object.
The second issue, which is likely causing your compile error, is that board has type double[][] but you're trying to put a Rectangle2D.Double into it, which is a different "double" to your array. You can only put double values into your array.

Finding a sequence of pixels by color

I have this code:
{
Robot robot = new Robot();
Color inputColor = new Color();
Rectangle rectangle = new Rectangle(0, 0, 1365, 770);
BufferedImage image = robot.createScreenCapture(rectangle);
for(int x = 0; x < rectangle.getWidth(); x++)
{
for (int y = 0; y < rectangle.getHeight(); y++)
{
if (image.getRGB(x, y) == inputColor.getRGB())
{
return 1;
break;
}
}
}
}
it is supposed to, and does, take a screenshot and find in it a pixel specified by the inputColor. However the program requirements have changed, and now it needs to find a string of pixels 5 long that match a given string. Is there an easy way to specify this with the existing code, or will I need to change it? I mean, can I keep the existing code and define inputColor as a string with the values of the 5 pixels, or do I need to change the whole algorithm?
I think something like this would work. Not the best efficiency, but its a bone to chew.
int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth())) {
for (int i = 0; i < pixels.length; i++) {
if (Array.equals(search, Array.copyOfRange(pixels, i, i + search.length)) {
//found it
}
}
search would be an array of integers(your colors).

Categories

Resources