Find index near mouseX, mouseY with matrix - java

I am creating a game sort of based on the Game of Life and Death. The goal of the project is when the cells turn white they will reproduce with other nearby cells, and when they are black they will die randomly. This part of the game I want to implement and have it run based on the state of the cells (life or death).
Currently, when the cells are white and the mouse is pressed the cell will turn white and stay white until the mouse is unclicked and clicked again. When they are black they will be erased if the mouse is over them. Unfortunately, that also removes the array value from the matrix I use to keep track of the current cells. How can I use matrixes without getting an Array Index out of bounds error? I've tried adding a second if statement to search for nearby cells, but it searches even if the cells aren't drawn. I including the entire code here as I do not want to exclude any parts. For reference, I am using Processing 3 for Java.
int value = 0;
int cols, rows;
int scl = 20;
boolean[][] matrix = new boolean[scl+1][scl+1];
boolean life;
boolean death;
void setup() {
frameRate(25);
size(400, 400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
//cell border color
stroke(55);
if ((mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)) {
if (mousePressed == true) {
//println("Clicked at: " + xpos + " and " + ypos);
if (!matrix[xpos/scl][ypos/scl]) {
matrix[xpos/scl][ypos/scl] = true;
if (life){
matrix[xpos/scl][ypos/scl] = true;
println("Living at " + xpos + " and " + ypos);
}
if (death){
matrix[xpos/scl][ypos/scl] = false;
println("Dying at " + xpos + " and " + ypos);
}
} else {
matrix[xpos/scl][ypos/scl] = false;
}
//fill(100);
fill(value);
}
//println("Mouse at: " + xpos + " and " + ypos);
} else {
fill(50);
}
if (matrix[x][y]) {
fill(value);
}
rect(xpos, ypos, scl, scl);
}
}
}
void mousePressed() {
if (value == 0) {
life = true;
death = false;
value = 245;
} else {
life = false;
death = true;
value = 0;
}
}

Related

"Avoid Falling Blocks " the game on Processing java

So I am making this game in processing JAVA and the code is below so the gist is I have a ball and it avoids the falling rectangles so, for now, the ball can move sideways and the rectangles fall from above but how do I decrease my life when a rectangle hits the ball.
I made a function named Lives which was supposed to decrease lives if the circle gets hit with a rectangle but I can't come up with the code for that. Could anyone help with that?
int score;
int score1;
int miss;
int lives=10;
int ballx, bally;
class Rect
{
float x;
float y;
float speed;
float leng;
color c;
boolean valid;
final int MAX_COLOR = 255;
final int MIN_X = 50, MAX_X = 750;
final int MIN_Y = -800, MAX_Y = -100;
int MIN_SPEED = 1, MAX_SPEED = 2;
final int MIN_Leng = 50, MAX_Leng =100 ;
Rect()
{
initAll();
}
void initAll() {
valid = true;
c = color(random(255), random(255), random(255));
x = random(MIN_X, MAX_X);
y = random(MIN_Y, MAX_Y);
speed = random(MIN_SPEED, MAX_SPEED);
leng = random(MIN_Leng, MAX_Leng);
}
void update() {
if (!valid) {
initAll();
return;
}
move();
draw_rect();
}
void draw_rect()
{
fill(c);
rect (x, y, leng, leng);
}
void move()
{
if (y-leng <= height)
{
y += speed;
} else if (y-leng > height )
{
valid = false;
miss++;
}
}
void Lives()
{
}
void GameOver()
{
if (lives==0)
{
for (int i = 0; i < Obj.length; i++)
{
Obj[i] = new Rect();
}
background(0);
textSize(50 );
fill(255);
text( "You Lose ", 15, 150);
text( "Score: " + score, 15, 100);
}
}
boolean isOver(int mx, int my) {
float disX = x - mx;
float disY = y - my;
if (sqrt(sq(disX) + sq(disY)) < leng/2 ) {
return true;
} else {
return false;
}
}
}
Rect [] Obj = new Rect [10];
void setup() {
size (400, 600);
ballx=200;
bally=300;
for (int i = 0; i < Obj.length; i++)
{
Obj[i] = new Rect();
}
}
void draw() {
background(0);
textSize(50);
//fill(0);
text( "Score: " + score, 0, 100);
text("Lives: " + lives, 0, 50);
ellipse(ballx,bally,20,20);
for (int i = 0; i < Obj.length; i++) {
Obj[i].update();
//Obj[i].Lives();
Obj[i].GameOver();
}
surface.setTitle(nf(frameRate, 3, 2));
}
void keyPressed(){
for(Rect s : Obj){
if ( key =='q' ){
ballx=ballx-2;
score++;
score1++;
s.valid = false;
break;
}
if ( key =='e'){
ballx=ballx+2;
score++;
score1++;
s.valid = false;
break;
}
}
}
Easiest i think think of is -
case 1 - if you want health of ball to reduce gradually :
Define maximum_Health variable and assign it to 100.
Every time a block hits your ball, reduce the health by some weight you want to define.
case 2 - if ball life is lost for every block hit
Define remaining_Lives variable and give it some value you want the number of lives to start with.
Every time a block hits your ball, reduce the remaining_Lives by one.
I think that should give you some hint.

