I'm currently recreating a Civilization game in Processing. I'm planning to implement the feature in a which a given unit can see every possible move it can make with a given number of hexes it is allowed to move. All possible endpoints are marked with red circles. However, units cannot move through mountains or bodies of water. I'm trying to approach this by finding out every possible combination of moves I can make without the unit going into a mountain or body of water but I can't figure out how I can determine every combination.
There are 6 directions that any unit can go in, north-east, north, north-west, south-east, south, south-west. The max number of movements I'm assigning to any unit would probably go up to 6. Any higher and I'm afraid processing may become to slow every time I move a unit.
I'm trying to recreate this:
What I'm hoping the result will look like with two possible movements (without the black arrows):
Raw version of that image:
Here is the code I use to draw the hex grid. Immediately after drawing each individual hex, its center's x coords and y coords are stored in xHexes and yHexes respectively. Also, immediately after generating the type of tile (e.g. grass, beach), the type of tile is also stored in an array named hexTypes. Therefore, I can get the x and y coords and type of hex of any hex I want on the map just by referencing its index.
Code used to draw a single hexagon:
beginShape();
for (float a = PI/6; a < TWO_PI; a += TWO_PI/6) {
float vx = x + cos(a) * gs*2;
float vy = y + sin(a) * gs*2;
vertex(vx, vy);
}
x is the x coord for centre of hexagon
y is the y coord for centre of hexagon
gs = radius of hexagon
Code used to tesselate hex over the window creating a hex grid:
void redrawMap() {
float xChange = 1.7;
float yChange = 6;
for (int y = 0; y < ySize/hexSize; y++) {
for (int x = 0; x < xSize/hexSize; x++) {
if (x % 2 == 1) {
// if any part of this hexagon being formed will be visible on the window and not off the window.
if (x*hexSize*xChange <= width+2*hexSize && int(y*hexSize*yChange) <= height+3*hexSize) {
drawHex(x*hexSize*xChange, y*hexSize*yChange, hexSize);
}
// only record and allow player to react with it if the entire tile is visible on the window
if (x*hexSize*xChange < width && int(y*hexSize*yChange) < height) {
xHexes.add(int(x*hexSize*xChange));
yHexes.add(int(y*hexSize*yChange));
}
} else {
if (x*hexSize*xChange <= width+2*hexSize && int(y*hexSize*yChange) <= height+3*hexSize) {
drawHex(x*hexSize*xChange, y*hexSize*yChange+(hexSize*3), hexSize);
}
if (x*hexSize*xChange < width && int(y*hexSize*yChange+(hexSize*3)) < height) {
xHexes.add(int(x*hexSize*xChange));
yHexes.add(int(y*hexSize*yChange+(hexSize*3)));
}
}
}
}
}
hexSize is a user-specified size for each hexagon, determining the number of hexagons that will be on the screen.
This answer will help you get to this (green is plains, red is hills and blue is water, also please don't flame my terrible grid):
Note that there is no pathfinding in this solution, only some very simple "can I get there" math. I'll include the full code of the sketch at the end so you can reproduce what I did and test it yourself. One last thing: this answer doesn't use any advanced design pattern, but it assume that you're confortable with the basics and Object Oriented Programming. If I did something which you're not sure you understand, you can (and should) ask about it.
Also: this is a proof of concept, not a "copy and paste me" solution. I don't have your code, so it cannot be that second thing anyway, but as your question can be solved in a bazillion manners, this is only one which I deliberately made as simple and visual as possible so you can get the idea and run with it.
First, I strongly suggest that you make your tiles into objects. First because they need to carry a lot of information (what's on each tile, how hard they are to cross, maybe things like resources or yield... I don't know, but there will be a lot of stuff).
The Basics
I organized my global variables like this:
// Debug
int unitTravelPoints = 30; // this is the number if "travel points" currently being tested, you can change it
// Golbals
float _tileSize = 60;
int _gridWidth = 10;
int _gridHeight = 20;
ArrayList<Tile> _tiles = new ArrayList<Tile>(); // all the tiles
ArrayList<Tile> _canTravel = new ArrayList<Tile>(); // tiles you can currently travel to
The basics being that I like to be able to change my grid size on the fly, but that's just a detail. What's next is to choose a coordinate system for the grid. I choose the simplest one as I didn't want to bust my brain on something complicated, but you may want to adapt this to another coordinate system. I choose the offset coordinate type of grid: my "every second row" is half a tile offset. So, instead of having this:
I have this:
The rest is just adjusting the spatial coordinates of the tiles so it doesn't look too bad, but their coordinates stays the same:
Notice how I consider that the spatial coordinates and the grid coordinates are two different things. I'll mostly use the spatial coordinates for the proximity checks, but that's because I'm lazy, because you could make a nice algorithm which do the same thing without the spatial coordinates and it would probably be less costly.
What about the travel points? Here's how I decided to work: your unit has a finite amount of "travel points". Here there's no unit, but instead a global variable unitTravelPoints which will do the same thing. I decided to work with this scale: one normal tile is worth 10 travel points. So:
Plains: 10 points
Hills: 15 points
Water: 1000 points (this is impassable terrain but without going into the details)
I'm not going to go into the details of drawing a grid, but that's mostly because your algorithm looks way better than mine on this front. On the other hand, I'll spend some time on explaining how I designed the Tiles.
The Tiles
We're entering OOP: they are Drawable. Drawable is a base class which contains some basic info which every visible thing should have: a position, and an isVisible setting which can be turned off. And a method to draw it, which I call Render() since draw() is already taken by Processing:
class Drawable {
PVector position;
boolean isVisible;
public Drawable() {
position = new PVector(0, 0);
isVisible = true;
}
public void Render() {
// If you forget to overshadow the Render() method you'll see this error message in your console
println("Error: A Drawable just defaulted to the catch-all Render(): '" + this.getClass() + "'.");
}
}
The Tile will be more sophisticated. It'll have more basic informations: row, column, is it currently selected (why not), a type like plains or hills or water, a bunch of neighboring tiles, a method to draw itself and a method to know if the unit can travel through it:
class Tile extends Drawable {
int row, column;
boolean selected = false;
TileType type;
ArrayList<Tile> neighbors = new ArrayList<Tile>();
Tile(int row, int column, TileType type) {
super(); // this calls the parent class' constructor
this.row = row;
this.column = column;
this.type = type;
// the hardcoded numbers are all cosmetics I included to make my grid looks less awful, nothing to see here
position.x = (_tileSize * 1.5) * (column + 1);
position.y = (_tileSize * 0.5) * (row + 1);
// this part checks if this is an offset row to adjust the spatial coordinates
if (row % 2 != 0) {
position.x += _tileSize * 0.75;
}
}
// this method looks recursive, but isn't. It doesn't call itself, but it calls it's twin from neighbors tiles
void FillCanTravelArrayList(int travelPoints, boolean originalTile) {
if (travelPoints >= type.travelCost) {
// if the unit has enough travel points, we add the tile to the "the unit can get there" list
if (!_canTravel.contains(this)) {
// well, only if it's not already in the list
_canTravel.add(this);
}
// then we check if the unit can go further
for (Tile t : neighbors) {
if (originalTile) {
t.FillCanTravelArrayList(travelPoints, false);
} else {
t.FillCanTravelArrayList(travelPoints - type.travelCost, false);
}
}
}
}
void Render() {
if (isVisible) {
// the type knows which colors to use, so we're letting the type draw the tile
type.Render(this);
}
}
}
The Tile Types
The TileType is a strange animal: it's a real class, but it's never used anywhere. That's because it's a common root for all tile types, which will inherit it's basics. The "City" tile may need very different variables than, say, the "Desert" tile. But both need to be able to draw themselves, and both need to be owned by the tiles.
class TileType {
// cosmetics
color fill = color(255, 255, 255);
color stroke = color(0);
float strokeWeight = 2;
// every tile has a "travelCost" variable, how much it cost to travel through it
int travelCost = 10;
// while I put this method here, it could have been contained in many other places
// I just though that it made sense here
void Render(Tile tile) {
fill(fill);
if (tile.selected) {
stroke(255);
} else {
stroke(stroke);
}
strokeWeight(strokeWeight);
DrawPolygon(tile.position.x, tile.position.y, _tileSize/2, 6);
textAlign(CENTER, CENTER);
fill(255);
text(tile.column + ", " + tile.row, tile.position.x, tile.position.y);
}
}
Each tile type can be custom, now, yet each tile is... just a tile, whatever it's content. Here are the TileType I used in this demonstration:
// each different tile type will adjust details like it's travel cost or fill color
class Plains extends TileType {
Plains() {
this.fill = color(0, 125, 0);
this.travelCost = 10;
}
}
class Water extends TileType {
// here I'm adding a random variable just to show that you can custom those types with whatever you need
int numberOfFishes = 10;
Water() {
this.fill = color(0, 0, 125);
this.travelCost = 1000;
}
}
class Hill extends TileType {
Hill() {
this.fill = color(125, 50, 50);
this.travelCost = 15;
}
}
Non-class methods
I added a mouseClicked() method so we can select a hex to check how far from it the unit can travel. In your game, you would have to make it so when you select a unit all these things fall into place, but as this is just a proof of concept the unit is imaginary and it's location is wherever you click.
void mouseClicked() {
// clearing the array which contains tiles where the unit can travel as we're changing those
_canTravel.clear();
for (Tile t : _tiles) {
// select the tile we're clicking on (and nothing else)
t.selected = IsPointInRadius(t.position, new PVector(mouseX, mouseY), _tileSize/2);
if (t.selected) {
// if a tile is selected, check how far the imaginary unit can travel
t.FillCanTravelArrayList(unitTravelPoints, true);
}
}
}
At last, I added 2 "helper methods" to make things easier:
// checks if a point is inside a circle's radius
boolean IsPointInRadius(PVector center, PVector point, float radius) {
// simple math, but with a twist: I'm not using the square root because it's costly
// we don't need to know the distance between the center and the point, so there's nothing lost here
return pow(center.x - point.x, 2) + pow(center.y - point.y, 2) <= pow(radius, 2);
}
// draw a polygon (I'm using it to draw hexagons, but any regular shape could be drawn)
void DrawPolygon(float x, float y, float radius, int npoints) {
float angle = TWO_PI / npoints;
beginShape();
for (float a = 0; a < TWO_PI; a += angle) {
float sx = x + cos(a) * radius;
float sy = y + sin(a) * radius;
vertex(sx, sy);
}
endShape(CLOSE);
}
How Travel is calculated
Behind the scenes, that's how the program knows where the unit can travel: in this example, the unit has 30 travel points. Plains cost 10, hills cost 15. If the unit has enough points left, the tile is marked as "can travel there". Every time a tile is in travel distance, we also check if the unit can get further from this tile, too.
Now, if you're still following me, you may ask: how do the tiles know which other tile is their neighbor? That's a great question. I suppose that an algorithm checking their coordinates would be the best way to handle this, but as this operation will happen only once when we create the map I decided to take the easy route and check which tiles were the close enough spatially:
void setup() {
// create the grid
for (int i=0; i<_gridWidth; i++) {
for (int j=0; j<_gridHeight; j++) {
int rand = (int)random(100);
if (rand < 20) {
_tiles.add(new Tile(j, i, new Water()));
} else if (rand < 50) {
_tiles.add(new Tile(j, i, new Hill()));
} else {
_tiles.add(new Tile(j, i, new Plains()));
}
}
}
// detect and save neighbor tiles for every Tile
for (Tile currentTile : _tiles) {
for (Tile t : _tiles) {
if (t != currentTile) {
if (IsPointInRadius(currentTile.position, t.position, _tileSize)) {
currentTile.neighbors.add(t);
}
}
}
}
}
Complete code for copy-pasting
Here's the whole thing in one place so you can easily copy and paste it into a Processing IDE and play around with it (also, it includes how I draw my awful grid):
// Debug
int unitTravelPoints = 30; // this is the number if "travel points" currently being tested, you can change it
// Golbals
float _tileSize = 60;
int _gridWidth = 10;
int _gridHeight = 20;
ArrayList<Tile> _tiles = new ArrayList<Tile>();
ArrayList<Tile> _canTravel = new ArrayList<Tile>();
void settings() {
// this is how to make a window size's dynamic
size((int)(((_gridWidth+1) * 1.5) * _tileSize), (int)(((_gridHeight+1) * 0.5) * _tileSize));
}
void setup() {
// create the grid
for (int i=0; i<_gridWidth; i++) {
for (int j=0; j<_gridHeight; j++) {
int rand = (int)random(100);
if (rand < 20) {
_tiles.add(new Tile(j, i, new Water()));
} else if (rand < 50) {
_tiles.add(new Tile(j, i, new Hill()));
} else {
_tiles.add(new Tile(j, i, new Plains()));
}
}
}
// detect and save neighbor tiles for every Tile
for (Tile currentTile : _tiles) {
for (Tile t : _tiles) {
if (t != currentTile) {
if (IsPointInRadius(currentTile.position, t.position, _tileSize)) {
currentTile.neighbors.add(t);
}
}
}
}
}
void draw() {
background(0);
// show the tiles
for (Tile t : _tiles) {
t.Render();
}
// show how far you can go
for (Tile t : _canTravel) {
fill(0, 0, 0, 0);
if (t.selected) {
stroke(255);
} else {
stroke(0, 255, 0);
}
strokeWeight(5);
DrawPolygon(t.position.x, t.position.y, _tileSize/2, 6);
}
}
class Drawable {
PVector position;
boolean isVisible;
public Drawable() {
position = new PVector(0, 0);
isVisible = true;
}
public void Render() {
// If you forget to overshadow the Render() method you'll see this error message in your console
println("Error: A Drawable just defaulted to the catch-all Render(): '" + this.getClass() + "'.");
}
}
class Tile extends Drawable {
int row, column;
boolean selected = false;
TileType type;
ArrayList<Tile> neighbors = new ArrayList<Tile>();
Tile(int row, int column, TileType type) {
super(); // this calls the parent class' constructor
this.row = row;
this.column = column;
this.type = type;
// the hardcoded numbers are all cosmetics I included to make my grid looks less awful, nothing to see here
position.x = (_tileSize * 1.5) * (column + 1);
position.y = (_tileSize * 0.5) * (row + 1);
// this part checks if this is an offset row to adjust the spatial coordinates
if (row % 2 != 0) {
position.x += _tileSize * 0.75;
}
}
// this method looks recursive, but isn't. It doesn't call itself, but it calls it's twin from neighbors tiles
void FillCanTravelArrayList(int travelPoints, boolean originalTile) {
if (travelPoints >= type.travelCost) {
// if the unit has enough travel points, we add the tile to the "the unit can get there" list
if (!_canTravel.contains(this)) {
// well, only if it's not already in the list
_canTravel.add(this);
}
// then we check if the unit can go further
for (Tile t : neighbors) {
if (originalTile) {
t.FillCanTravelArrayList(travelPoints, false);
} else {
t.FillCanTravelArrayList(travelPoints - type.travelCost, false);
}
}
}
}
void Render() {
if (isVisible) {
// the type knows which colors to use, so we're letting the type draw the tile
type.Render(this);
}
}
}
class TileType {
// cosmetics
color fill = color(255, 255, 255);
color stroke = color(0);
float strokeWeight = 2;
// every tile has a "travelCost" variable, how much it cost to travel through it
int travelCost = 10;
// while I put this method here, it could have been contained in many other places
// I just though that it made sense here
void Render(Tile tile) {
fill(fill);
if (tile.selected) {
stroke(255);
} else {
stroke(stroke);
}
strokeWeight(strokeWeight);
DrawPolygon(tile.position.x, tile.position.y, _tileSize/2, 6);
textAlign(CENTER, CENTER);
fill(255);
text(tile.column + ", " + tile.row, tile.position.x, tile.position.y);
}
}
// each different tile type will adjust details like it's travel cost or fill color
class Plains extends TileType {
Plains() {
this.fill = color(0, 125, 0);
this.travelCost = 10;
}
}
class Water extends TileType {
// here I'm adding a random variable just to show that you can custom those types with whatever you need
int numberOfFishes = 10;
Water() {
this.fill = color(0, 0, 125);
this.travelCost = 1000;
}
}
class Hill extends TileType {
Hill() {
this.fill = color(125, 50, 50);
this.travelCost = 15;
}
}
void mouseClicked() {
// clearing the array which contains tiles where the unit can travel as we're changing those
_canTravel.clear();
for (Tile t : _tiles) {
// select the tile we're clicking on (and nothing else)
t.selected = IsPointInRadius(t.position, new PVector(mouseX, mouseY), _tileSize/2);
if (t.selected) {
// if a tile is selected, check how far the imaginary unit can travel
t.FillCanTravelArrayList(unitTravelPoints, true);
}
}
}
// checks if a point is inside a circle's radius
boolean IsPointInRadius(PVector center, PVector point, float radius) {
// simple math, but with a twist: I'm not using the square root because it's costly
// we don't need to know the distance between the center and the point, so there's nothing lost here
return pow(center.x - point.x, 2) + pow(center.y - point.y, 2) <= pow(radius, 2);
}
// draw a polygon (I'm using it to draw hexagons, but any regular shape could be drawn)
void DrawPolygon(float x, float y, float radius, int npoints) {
float angle = TWO_PI / npoints;
beginShape();
for (float a = 0; a < TWO_PI; a += angle) {
float sx = x + cos(a) * radius;
float sy = y + sin(a) * radius;
vertex(sx, sy);
}
endShape(CLOSE);
}
Hope it'll help. Have fun!
You will have to use similar algorithms we use on pathfinding. you create a stack or queue that will hold a class storing the position of the hex and the number of moves left from that point, initially you insert your starting position with the number of moves you have and mark that hex as done ( to not re-use a position you have already been on ), then you pop an element, and you insert every neighbor of that hex with a number of moves -1. when you insert the hexes with zero moves, those are your endpoints. And before inserting any hex check if it's not already done.
I hope I was clear, your question was a bit vague but I tried to give you an idea of how these solutions are usually done, also I think your question fits more into algorithms rather then processing
Best of luck
I currently work on a BreakOut game and I am almost finished. The only problem I currently have is that the color of the stones wont change, when hit by the ball.
The color of a stone is defined by its type (1-3) and whenever a stone is hit, its type is reduced by 1. I know a stone's type is succesfully reduced when hit, cause it disappears when the type turns into 0.
This is the constructor of the stones class:
public Stone(int type, Position pos) {
this.pos = pos;
this.type = type;
switch(this.type) {
case 1:
value = 5;
color = Color.LIGHT_GRAY;
break;
case 2:
value = 10;
color = Color.orange;
break;
case 3:
value = 15;
color = Color.green;
break;
}
}
This is the method, which draws the stones:
private void drawStones(Graphics2D g2) {
stones = view.getGame().getLevel().getStones();
for (int i = 0; i < stones.length; i++) {
for (int j = 0; j < stones[1].length; j++) {
int x_position = (int) stones[i][j].getPosition().getX();
int y_position = (int) stones[i][j].getPosition().getY();
if(stones[i][j].getType() >= 1) {
g2.setColor(stones[i][j].getColor());
g2.fillRoundRect(x_position, y_position,
(int) ((double)Constants.SCREEN_WIDTH/Constants.SQUARES_X)-2,
(int) ((double)Constants.SCREEN_HEIGHT/Constants.SQUARES_Y)-2 ,1,1);
}
}
}
}
And this is the method, which updates the stones type on hit:
private void updateStonesAndScore() {
int posLine = ball.getHitStonePosition().getLine();
int posColumn = ball.getHitStonePosition().getColumn();
score = score + stones[posLine][posColumn].getValue();
System.out.println(stones[posLine][posColumn].getType());
stones[posLine][posColumn].setColor(stones[posLine][posColumn].getColor());
stones[posLine][posColumn].setType(stones[posLine][posColumn].getType()-1);
}
Does anybody know why stones color doesn't change on hit, allthough its type is succesfully reduced?
Thanks in advance!
You never change the color of the stone. It is set in the constructor but changed no where else (not in code you've shown).
I wouldn't even have the stone hold a color value, but instead let the drawing code decide what to color it, perhaps something like:
private void drawStones(Graphics2D g2) {
stones = view.getGame().getLevel().getStones();
for (int i = 0; i < stones.length; i++) {
for (int j = 0; j < stones[1].length; j++) {
int x_position = (int) stones[i][j].getPosition().getX();
int y_position = (int) stones[i][j].getPosition().getY();
if(stones[i][j].getType() >= 1) {
// ********
int type = stones[i][j].getType();
Color color = .... set color based on type value here
// *******
g2.setColor(stones[i][j].getColor());
g2.fillRoundRect(x_position, y_position,
(int) ((double)Constants.SCREEN_WIDTH/Constants.SQUARES_X)-2,
(int) ((double)Constants.SCREEN_HEIGHT/Constants.SQUARES_Y)-2 ,1,1);
}
}
}
}
I want to code my own version of "game of life", in processing 3, but I've come across an error I don't seem to understand. Whenever the code run, the screen keeps going black and white with a few pixels changing but it does not look like game of life.
Any help?
int windowW, windowH, percentAlive, gen;
//windowW is the width of the window, windowH is the height
//percentVlive is the initial percent of alive pixel
//gen is the counter for the generation
color alive, dead;//alive is white and dead is black to represent their respective colors
boolean[][] cells0, cells1;//two arrays for the state of the cells, either alive or dead
boolean zeroOrOne = true;//this is to check which array should be iterated over
void setup() {
size(700, 700);
int width = 700;
int height = 700;
windowW = width;
windowH = height;
percentAlive = 15;
alive = color(255, 255, 255);
dead = color(0, 0, 0);
cells0 = new boolean[width][height];
cells1 = new boolean[width][height];
frameRate(2);
background(alive);
for (int x=0; x<width; x++) {//set the percent of live pixels according to the precentAlive varriable
for (int y=0; y<height; y++) {
int state = (int)random (100);
if (state > percentAlive)
cells0[x][y] = true;
else
cells0[x][y] = false;
}
}
}
void draw() {
gen += 1;//increases the generation every time it draws
drawLoop(zeroOrOne);
WriteGeneration(gen);
if(zeroOrOne){//changes the zeroOrOne value to change the array being iterated over
zeroOrOne = false;
}
else {
zeroOrOne = true;
}
}
void WriteGeneration(int number) {//changes the label on top
fill(0);
rect(0, 0, windowW, 100);
fill(255);
textFont(loadFont("BerlinSansFB-Reg-100.vlw"));
text("Generation " + number, 10, 90);
}
void drawLoop(boolean check) {
loadPixels();
if (check) {//checks which array to iterate thrgough
for (int x = 0; x < windowW; x++) {//iterates through the array
for (int y = 0; y < windowH; y++) {
if (cells0[x][y]) {//checks wether the pixel is alive or dead
pixels[x * 700 + y] = alive;//gets the current pixel
int lives = lives(x, y, check);//checks how many cells are alive around the current cell
if (lives<2) {//these are supposed to put in place the game of life rules
cells1[x][y] = false;
} else if (lives>4) {
cells1[x][y] = false;
} else {
cells1[x][y] = true;
}
} else {
pixels[x * 700 + y] = dead;//gets the current pixel
int lives = lives(x, y, check);//checks how many cells are alive around the current cell
if (lives == 3) {//turns the pixel alive if the condition is met
cells1[x][y] = true;
}
}
}
}
} else {//the same as the top but instead the arrays being updated and read are switched
for (int x = 0; x < windowW; x++) {
for (int y = 0; y < windowH; y++) {
if (cells1[x][y]) {
pixels[x * 700 + y] = alive;
int lives = lives(x, y, check);
if (lives<2) {
cells0[x][y] = false;
} else if (lives>4) {
cells0[x][y] = false;
} else {
cells0[x][y] = true;
}
} else {
pixels[x * 700 + y] = dead;
int lives = lives(x, y, check);
if (lives == 3) {
cells0[x][y] = true;
}
}
}
}
}
updatePixels();
}
int lives(int x, int y, boolean check) {//this just checks how many live pixels are around a given pixel
int lives = 0;
if (x > 1 && y >1 && x < 699 && y < 699) {
if (check) {
if (cells0[x-1][y-1])
lives++;
if (cells0[x][y-1])
lives++;
if (cells0[x+1][y-1])
lives++;
if (cells0[x-1][y])
lives++;
if (cells0[x+1][y])
lives++;
if (cells0[x-1][y+1])
lives++;
if (cells0[x][y+1])
lives++;
if (cells0[x+1][y+1])
lives++;
} else {
if (cells1[x-1][y-1])
lives++;
if (cells1[x][y-1])
lives++;
if (cells1[x+1][y-1])
lives++;
if (cells1[x-1][y])
lives++;
if (cells1[x+1][y])
lives++;
if (cells1[x-1][y+1])
lives++;
if (cells1[x][y+1])
lives++;
if (cells1[x+1][y+1])
lives++;
}
}
return lives;
}
Please post your code as an MCVE. When I try to run your code, I get an error because I don't have the font file your'e trying to load on line 59. That font has nothing to do with your problem, so you should really get rid of it before posting a question.
You've got a lot going on in this code. I understand why you have two arrays, but having them both at the sketch level is only over-complicating your code. You shouldn't need to constantly switch between arrays like that. Instead, I would organize your code like this:
You should only have one array at the sketch level. You can also get rid of the zeroOrOne variable.
Initialize that array however you want.
Create a nextGeneration() that returns a new array based on the current array. This will probably call other functions for counting neighbors and whatnot. But the point is that you can just create a new array every time instead of switching between two global arrays.
This removes all of your duplicated logic.
General notes:
Having 8 if statements to check the neighbors is a bit of overkill. Why not just use a nested for loop?
You should get into the habit of following proper naming conventions. Functions should start with a lower-case letter, and variables should be descriptive- naming something check doesn't really tell the reader anything.
If you still can't get it working, then you're going to have to do some debugging. Add print() statements, or use the Processing editor's debugger to step through the code. Which line behaves differently from what you expect? Then you can post an MCVE of just that line (and whatever hard-coded variables it needs to show the behavior) and we'll go from there. Good luck.
The issues you are having are twofold:
The two cells arrays that you have interfere and make two separate games, when you only want one.
You are updating the cells in your arrays before you get to the end of checking which ones need to be modified.
The way to solve both problems at once is to repurpose the cells1 array. Instead of checking it every other time, make it an array set entirely to false. Then, whenever you want to modify a square in cells0, set that location in cells1 to true, and after you make a marker of each cell you want to change, change them all at once with a separate for loop at the end of the drawLoop() method. This solves both problems in one fell swoop.
Once you have done this, you can remove the check and zeroAndOne variables, as you won't need them anymore. This is what I got for the drawLoop() method after I made the modifications I recommend:
void drawLoop() {
loadPixels();
for (int x = 0; x < windowW; x++) {
for (int y = 0; y < windowH; y++) {
if (cells0[x][y]) {
pixels[x * 700 + y] = alive;
int lives = lives(x, y);
if (lives<2) {
cells1[x][y] = true;
} else if (lives>4) {
cells1[x][y] = true;
}
} else {
pixels[x * 700 + y] = dead;
int lives = lives(x, y);
if (lives == 3) {
cells1[x][y] = true;
}
}
}
}
for (int x = 0; x < windowW; x++) {
for (int y = 0; y < windowH; y++) {
if (cells1[x][y]) {
cells0[x][y] = !cells0[x][y];
cells1[x][y] = false;
}
}
}
updatePixels();
}
I'm sure you can figure out the rest. Good luck!
I am developing a game in java just for fun. It is a ball brick breaking game of some sort.
Here is a level, when the ball hits one of the Orange bricks I would like to create a chain reaction to explode all other bricks that are NOT gray(unbreakable) and are within reach of the brick being exploded.
So it would clear out everything in this level without the gray bricks.
I am thinking I should ask the brick that is being exploded for other bricks to the LEFT, RIGHT, UP, and DOWN of that brick then start the same process with those cells.
//NOTE TO SELF: read up on Enums and List
When a explosive cell is hit with the ball it calls the explodeMyAdjecentCells();
//This is in the Cell class
public void explodeMyAdjecentCells() {
exploded = true;
ballGame.breakCell(x, y, imageURL[thickness - 1][0]);
cellBlocks.explodeCell(getX() - getWidth(),getY());
cellBlocks.explodeCell(getX() + getWidth(),getY());
cellBlocks.explodeCell(getX(),getY() - getHeight());
cellBlocks.explodeCell(getX(),getY() + getHeight());
remove();
ballGame.playSound("src\\ballgame\\Sound\\cellBrakes.wav", 100.0f, 0.0f, false, 0.0d);
}
//This is the CellHandler->(CellBlocks)
public void explodeCell(int _X, int _Y) {
for(int c = 0; c < cells.length; c++){
if(cells[c] != null && !cells[c].hasExploded()) {
if(cells[c].getX() == _X && cells[c].getY() == _Y) {
int type = cells[c].getThickness();
if(type != 7 && type != 6 && type != 2) {
cells[c].explodeMyAdjecentCells();
}
}
}
}
}
It successfully removes my all adjacent cells,
But in the explodeMyAdjecentCells() method, I have this line of code
ballGame.breakCell(x, y, imageURL[thickness - 1][0]);
//
This line tells the ParticleHandler to create 25 small images(particles) of the exploded cell.
Tough all my cells are removed the particleHandler do not create particles for all the removed cells.
The problem was solved youst now, its really stupid.
I had set particleHandler to create max 1500 particles. My god how did i not see that!
private int particleCellsMax = 1500;
private int particleCellsMax = 2500;
thx for all the help people, I will upload the source for creating the particles youst for fun if anyone needs it.
The source code for splitting image into parts was taken from:
Kalani's Tech Blog
//Particle Handler
public void breakCell(int _X, int _Y, String URL) {
File file = new File(URL);
try {
FileInputStream fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);
int rows = 5;
int colums = 5;
int parts = rows * colums;
int partWidth = image.getWidth() / colums;
int partHeight = image.getHeight() / rows;
int count = 0;
BufferedImage imgs[] = new BufferedImage[parts];
for(int x = 0; x < colums; x++) {
for(int y = 0; y < rows; y++) {
imgs[count] = new BufferedImage(partWidth, partHeight, image.getType());
Graphics2D g = imgs[count++].createGraphics();
g.drawImage(image, 0, 0, partWidth, partHeight, partWidth * y, partHeight * x, partWidth * y + partWidth, partHeight * x + partHeight, null);
g.dispose();
}
}
int numParts = imgs.length;
int c = 0;
for(int iy = 0; iy < rows; iy ++) {
for(int ix = 0; ix < colums; ix++) {
if(c < numParts) {
Image imagePart = Toolkit.getDefaultToolkit().createImage(imgs[c].getSource());
createCellPart(_X + ((image.getWidth() / colums) * ix), _Y + ((image.getHeight() / rows) * iy), c, imagePart);
c++;
} else {
break;
}
}
}
} catch(IOException io) {}
}
You could consider looking at this in a more OO way, and using 'tell don't ask'. So you would look at having a Brick class, which would know what its colour was, and its adjacent blocks. Then you would tell the first Block to explode, it would then know that if it was Orange (and maybe consider using Enums for this - not just numbers), then it would tell its adjacent Blocks to 'chain react' (or something like that), these blocks would then decide what to do (either explode in the case of an orange block - and call their adjacent blocks, or not in the case of a grey Block.
I know its quite different from what your doing currently, but will give you a better structured program hopefully.
I would imagine a method that would recursively get all touching cells of a similar color.
Then you can operate on that list (of all touching blocks) pretty easily and break all the ones are haven't been broken.
Also note that your getAdjentCell() method has side effects (it does the breaking) which isn't very intuitive based on the name.
// I agree with Matt that color (or type) should probably be an enum,
// or at least a class. int isn't very descriptive
public enum CellType { GRAY, RED, ORANGE }
public class Cell{
....
public final CellType type;
/**
* Recursively find all adjacent cells that have the same type as this one.
*/
public List<Cell> getTouchingSimilarCells() {
List<Cell> result = new ArrayList<Cell>();
result.add(this);
for (Cell c : getAdjecentCells()) {
if (c != null && c.type == this.type) {
result.addAll(c.getTouchingSimilarCells());
}
}
return result;
}
/**
* Get the 4 adjacent cells (above, below, left and right).<br/>
* NOTE: a cell may be null in the list if it does not exist.
*/
public List<Cell> getAdjecentCells() {
List<Cell> result = new ArrayList<Cell>();
result.add(cellBlock(this.getX() + 1, this.getY()));
result.add(cellBlock(this.getX() - 1, this.getY()));
result.add(cellBlock(this.getX(), this.getY() + 1));
result.add(cellBlock(this.getX(), this.getY() - 1));
return result;
}
}
boolean openingboard;
{
Robot robot = new Robot();
Color color3 = new Color(108, 25, 85);
Rectangle rectangle = new Rectangle(0, 0, 1365, 770);
while(true)
{
BufferedImage image = robot.createScreenCapture(rectangle);
search: for(int x = 0; x < rectangle.getWidth(); x++)
{
for(int y = 0; y < rectangle.getHeight(); y++)
{
if(image.getRGB(x, y) == color3.getRGB())
{
System.out.println("About to finish and return true");
return true;
}
System.out.println("About to finish and return false");
}
}
}
}
the error is:
java:71: return outside method
return true
^
i don't know what this is happening please help!
From your comment response above, I am going to make the educated guess that you believe that
boolean openingboard;
{
return true;
}
defines a Java method called openingboard. This isn't the case. Java follows the C paradigm of requiring you to specify your parameters in parentheses, regardless of whether you have any parameters or not. So, the method
boolean openingboard() {
return true;
}
is a valid Java method (assuming it is inside some class), as is a version of openingboard with much more code between the curly braces.
That said, I'm going to pass along a few friendly pointers on Java style:
Java (and indeed most higher-level language) programmers tend to frown on "forever" loops such as while (true), since those loops make it much harder to determine when the loop actually stops.
There is no need for the label search in the code, and labels are even more discouraged than forever loops are.
So, I would recommend rewriting your code to look something like
private boolean openingboard() {
Robot robot = new Robot();
Color color3 = new Color(108, 25, 85);
Rectangle rect = new Rectangle(0, 0, 1365, 770);
BufferedImage image = robot.createScreenCapture(rect);
for(int x = 0; x < rectangle.getWidth(); x++) {
for(int y = 0; y < rectangle.getHeight(); y++) {
if(image.getRGB(x, y) == color3.getRGB())
return true;
}
}
return false;
}
assuming of course that you prefer a debugger to trace prints.
Proper methods look like: boolean openingboard ( )
not like boolean openingboard;
The parenthesis are not optional.
The way you have it: openingboard is a field. There is a init block with a Robot and a color and some for loops nested inside of each other. Inside one of the for loops is a return which is not allowed in an init block.