I am trying to create a Grid class to arrange elements the screen on rows and cols. The methods cellXCenter() and cellYCenter() are supposed to return the coordinates for a given i cell on the grid.
When running this code, which is supposed to draw an ellipse inside each grid cell, only the last element is given the correct coordinates.
What I am doing wrong?
Grid grid;
int columns = 3;
int rows = 2;
void setup() {
size(900,600);
background(0);
grid = new Grid(columns,rows);
fill(255,0,0);
for (int i = 0 ; i < columns * rows; i++) {
ellipse(grid.cellXCenter(i+1),grid.cellYCenter(i+1),100,100);
}
}
class Grid {
//grid width, height, number of columns, number of rows
int gw;
int gh;
int cols;
int rows;
int cells; //total de celdas desde 1
float cellWidth;
float cellHeight;
Grid(int cols_, int rows_) {
gw = width;
gh = height;
cols = cols_;
rows = rows_;
cells = rows * cols;
cellWidth = gw / cols;
cellHeight = gh / rows;
}
int rowPos(int index_) {
//all index arguments one based
float i = index_;
int position = (int)Math.ceil(i/cols);
return position;
}
int colPos(int index_) {
int i = index_;
int position = i - (cols * (rowPos(i) -1));
return position;
}
float cellX(int index_) {
int i = index_;
float xPos = gw * (colPos(i)/cols);
return xPos;
}
float cellXCenter(int index_) {
int i = index_;
float xCenterPos = cellX(i) - cellWidth/2;
return xCenterPos;
}
float cellY(int index_) {
int i = index_;
float yPos = gh * (rowPos(i)/rows);
return yPos;
}
float cellYCenter(int index_) {
int i = index_;
float yCenterPos = cellY(i) - cellHeight/2;
return yCenterPos;
}
}
You need to do some debugging. I'd start out by printing out the position of every cell:
for (int i = 0 ; i < columns * rows; i++) {
println(grid.cellXCenter(i+1) + ", " + grid.cellYCenter(i+1));
ellipse(grid.cellXCenter(i+1),grid.cellYCenter(i+1),10,10);
}
This prints out:
-150.0, -150.0
-150.0, -150.0
750.0, -150.0
-150.0, 450.0
-150.0, 450.0
750.0, 450.0
So you can see that all but one of your cells have negative coordinates, which cause them to be drawn off the edges of the window.
Now you need to keep debugging to figure out why these values are negative. Add more print statements to see exactly what's going on in your code, and find the line that's not behaving how you expect.
When you get it narrowed down to just a few lines that aren't behaving how you expect, then you can post a more specific question along with an MCVE. Good luck.
Related
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 ++;
}
}
}
I am going to develop an app where I draw rectangles with this method:
private int columnWidth = 1;
private int rowHeight = 1;
private int nbColumns = 1;
private int nbRows = 1;
public static final int DEFAULT_SIZE = 150;
private void initWorld() {
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point point = new Point();
display.getSize(point);
// we calculate the number of columns and rows for our World
nbColumns = point.x / DEFAULT_SIZE;
nbRows = point.y / DEFAULT_SIZE;
// we calculate the column width and row height
columnWidth = point.x / nbColumns;
rowHeight = point.y / nbRows;
world = new World(nbColumns, nbRows);
}
// Method to draw each cell of the world on the canvas
private void drawCells(Canvas canvas) {
for (int i = 0; i < nbColumns; i++) {
for (int j = 0; j < nbRows; j++) {
Cell cell = world.get(i, j);
r.set((cell.x * columnWidth) - 1, (cell.y * rowHeight) - 1,
(cell.x * columnWidth + columnWidth) - 1,
(cell.y * rowHeight + rowHeight) - 1);
// we change the color according the alive status of the cell
p.setColor(cell.alive ? DEFAULT_ALIVE_COLOR : DEFAULT_DEAD_COLOR);
canvas.drawRect(r, p);
}
}
}
Can anyone tell me, how could I get some space or lines between the rectangles?
I have a grid, grid is and 2-demension array of Cell object.
public class Cell
{
int x;
int y;
ArrayList<Cell> nighbors=new ArrayList<Cell>();
public void addNeighbor(Cell cell)
{
this.neighbors.add(cell);
}
}
Every cell have 8 neighbors:
And also, one more, field is looped, like on the picture below:
So the neighbors for Cell(0,1) are also cells (5,0), (5,1), (5,2).
Now I fill neigbors like that:
public void addNeigbors(int x, int y)
{
Cell curentCell=grid[x][y];
if(x==0)
{
if(y==0)
{
curentCell.addNiegbor(this.cells[this.width-1][this.height-1]);
curentCell.addNiegbor(this.cells[x][this.height-1]);
curentCell.addNiegbor(this.cells[x+1][this.height-1]);
curentCell.addNiegbor(this.cells[x+1][y]);
curentCell.addNiegbor(this.cells[x+1][y+1]);
curentCell.addNiegbor(this.cells[x][y+1]);
curentCell.addNiegbor(this.cells[this.width-1][y+1]);
curentCell.addNiegbor(this.cells[this.width-1][y]);
}
else if(y==this.height-1)
{
// similar code
}
else
{
// and so on
}
}
// and so on
}
This code make my cry but I have no idea to make it better.
What can you advise me?
Storing references to each neighbor in Cell is a waste. IF cells need to access their neighbors, then put a reference to the grid array in each cell, and let cell calculate its neighbor indexes on the fly when necessary.
You could add a method like this:
Cell getNeighbor(int dx, int dy)
{
int w = grid.length;
int h = grid[x].length;
return grid[(x+w+dx)%w][(y+h+dy)%h];
}
If a cell needs to iterate through all of its neighbors, you can do it like this:
for (int dy=-1;dy<=1;++dy) {
for(int dx=-1;dx<=1;++dx) {
if (dx!=0 || dy!=0) {
processNeighbor(getNeighbor(dx,dy));
}
}
}
Something like this :
public void addNeigbors(int x, int y)
{
Cell curentCell=grid[x][y];
int xp1 = (x+1)%width;
int xm1 = (x-1+width)%width;
int yp1 = (y+1)%height;
int ym1 = (y-1+height)%height;
curentCell.addNiegbor(this.cells[xp1][y]);
curentCell.addNiegbor(this.cells[xp1][yp1]);
curentCell.addNiegbor(this.cells[xp1][ym1]);
curentCell.addNiegbor(this.cells[x][yp1]);
curentCell.addNiegbor(this.cells[x][ym1]);
curentCell.addNiegbor(this.cells[xm1][y]);
curentCell.addNiegbor(this.cells[xm1][yp1]);
curentCell.addNiegbor(this.cells[xm1][ym1]);
}
Create an (static) array that conains the x/y delta for all 8 neighbors so you can loop through it an add the delta to your cells x/y coordinates to get the neighbor coordinates and use mod -> % to deal with the borders:
public class Cell {
int x;
int y;
private static int delta[][] = {{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1}};
ArrayList < Cell > neighbors = new ArrayList < Cell > ();
public void addNeighbors() {
for (int i = 0; i < delta.length; i++) {
this.neighbors.add(this.cells
[Math.floorMod(this.x + delta[i][0], width)]
[Math.floorMod(this.y + delta[i][1], height)]
);
}
}
}
Loop over possible variations on x (dx) and y (dy), avoid the special case dx = dy = 0 and use mod to wrap around the grid.
public void addNeigbors(int x, int y) {
for(int dx = -1; dx <= 1; dx++) {
for(int dy = -1; dy <= 1; dy++) {
if(dx != 0 || dy != 0) {
int nx = Math.floorMod(x + dx, this.width);
int ny = Math.floorMod(y + dy, this.height);
this.cells[x][y].addNeighbors(this.cells[nx][ny]);
}
}
}
}
Hey if i have a simple rectangle class, how can i make it so that it creates that rectangle next to each other in a grid like pattern? maybe like 10 rows 10 columns?
public class Vak {
private int posX = 0;
private int posY = 0;
private int width = 50;
private int height = 50;
private Color colour;
public Vak(Color c, int x, int y){
this.colour = c;
this.posX = x;
this.posY = y;
}
public int vakPosY(){
return this.posY;
}
public int vakPosX(){
return this.posX;
}
public void draw (Graphics g){
g.setColor(this.colour);
g.drawRect(posX, posY, width, height);
}
public void move(int numberPixelsX, int numberPixelsY){
this.posX = this.posX + numberPixelsX;
this.posY = this.posY + numberPixelsY;
}
}
this is my code for rectangle "vak"
Is this what you are looking for?
int mapWidth = 10;
int mapHeight = 10;
// tileWidth and tileHeight should probably be public static const fields or static readonly properties of some class, but I put them here for now.
int tileWidth = 50; // Pixels
int tileHeight = 50; // Pixels
// tiles should probably be a field of a Map class (if you have one)
Vak[][] tiles = new Vak[mapWidth][mapHeight];
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++)
{
tiles[x][y] = new Vak(Color.white, x*tileWidth, y*tileHeight);
}
}
And then in the drawing part of the main loop:
for(Vak[] row : tiles)
{
for(Vak tile : row)
{
tile.draw(g);
}
}
This is a homework assignment.
Work 19 5/16 is the assignment
http://sites.stuycs.org/home/courses/ml2x/dyrland-weaver/work
I am running this in the program processing, which does not require main methods.
Blob was given to us. We had to make BlobRunner on our own.
Any advice on why my code isn't doing what its supposed to would be appreciated.
FIRST FILE BlobRunner
int popSize = 4;
int wobble = 2;
int numSides = 4;
float rad = 100;
int radInt = (int) rad;
float a = sqrt(popSize);
int rootPop = (int) a;
Blob[][] blobs = new Blob[popSize/rootPop][rootPop];
/*=====================================
The trickiest part of setup is to make
the screen an appropriate size for the
grid of blobs. The grid should be just
big enough to contain all of the blobs.
====================================*/
void setup() {
size ((popSize/rootPop)*(2*(radInt+3)), rootPop*(2*(radInt+3)));
populate();
}
/*=====================================
The main purpose of draw is to go through
the array of blobs and display each.
====================================*/
void draw() {
int createdSoFar = 0;
for (int i = 0; i<rootPop; i++){
for (int j = 0; j<popSize/rootPop; j++){
if (createdSoFar < popSize){
blobs[j][i].display();
}
createdSoFar++;
}
}
}
/*=====================================
Populate the array of blobs.
You can use any values for radius, number of sides
and wobble factor that you'd like, but you must
use x and y coordinates that ensure the blobs
are drawn in a grid without overlaping each other.
Your code should work for any reasonable value
of population (i.e. something that would fit on a
normal monitor).
====================================*/
void populate() {
for (int i = 0; i < rootPop; i++){
float y = 1;
for (int j = 0; j < (popSize/rootPop); j++){
float x = 1;
blobs[j][i] = new Blob (x*(rad+3), y*(rad+3), numSides, radInt, wobble, wobble);
x=x+2;}
y=y+2;}
}
SECOND FILE Blob
/*=====================================
A Blob object is a regular polygon variant that
can have various features.
Instance Variables:
numSides: number of sides
rad: distance from the center of the polygon
to any vertext
x: x coordinate of the center
y: y coordinate of the center
xFactor: "wobble" foctor in the x direction
yFactor: "wobble" factor in the y direction
====================================*/
class Blob {
int numSides;
int rad;
float x;
float y;
int xFactor;
int yFactor;
Blob(float cx, float cy, int sides, int r, int xf, int yf ) {
x = cx;
y = cy;
numSides = sides;
rad = r;
xFactor = xf;
yFactor = yf;
}
void display() {
float nx;
float ny;
int rx, ry;
float sy;
strokeWeight(1);
beginShape();
for( float t = 0; t <= 1; t+=( 1.0/numSides ) ) {
/*
"wobble" effect is created by adding a random number to each
x and y coordinate. The larger the x and y factors, the higher
the possible wobble value could be
*/
rx = (int)random(xFactor);
ry = (int)random(yFactor);
nx = rad * cos( 2 * PI * t ) + x + rx;
ny = rad * sin( 2 * PI * t ) + y + ry;
vertex(nx, ny);
}
endShape();
}
}
Your code runs, thus it is doing what you asked it to do and nothing more.
I asked my cat to check it out though and she was all, "the guy is re-initializing his variables inside each pass of the loop, he'll never get a grid of blobs that way. Tell him to start by moving float y = 1; float x = 1; in populate() outside of the bounds of the two for loops and start debugging from there."
Then she rolled over on to her side and I patted her.