How to convert the mouse position in pixels into the row and column on the grid?

I am basically making a battleship guessing game where you have to the position of a ship by the click of your mouse. When a position of the ship is guessed correctly it deletes that ship cell from the array and when every cell is guessed correctly, the game is over.
What I am now struggling on is to
keep the ship cells within the canvas
convert the mouse position in pixels into the row and column on the grid
if the guess is correct, add the guess to the hit array and if missed adding it to the miss array.
when a guess is made, in addition to colouring the cell, print either “Hit!” or “Miss!” on the cell
sinking the ship when all cells have been hit
In your code you've mixed rows and columns. The x coordinate goes from the left to the right, this are the columns. The y axis goes from the top to the bottom and corresponds to the rows.
Don't store column, row, hit and miss in arrays. But use 2-dimensional arrays to store the position of the ship and the positions of mouse clicks:
boolean [][] ship;
boolean [][] click;
keep the ship cells within the canvas
If the direction is horizontal, then the x start position of the ship has to be less than NUM_COLS - shipLength:
randomX = (int)random(NUM_COLS - shipLength);
randomY = (int)random(NUM_ROWS);
If the direction is horizontal, then the y start position of the ship has to be less than NUM_ROWS - shipLength:
randomX = (int)random(NUM_COLS);
randomY = (int)random(NUM_ROWS - shipLength);
Call randomShip in setup rather than draw:
void setup() {
size(600, 500);
randomShip();
println(store);
}
void draw() {
// randomShip(); <---- delete
drawCells (row, column, shipLength, (255) );
}
Generate the random position and size of the ship in randomShip;
void randomShip () {
ship = new boolean[NUM_COLS][NUM_ROWS];
click = new boolean[NUM_COLS][NUM_ROWS];
shipLength = (int)random (3, 8);
int store = (int)random(vert, horz);
if (store >= 0) {
int randomX = (int)random(NUM_COLS - shipLength);
int randomY = (int)random(NUM_ROWS);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX + i][randomY] = true;
}
} else {
int randomX = (int)random(NUM_COLS);
int randomY = (int)random(NUM_ROWS - shipLength);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX][randomY+1] = true;
}
}
println(shipLength);
}
convert the mouse position in pixels into the row and column on the grid
if the guess is correct, add the guess to the hit array and if missed adding it to the miss array.
The cell which was clicked can be get by the dividing the mouse coordinates mouseX and mouseY by CELLSIZE
int cell_x = mouseX / CELLSIZE;
int cell_y = mouseY / CELLSIZE;
Store mark the clicked cells and count the hits and miss in mouseClicked:
void mouseClicked () {
int cell_x = mouseX / CELLSIZE;
int cell_y = mouseY / CELLSIZE;
if (!click[cell_x][cell_y]) {
click[cell_x][cell_y] = true;
if ( ship[cell_x][cell_y] ) {
hitCount ++;
} else {
missCount ++;
}
}
}
when a guess is made, in addition to colouring the cell, print either “Hit!” or “Miss!” on the cell
Evaluate the ship position (ship[][]) and clicked positions (click[][]) in drawCells. Draw the cells and the text dependent on the states in 2 nested loops:
void drawCells(int colour) {
for (int i = 0; i < NUM_COLS; i++) {
for (int j = 0; j < NUM_ROWS; j++) {
float x = i * CELLSIZE;
float y = j * CELLSIZE;
if (ship[i][j]) {
fill (colour);
rect(x, y, CELLSIZE, CELLSIZE);
}
if (click[i][j]) {
fill(255, 0, 0);
textSize(15);
text(ship[i][j] ? "hit" : "miss", x+10, y+30);
}
}
}
}
sinking the ship when all cells have been hit
Handle the end of the game in draw:
e.g.
void draw() {
drawCells(255);
if (hitCount == shipLength ) {
// [...]
}
}
Full code listing:
final int CELLSIZE = 50;
final int NUM_ROWS = 10;
final int NUM_COLS = 12;
int horz = (int)random(50);
int vert = (int)random(-50);
int store;
int shipLength;
boolean [][] ship;
boolean [][] click;
int hitCount = 0;
int missCount = 0;
void setup() {
size(600, 500);
randomShip();
println(store);
}
void draw() {
drawCells(255);
if (hitCount == shipLength ) {
// [...]
}
}
void drawCells(int colour) {
for (int i = 0; i < NUM_COLS; i++) {
for (int j = 0; j < NUM_ROWS; j++) {
float x = i * CELLSIZE;
float y = j * CELLSIZE;
if (ship[i][j]) {
fill (colour);
rect(x, y, CELLSIZE, CELLSIZE);
}
if (click[i][j]) {
fill(255, 0, 0);
textSize(15);
text(ship[i][j] ? "hit" : "miss", x+10, y+30);
}
}
}
}
void randomShip () {
ship = new boolean[NUM_COLS][NUM_ROWS];
click = new boolean[NUM_COLS][NUM_ROWS];
hitCount = 0;
missCount = 0;
shipLength = (int)random (3, 8);
int store = (int)random(vert, horz);
if (store >= 0) {
int randomX = (int)random(NUM_COLS - shipLength);
int randomY = (int)random(NUM_ROWS);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX + i][randomY] = true;
}
} else {
int randomX = (int)random(NUM_COLS);
int randomY = (int)random(NUM_ROWS - shipLength);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX][randomY+1] = true;
}
}
println(shipLength);
}
void mouseClicked () {
int cell_x = mouseX / CELLSIZE;
int cell_y = mouseY / CELLSIZE;
if (!click[cell_x][cell_y]) {
click[cell_x][cell_y] = true;
if ( ship[cell_x][cell_y] ) {
hitCount ++;
} else {
missCount ++;
}
}
}

