Array grid with click functions in Processing - grid

I have a grid that is clickable but I am unsure how to proceed with a certain set of rules.
Edit: I rewrote the rules in a more understandable fashion. Very similar to that of the game of life.
Setup
21 cells across / columns
10 cells down / rows
4 base cells vertically aligned in the centre of the board.
Outline cells will surround the base cells.
Every other cell begins as inactive.
Base Cells [2]
Constant and active blue cells in the middle, which cannot be removed.
Active [0] -> [1]
When clicked, an inactive white cell becomes black
if
the edge touches the edge of a base cell
or
the edge touches the edge of another active cell
(either to the left, right, top or bottom – not diagonally.)
else
remain inactive
Inactive [1] -> [0]
When clicked, an active black cell returns to white.
Outline [3]
A series of yellow cells that will constantly update to surround the neighborhood of active cells.
Could anyone help me in achieving this, I would appreciate comments to help me understand the process.
Here is my current code:
int boxsize = 100;
int cols, rows;
color[][] colors;
int saved_i = -1;
int saved_j = -1;
void setup() {
size(1300, 600);
cols = width/boxsize;
rows = height/boxsize;
colors = new color[cols][rows];
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
colors[i][j] = color(255);
}
}
}
void draw() {
background(255);
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
fill(colors[i][j]);
rect(i*boxsize, j*boxsize, boxsize, boxsize);
}
}
}
void mousePressed() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
int x = i*boxsize;
int y = j*boxsize;
if (mouseX > x && mouseX < (x + boxsize) && mouseY > y && mouseY < (y + boxsize)) {
if ( saved_i == -1 || saved_i == i || saved_j == j ) {
colors[i][j] = color(0);
if (j>0) colors[i][j-1]=color(255, 255, 0);
if (j>0) colors[i+1][j-1]=color(255, 255, 0);
if (j<rows-1) colors[i][j+1]=color(255, 255, 0);
if (j<rows-1) colors[i+1][j+1]=color(255, 255, 0);
if (i>0) colors[i-1][j]=color(255, 255, 0);
if (i>0) colors[i-1][j-1]=color(255, 255, 0);
if (i>0) colors[i-1][j+1]=color(255, 255, 0);
if (i<cols-1) colors[i+1][j]=color(255, 255, 0);
saved_i = i;
saved_j = j;
}
}
}
}
}

Your question is pretty broad, so I'll answer in broad terms. You need to figure out four things:
How to represent your cells. In other words, what type of variable you want to store your grid in. You're using colors now, but you probably don't want to do it that way. The way I see it, you have three logical options:
Use a 2D array of enum values. The enum would have states for BASE, ACTIVE, INACTIVE, and OUTLINE. This is probably the correct way to go.
Use a 2D array of ints. 0 for base, 1 for active, 2 for inactive, 3 for outline. Using an enum is probably better, but this is probably easier for a novice to understand.
Use a 2D array of objects. Create a class that represents a cell, and the object would store its state (in either an enum or an int). You would use this approach if you wanted other logic inside each cell, or maybe if you wanted each cell to keep track of its own neighbors.
How to change the state of a single cell on mouse click. You've got logic that deals with colors, now you just have to apply that logic to the data structure you choose in step 1. Maybe create a function that takes mouseX and mouseY and returns the position in the array at that location.
How to get the new state for each cell for the next generation. Create a function that takes the position of one cell (its row and column in the 2D array) and returns the state that the cell should have in the next generation. This is the "meat and potatoes" of your project, and separating it out will help you isolate the logic. Get out a piece of grid paper and draw some examples. If you know the position of a cell, what are the positions of its neighbors? There are a ton of tutorials on the Game of Life out there that will have this logic.
How to update your grid. Remember that you have to do step 2 to every cell in the grid before you update the whole grid. This means that you have to make a new 2D array each iteration.
Break your problem down down like this, and post a new question if you get stuck on a particular step. It's hard to help with general "how do I do this" type questions. It's much easier to help with more specific questions like "I tried X, expected Y, but got Z instead. What am I doing wrong?"
Good luck!

Related

Is there an efficient algorithm for calculating which tiles are within a set walking distance of your character in a 2d grid?