Mouse Clicked is not working

I'm trying to have a square change colors from black to white and from white to black whenever the square is clicked on. I use the mouseClicked function to do so, but the problem is that the mouseClicked is not clicking correctly. When I click on the bottom of one square, the square underneath of it is pressed.
Here's my mouseClicked code:
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
System.out.println(mouseX + ", " + mouseY + ", " + (screenW / squares));
colorFlip();
}
});
My colorFlip code:
private void colorFlip() {
for (int i = 0; i < cells.size(); i++) {
Cell cell = cells.get(i);
int x = cell.getX();
int y = cell.getY();
int side = cell.getSide();
if (mouseX >= x && mouseX < x + side && mouseY >= y && mouseY < y + side) {
if (cell.getR() == 0) {
cell.setRGB(255, 255, 255);
} else if (cell.getR() == 255) {
cell.setRGB(0, 0, 0);
}
}
}
mouseX = -1;
mouseY = -1;
}
And my cell initialization code:
Cell(double xVal, double yVal, double sideVal) {
x = xVal;
y = yVal;
side = sideVal;
}
Thanks,
Pranav

Converting monochrome image to minimum number of 2d shapes

Basically, what I need to do is take a 2d array of bitflags and produce a list of 2d rectangles to fill the entire area with the minimum number of total shapes required to perfectly fill the space. I am doing this to convert a 2d top-down monochrome of a map into 2d rectangle shapes which perfectly represent the passed in image which will be used to generate a platform in a 3d world. I need to minimize the total number of shapes used, because each shape will represent a separate object, and flooding it with 1 unit sized squares for each pixel would be highly inefficient for that engine.
So far I have read in the image, processed it, and filled a two dimensional array of booleans which tells me if the pixel should be filled or unfilled, but I am unsure of the most efficient approach of continuing.
Here is what I have so far, as reference, if you aren't following:
public static void main(String[] args) {
File file = new File(args[0]);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (IOException ex) {
Logger.global.log(Level.SEVERE, null, ex);
}
if (bi != null) {
int[] rgb = bi.getRGB(0, 0, bi.getWidth(), bi.getHeight(), new int[bi.getWidth() * bi.getHeight()], 0, bi.getWidth());
Origin origin = new Origin(bi.getWidth() / 2, bi.getHeight() / 2);
boolean[][] flags = new boolean[bi.getWidth()][bi.getHeight()];
for (int y = 0; y < bi.getHeight(); y++) {
for (int x = 0; x < bi.getWidth(); x++) {
int index = y * bi.getWidth() + x;
int color = rgb[index];
int type = color == Color.WHITE.getRGB() ? 1 : (color == Color.RED.getRGB() ? 2 : 0);
if (type == 2) {
origin = new Origin(x, y);
}
flags[x][y] = type != 1;
}
}
List<Rectangle> list = new ArrayList();
//Fill list with rectangles
}
}
White represents no land. Black or Red represents land. The check for the red pixel marks the origin position of map, which was just for convenience and the rectangles will be offset by the origin position if it is found.
Edit: The processing script does not need to be fast, the produced list of rectangles will be dumped and that will be what will be imported and used later, so the processing of the image does not need to be particularly optimized, it doesn't make a difference.
I also just realized that expecting a 'perfect' solution is expecting too much, since this would qualify as a 'knapsack problem' of the multidimensionally constrained variety, if I am expecting exactly the fewest number of rectangles, so simply an algorithm that produces a minimal number of rectangles will suffice.
Here is a reference image for completion:
Edit 2: It doesn't look like this is such an easy thing to answer given no feedback yet, but I have started making progress, but I am sure I am missing something that would vastly reduce the number of rectangles. Here is the updated progress:
static int mapWidth;
static int mapHeight;
public static void main(String[] args) {
File file = new File(args[0]);
BufferedImage bi = null;
System.out.println("Reading image...");
try {
bi = ImageIO.read(file);
} catch (IOException ex) {
Logger.global.log(Level.SEVERE, null, ex);
}
if (bi != null) {
System.out.println("Complete!");
System.out.println("Interpreting image...");
mapWidth = bi.getWidth();
mapHeight = bi.getHeight();;
int[] rgb = bi.getRGB(0, 0, mapWidth, mapHeight, new int[mapWidth * mapHeight], 0, mapWidth);
Origin origin = new Origin(mapWidth / 2, mapHeight / 2);
boolean[][] flags = new boolean[mapWidth][mapHeight];
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
int index = y * mapWidth + x;
int color = rgb[index];
int type = color == Color.WHITE.getRGB() ? 1 : (color == Color.RED.getRGB() ? 2 : 0);
if (type == 2) {
origin = new Origin(x, y);
}
flags[x][y] = type != 1;
}
}
System.out.println("Complete!");
System.out.println("Processing...");
//Get Rectangles to fill space...
List<Rectangle> rectangles = getRectangles(flags, origin);
System.out.println("Complete!");
float rectangleCount = rectangles.size();
float totalCount = mapHeight * mapWidth;
System.out.println("Total units: " + (int)totalCount);
System.out.println("Total rectangles: " + (int)rectangleCount);
System.out.println("Rectangle reduction factor: " + ((1 - rectangleCount / totalCount) * 100.0) + "%");
System.out.println("Dumping data...");
try {
file = new File(file.getParentFile(), file.getName() + "_Rectangle_Data.txt");
if(file.exists()){
file.delete();
}
file.createNewFile();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
for(Rectangle rect: rectangles){
bw.write(rect.x + "," + rect.y + "," + rect.width + ","+ rect.height + "\n");
}
bw.flush();
bw.close();
} catch (Exception ex) {
Logger.global.log(Level.SEVERE, null, ex);
}
System.out.println("Complete!");
}else{
System.out.println("Error!");
}
}
public static void clearRange(boolean[][] flags, int xOff, int yOff, int width, int height) {
for (int y = yOff; y < yOff + height; y++) {
for (int x = xOff; x < xOff + width; x++) {
flags[x][y] = false;
}
}
}
public static boolean checkIfFilled(boolean[][] flags, int xOff, int yOff, int width, int height) {
for (int y = yOff; y < yOff + height; y++) {
for (int x = xOff; x < xOff + width; x++) {
if (!flags[x][y]) {
return false;
}
}
}
return true;
}
public static List<Rectangle> getRectangles(boolean[][] flags, Origin origin) {
List<Rectangle> rectangles = new ArrayList();
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
if (flags[x][y]) {
int maxWidth = 1;
int maxHeight = 1;
Loop:
//The search size limited to 400x400 so it will complete some time this century.
for (int w = Math.min(400, mapWidth - x); w > 1; w--) {
for (int h = Math.min(400, mapHeight - y); h > 1; h--) {
if (w * h > maxWidth * maxHeight) {
if (checkIfFilled(flags, x, y, w, h)) {
maxWidth = w;
maxHeight = h;
break Loop;
}
}
}
}
//Search also in the opposite direction
Loop:
for (int h = Math.min(400, mapHeight - y); h > 1; h--) {
for (int w = Math.min(400, mapWidth - x); w > 1; w--) {
if (w * h > maxWidth * maxHeight) {
if (checkIfFilled(flags, x, y, w, h)) {
maxWidth = w;
maxHeight = h;
break Loop;
}
}
}
}
rectangles.add(new Rectangle(x - origin.x, y - origin.y, maxWidth, maxHeight));
clearRange(flags, x, y, maxWidth, maxHeight);
}
}
}
return rectangles;
}
My current code's search for larger rectangles is limited to 400x400 to speed up testing, and outputs 17,979 rectangles, which is a 99.9058% total reduction of rectangles if I treated each pixel as a 1x1 square(19,095,720 pixels). So far so good.

Animating smoothly in android surfaceview

I have created a Tetris game on android and I don't think the animation is as good as it could be. When blocks are moving fast (100ms between the ticks), it's a pretty obvious flicker in the animation, as if there's a very short moment where you can see traces of the previous position of the moving block.
Here is the animation loop, implemented in a separate thread as an extension of SurfaceView:
public void run()
{
while(running)
{
if(surfaceHolder.getSurface().isValid())
{
sleep(1);
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.BLACK); //reset canvas
int width = canvas.getWidth();
int squareSpaceW = (width/4)*3;
int squareSize = squareSpaceW/10;
squareSpaceW = squareSize*10;
int squareSpaceH = squareSpaceW*2;
//Draw lines on the play field
canvas.drawLine(squareSpaceW, 0, squareSpaceW, squareSpaceH, whitePaint);
canvas.drawLine(0, squareSpaceH, squareSpaceW, squareSpaceH, whitePaint);
//draw next piece
int nxtPieceSize = board.getNextPiece().getBlocks().size() -1;
while(nxtPieceSize >= 0)
{
rectPaint.setColor(Color.parseColor(board.getNextPiece().getBlocks().get(nxtPieceSize).getColor()));
int x = board.getNextPiece().getCoordList().get(nxtPieceSize).getX();
int y = board.getNextPiece().getCoordList().get(nxtPieceSize).getY();
nxtPieceSize--;
rect.set(x*(squareSize/2) + (squareSpaceW/17)*16, y*(squareSize/2) + (squareSize/2), x*(squareSize/2) + (squareSize/2) + (squareSpaceW/17)*16, y*(squareSize/2)+ (squareSize/2) + (squareSize/2));
canvas.drawRect(rect, rectPaint);
}
//draw text
canvas.drawText("Score: " + Integer.toString(board.getScore()), width - (width/8), (width/8) + (squareSize), whitePaint);
canvas.drawText("Level: " + Integer.toString(board.getLevel()), width - (width/8), (width/8) + (squareSize*2), whitePaint);
//draw the blocks
for(int x = 0; x < board.getWidth(); x++)
{
for(int y = 0; y < board.getHeight(); y++)
{
tempBlock = board.getBlock(x, y);
if(tempBlock != null)
{
rectPaint.setColor(Color.parseColor(tempBlock.getColor()));
rect.set(x*squareSize, y*squareSize, x*squareSize + squareSize, y*squareSize+ squareSize);
canvas.drawRect(rect, rectPaint);
}
}
}
//draw pause icon
rect.set(squareSize/2,squareSize/2, (squareSize/4)*3, squareSize + squareSize/2);
canvas.drawRect(rect, whitePaint);
rect.set(squareSize ,squareSize/2, squareSize + squareSize/4, squareSize + squareSize/2);
canvas.drawRect(rect, whitePaint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
Hope I have given the information you need. Sorry if the code is a bit messy...

Categories

Resources