Lets say that on a 2d grid of 20x20, you have your character at position (5,5).
He is able to walk up to 4 tiles in his move. However, there may be obstacles blocking your path such as a wall.
Is there any efficient / easy way for calculating exactly which tiles he would be able to walk to without checking every single possible move ( e.g. move up 0 and right 0 then move up 0 and right 1 e.t.c )?
At the moment I'm calculating the places that you can walk through with this horrific thing:
int playerx = GridPane.getRowIndex(button);
int playery = GridPane.getColumnIndex(button);
int position = playery*8+playerx;
for (int i = 0; i < 5; i++)
{
for (int j = i-4; j < 5-i; j++)
{
try
{
int expectedCollumn = playerx+j;
int actualCollumn = ((position+i+j*8)-((position+i+j*8)%8))/8;
if(expectedCollumn==actualCollumn)
{
Button temp = (Button)gridPane.getChildren()
.get(position+i+j*8);
if (!temp.getText().equals("W") &&
!temp.getText().equals("P"))
{
temp.setText("T");
}
}
actualCollumn = ((position-i+j*8)-((position-i+j*8)%8))/8;
if(expectedCollumn==actualCollumn)
{
Button temp2 = (Button)
gridPane.getChildren().get(position-i+j*8);
if (!temp2.getText().equals("W") &&
!temp2.getText().equals("P"))
{
temp2.setText("T");
}
}
}
}
}
However, its showing as if you are able to walk to the otherside of the wall and I'm not sure how I would go about fixing this.
Many thanks in advance.
For path finding, you should figure out how this works:
https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
and then move on to A* or something more efficient.
Thanks to everyone that answered but the solution was simple
incase somehow someone finds this post and is interested it was a simple recursive call
void getReachableTiles(Tile current, Int stamina, List<Tile> visited, List<Tile> reachable) {
if (stamina <= 0) return;
List<Tile> neighbours = new List<>(current + up, current + left, ..)
for (Tile t in neighbours) {
if (!visited.contains(t)) {
visited.append(t);
if (!t.isWall()) {
reachable.append(t);
getReachableTiles(t, stamina - 1, visited, reachable);
}
}
}
}

Metaballs in Processing as vector

i am trying to create a kind of metaball, nice curves between two circles.
Something like the image, the lines are drawn straight but can also be more curved. I need them as a vector in Processing. Does anyone can help me?
thanks in advance!
Example in paperjs:
http://paperjs.org/examples/meta-balls/
image:
http://www.smeulders.biz/tmp/metaballs.png
void setup() {
size(500,500);
ellipse(100, 250, 100, 100);
ellipse(350, 250, 200, 200);
}
void draw() {}
With a bit of math (to workout distance between circles) and a bit of pixel manipulation to set pixel colours based on these calculated distances, you can render 2D metaballs and there plenty of examples
For fun however I decided to take a stab at making a very hacky version of the example you shared by simply rendering ellipses into an image, then filtering the image at the end:
PGraphics pg;//a separate layer to render into
int dilateAmt = 3;
PImage grid;//pixels of the grid alone, minus the 'cursor'
void setup(){
size(400,400);
//create a new layer
pg = createGraphics(width,height);
pg.beginDraw();
//draw a di-grid inside
pg.background(255);
pg.noStroke();pg.fill(0);
for(int y = 0 ; y < 5; y++)
for(int x = 0 ; x < 5; x++)
pg.ellipse((y%2==0?40:0)+(x * 80),40+(y * 80), 40, 40);
pg.endDraw();
//grab a snapshot for later re-use
grid = pg.get();
}
void draw(){
pg.beginDraw();
//draw the cached grid (no need to loop and re-render circles)
pg.image(grid,0,0);
//and the cursor into the layer
pg.ellipse(mouseX,mouseY,60,60);
pg.endDraw();
//since PGraphics extends PImage, you can filter, so we dilate
for(int i = 0; i < dilateAmt; i++) pg.filter(DILATE);
//finally render the result
image(pg,0,0);
}
void keyPressed(){
if(keyCode == UP) dilateAmt++;
if(keyCode == DOWN) dilateAmt--;
if(dilateAmt < 1) dilateAmt = 1;
println(dilateAmt);
}
Note that the end result is raster, not vector.
If you want to achieve the exact effect you will need to port your example from JavaScript to Java. The source code is available.
If you like Processing the above example you could use plain javascript using p5.js. You'll find most of the familiar functions from Processing, but also directly use the paper.js library.

Javafx gridpane width setting

I need to make some kind of table in which I store simple Region nodes (I will do other stuff on them afterwards - such as megring cells horizontally and giving them other properties, Labels for example) Table will have lots of columns, >200. My goal is to force every grid to have the same width (very important) and to generate that table dynamically.
Here is part of my code that generates that table.
GridPane schedule = new GridPane();
for (int j = 0; j < horizontalGridCount; ++j) {
ColumnConstraints cc = new ColumnConstraints();
cc.setPercentWidth(100/horizontalGridCount);
schedule.getColumnConstraints().add(cc);
}
for (int i = 0; i < verticalGridCount; ++i) {
for (int j = 0; j < horizontalGridCount; ++j) {
final Region grid = new Region();
grid.setStyle("-fx-background-color: #dddddd;");
grid.setPrefHeight(30); // set to make regions visible on screen
grid.setPrefWidth(10); // set to make regions visible on screen
schedule.add(grid, j, i);
}
}
schedule.gridLinesVisibleProperty().set(true);
Here is the output I get on my screen. As you can observe some grids are close-grained then the others
Do you have any idea why it is that wrong and how to fix that?
P.S. It's my first post here, I hope I've done everything right ;)
You are using integer division logic, which rounds things. Use floating point logic instead:
cc.setPercentWidth(100.0/horizontalGridCount);
Note the 100.0 which makes 100.0 (and the division result) a non-integer.
Also don't set the grid lines visible in your target app, that setting is only for debugging (I guess this is why you have it there and set to true, but just a reminder in case):
schedule.gridLinesVisibleProperty().set(true);
If you want borders on your grid cells you can review this demo program.

2D Continuous Collision Detection

I'm trying to implement simple continuous collision detection for my pong game however i'm not sure i'm implementing or understand this right. AFAIR continuous collision detection is used for fast moving objects that may pass through another object circumventing normal collision detection.
So what I tried was that because the only fast moving object I have is a ball I would just need the position of the ball, its move speed, and the position of the object we are comparing to.
From this I figured it would be best that for example if the ball's move speed indicated it was moving left, I would compare it's left-most bound to the right-most bound of the other object. From this I would step through by adding the move speed to the left-most bound of the ball and compare to make sure it's greater than the other objects right bound. This would show that there is no left right collision.
I have something somewhat working, but unfortunately, the ball starts bouncing normally for a while then it acts as if it hits a paddle when nothing is there.
I'm a bit lost, any help would be appreciated!
static bool CheckContinuousCollision(PActor ball, PRect ballRect, PActor other, PRect otherRect)
{
PVector ballMoveSpeed;
int ballXLimit;
int ballYLimit;
ballMoveSpeed = ball.moveSpeed;
// We are moving left
if ( sgn(ball.moveSpeed.x) < 0 )
{
ballXLimit = std.math.abs(ballMoveSpeed.x) / 2;
for ( int i = 0; i <= ballXLimit; i++ )
{
if ( ballRect.Left < otherRect.Right && otherRect.Left < ballRect.Left)
{
return true;
}
ballRect.Left -= i;
}
}
//We are moving right
if ( sgn(ball.moveSpeed.x) > 0)
{
ballXLimit = std.math.abs(ballMoveSpeed.x) / 2;
for ( int i = 0; i < ballXLimit; i ++ )
{
if ( ballRect.Right > otherRect.Left && ballRect.Right < otherRect.Right )
{
return true;
}
ballRect.Right += i;
}
}
// we are not moving
if ( sgn(ball.moveSpeed.x) == 0)
{
return false;
}
}
You seem to be checking the collision of only one dimension, i.e the X dimension of your ball versus your Other.
What you probably want is to compare whether the two objects collide in 2d space. This can be easily done by adjusting each objects Bounding Rectangle and checking whether the rectangles overlap. Then in your for loop you can adjust your Ball rectangle accordingly

CSG operations on implicit surfaces with marching cubes

I render isosurfaces with marching cubes, (or perhaps marching squares as this is 2D) and I want to do set operations like set difference, intersection and union. I thought this was easy to implement, by simply choosing between two vertex scalars from two different implicit surfaces, but it is not.
For my initial testing, I tried with two spheres circles, and the set operation difference. i.e A - B. One circle is moving and the other one is stationary. Here's the approach I tried when picking vertex scalars and when classifying corner vertices as inside or outside. The code is written in C++. OpenGL is used for rendering, but that's not important. Normal rendering without any CSG operations does give the expected result.
void march(const vec2& cmin, //min x and y for the grid cell
const vec2& cmax, //max x and y for the grid cell
std::vector<vec2>& tri,
float iso,
float (*cmp1)(const vec2&), //distance from stationary circle
float (*cmp2)(const vec2&) //distance from moving circle
)
{
unsigned int squareindex = 0;
float scalar[4];
vec2 verts[8];
/* initial setup of the grid cell */
verts[0] = vec2(cmax.x, cmax.y);
verts[2] = vec2(cmin.x, cmax.y);
verts[4] = vec2(cmin.x, cmin.y);
verts[6] = vec2(cmax.x, cmin.y);
float s1,s2;
/**********************************
********For-loop of interest******
*******Set difference between ****
*******two implicit surfaces******
**********************************/
for(int i=0,j=0; i<4; ++i, j+=2){
s1 = cmp1(verts[j]);
s2 = cmp2(verts[j]);
if((s1 < iso)){ //if inside circle1
if((s2 < iso)){ //if inside circle2
scalar[i] = s2; //then set the scalar to the moving circle
} else {
scalar[i] = s1; //only inside circle1
squareindex |= (1<<i); //mark as inside
}
}
else {
scalar[i] = s1; //inside neither circle
}
}
if(squareindex == 0)
return;
/* Usual interpolation between edge points to compute
the new intersection points */
verts[1] = mix(iso, verts[0], verts[2], scalar[0], scalar[1]);
verts[3] = mix(iso, verts[2], verts[4], scalar[1], scalar[2]);
verts[5] = mix(iso, verts[4], verts[6], scalar[2], scalar[3]);
verts[7] = mix(iso, verts[6], verts[0], scalar[3], scalar[0]);
for(int i=0; i<10; ++i){ //10 = maxmimum 3 triangles, + one end token
int index = triTable[squareindex][i]; //look up our indices for triangulation
if(index == -1)
break;
tri.push_back(verts[index]);
}
}
This gives me weird jaggies:
(source: mechcore.net)
It looks like the CSG operation is done without interpolation. It just "discards" the whole triangle. Do I need to interpolate in some other way, or combine the vertex scalar values? I'd love some help with this.
A full testcase can be downloaded HERE
EDIT: Basically, my implementation of marching squares works fine. It is my scalar field which is broken, and I wonder what the correct way would look like. Preferably I'm looking for a general approach to implement the three set operations I discussed above, for the usual primitives (circle, rectangle/square, plane)
EDIT 2: Here are some new images after implementing the answerer's whitepaper:
1.Difference
2.Intersection
3.Union
EDIT 3: I implemented this in 3D too, with proper shading/lighting:
1.Difference between a greater sphere and a smaller sphere
2.Difference between a greater sphere and a smaller sphere in the center, clipped by two planes on both sides, and then union with a sphere in the center.
3.Union between two cylinders.
This is not how you mix the scalar fields. Your scalars say one thing, but your flags whether you are inside or not say another. First merge the fields, then render as if you were doing a single compound object:
for(int i=0,j=0; i<4; ++i, j+=2){
s1 = cmp1(verts[j]);
s2 = cmp2(verts[j]);
s = max(s1, iso-s2); // This is the secret sauce
if(s < iso) { // inside circle1, but not inside circle2
squareindex |= (1<<i);
}
scalar[i] = s;
}
This article might be helpful: Combining CSG modeling with soft blending using
Lipschitz-based implicit surfaces.

Resources