Creating a clickable grid in Processing 3 - java

I'm trying to make a grid of squares that change their fill (from black to white and vice-versa) when clicked. I'm able to turn the entire grid on or off currently, but I'm unable to figure out how to specify which particular square should be toggled when the mouse clicks within its borders. I've created buttons using mouseX and mouseY coordinates before, but they were for specific objects that I could adjust manually. I can't figure out how to do this using for loops and arrays.
I've been told to create a boolean array and pass the value of that array to the grid array, but again, I don't know how to specify which part of the array it needs to go to. For example, how do I change the fill value of square [6][3] upon mousePressed?
Here is my code so far:
int size = 100;
int cols = 8;
int rows = 5;
boolean light = false;
int a;
int b;
void setup() {
size (800, 600);
background (0);
}
void draw() {
}
void mousePressed() {
light = !light;
int[][] box = new int[cols][rows];
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
box[i][j] = i;
int a = i*100;
int b = j*100;
if (light == true) {
fill(255);
} else {
fill(0);
}
rect(a, b, 100, 100);
println(i, j);
}
}
}

First of all, you are currently recreating the entire board whenever the mouse is pressed. You must retain that info between mouse clicks, so make box a global array up there with the others. Further, it's sufficient to make it a boolean array if all you care about is the on/off state of each square:
boolean[][] isSquareLight = new boolean[cols][rows];
Instead of
if (light == true) {
you should then just check
if (isSquareLight[i][j] == true) {
(note that the == true is redundant).
Now, you've already written code that finds the coordinates for each box: You're passing it to rect!
rect(a, b, 100, 100);
All that is left to do is check whether the mouse is inside this rect, i.e. whether mouseX is between a and a+100 (and similar for mouseY) - if that's the case, then the user clicked in the box given by the current (i, j), so you can just negate isSquareLight[i][j] (before checking it like above) and it will work.
There are ways to calculate this without looping through the entire grid every time, but maybe the above helps you find the path yourself instead of just getting the code made for you.
PS: The int a; int b; at the top does nothing and can be removed. You are using the local variables a and b in your function, which is correct.

Related

processing: trouble using global array in if condition in for loop

I am trying to write a small program that has a given number of balls (in the example code below it's 3) travel back and forth across the screen at different speeds and phases (start offset).
This much has been achieved in the code. Although I want to be able to select the balls (one at a time) using a mouse click.
I have used the word "HIT!!!" to signify in the console that a ball has been clicked.
My problem is that when I run the code below, I only get a "HIT!" in the console when I click the top ball. That is when the first element y[0] matches with the click_Y variable. When I am sure (but obviously mistaken somehow) that there should be matches when I click in the vicinity of y[1] & y[2].
I'd really be grateful for any help with these. As it's gotten to the point where I am starting to stare blankly at the screen. Thanks.
int noCircles; // the number of items in the array (# of circles)
float[] y; // y-position of each circle (fixed)
float[] speed; // speed of each circle
float[] phase; // phase of each circle
float red = 120;
float green = 120;
float blue = 120;
float click_X;
float click_Y;
void setup() {
size(500, 500);
noCircles = 3;
// allocate space for each array
y = new float[noCircles];
speed = new float[noCircles];
phase = new float[noCircles];
// calculate the vertical gap between each circle based on the total number
// of circles
float gap = height / (noCircles + 1);
//setup an initial value for each item in the array
for (int i=0; i<noCircles; i++) {
y[i] = gap * (i + 1);
// y is constant for each so can be calculated once
speed[i] = random(10);
phase[i] = random(TWO_PI);
}
}
void draw() {
background(155);
for (int i=0; i<noCircles; i++) {
// calculate the x-position of each ball based on the speed, phase and
//current frame
float x = width/2 + sin(radians(frameCount*speed[i] ) + phase[i])* 200;
if (dist(x, y[i], click_X, click_Y) <= 20){
println("HIT!!!!!!!!!!!!!!!!!!");
}
ellipse(x, y[i], 20, 20);
click_X = 0;
click_Y = 0;
}
}
void mousePressed() {
println("You clicked******************************************");
click_X = mouseX;
click_Y = mouseY;
println("click_X =" + click_X);
println("click_Y =" + click_Y);
}
Problems like these are best solved by debugging your program. Start by tracing through the code by hand, then add print statements (more than you've already added), and if that doesn't work then don't be afraid to use the debugger.
You're using the click_X and click_Y variables to check the position of the mouse against the position of each ball. Trace through the for loop in your draw() function. What happens at the end of the first iteration?
You reset the values of click_X and click_Y. That's why you aren't detecting any hits on the other circles.
You could probably refactor your code to only reset those variables if something has been hit, but really, I would stop using them altogether.
I'm guessing that you're using those variables because you only want to check when the mouse is pressed? Just use the mousePressed variable for that. Then you can use the mouseX and mouseY variables directly.
Then your if statement would look like this:
if (mousePressed && dist(x, y[i], mouseX, mouseY) <= 20) {
println("HIT: " + i);
}
Also, using separate arrays like this is called parallel arrays, and is general a bad habit to get into. You should probably use classes instead.

Webcam Pixel Manipulation/Sorting via Processing

I am attempting to write a Processing sketch that will take each row's center pixel's color and apply that color to the entire row. However, I am having trouble with even getting the pixels to change. It seems like the sketch doesn't even go through the for-loops where I am trying to change the pixels because it doesn't print out any of the statements except the end draw at the end of draw(). I just end up with an unmanipulated feed. Does anyone know why this isn't working?
Also, currently using Processing's standard Video library with Capture at the moment, but if there is a better library that I could utilize please let me know! Thanks!
UPDATE: Testing out my algorithm with an array of numbers, it seems like using an inner for loop isn't working like how I thought it should. The i of the outer-loop is only incremented once after the first time the inner for loop completes itself, and then it just exits the outer loop instead of starting the inner loop again. What's going on here?
import processing.video.*;
Capture feed; // webcam
int pixelCount = width * height; // total # of pixels
int center = width / 2; // value for center pixel
int widthPlus = width + 1; // value to go row-to-row
color c; // center pixel color
void setup(){
size(displayWidth, displayHeight);
feed = new Capture(this);
feed.start();
}
void draw(){
if (feed.available() == true){
feed.read();
}
image(feed, 0, 0);
feed.loadPixels(); // load pixels from webcam
/** Use to look at each row one at a time*/
for (int i = 0; i < pixelCount; i+=widthPlus){
println("Outer for-loop");
c = feed.pixels[i + center]; //get center pixel
/** Make each pixel in row the color of 'c' */
for (int j = i; j < width; j++){
println("Inner for-loop");
feed.pixels[j] = c; // set pixel to 'c'
println(i + " - " + j);
}
}
feed.updatePixels(); // update pixels from webcam
println("end draw");
}

Java Arrays - Different values for the same object

Using Slick2D I am looping through my buttons and highlighting the one that is currently being hovered over. I do this by saving the index of a button whose onHover event fires. However, when I hover over the first button, it highlights the last. Hovering over the second button highlights the second to last, etc. If I use the keyboard to change the selected button it works perfectly, though.
Here is the method to save the index :
public void onHover(int x, int y) {
Button but;
for (int i = 0; i < b.size(); i++) {
but = b.get(i);
if (but.isClicked(x, y)) {
choice = i;
return;
}
}
}
And the one to compare them :
public void draw(Graphics g) {
Button but;
for (int i = 0; i < b.size(); i++) {
but = b.get(i);
if (i == choice) {
but.drawHighlighted(g);
} else {
but.draw(g);
}
}
}
Is there a special way to do this?
EDIT : I figured out where the problem was.
Mouse.getY() from LWJGL (which i use with onHover method) returns the height of the window minus the Y position of the mouse ; while mouseReleased(button, x, y) from Slick2D (which i use with draw method) returns the "true" Y position.
But both returns the same value with the x position.
I still don't know why the values are different (since Slick2D is based on LWJGL), but to bypass the problem, i use now HEIGHT - Mouse.getY() to have the right position.
Thanks everbody for helping me with that problem !

Update object position before rendering in Java?

The problem I'm having is with my render loop. My application is a series of 'Tile' objects each with an x and y coordinate and image. When the program starts it creates a 10x10 grid of these tiles on screen. However, not all the squares can be seen at the same time, so you can use the arrow keys to pan around them. When the key is pressed it uses a for loop to cycle through all the currently rendered tile (stored in an ArrayList) and shifts them all 16 in the appropriate direction. The problem is some of the tiles flicker. I can see when scrolling that one half of the screen doesn't move in time to be rendered in the right spot, making a black gap between that and the other half of the tiles. how do I ensure that all tiles are moved before rendering?
render function from my Core class
public static void render()
{
while(true)
{
Graphics g = buffer.getDrawGraphics();
try
{
g.setColor(Color.black);
g.fillRect(0, 0, 1280, 720);
if(renderQueue != null)
{
for(int i = 0; i<renderQueue.size(); i++)
{
Tile t = renderQueue.get(i);
g.drawImage(t.getImage(), t.getX(), t.getY(), null);
}
}
if(!buffer.contentsLost())
{
buffer.show();
}
}
finally
{
if(g != null)
{
g.dispose();
}
}
}
}
And here's the movement update function from the Input class
public void keyPressed(KeyEvent ke)
{
int e = ke.getKeyCode();
switch(e)
{
case 38://up
if(scrollY > 0)
{
scrollY -= 16;
for(int i = 0; i<Core.renderQueue.size(); i++)
{
Core.renderQueue.get(i).incrementY(16);
}
}
break;
case 40://down
if(scrollY < 560)
{
scrollY += 16;
for(int i = 0; i<Core.renderQueue.size(); i++)
{
Core.renderQueue.get(i).incrementY(-16);
}
}
break;
case 37://right
if(scrollX < 0)
{
scrollX += 16;
for(int i = 0; i<Core.renderQueue.size(); i++)
{
Core.renderQueue.get(i).incrementX(16);
}
}
break;
case 39://left
if(scrollX > 0)
{
scrollX -= 16;
for(int i = 0; i<Core.renderQueue.size(); i++)
{
Core.renderQueue.get(i).incrementX(-16);
}
}
break;
}
Thanks in advance!
It sounds like the tiles are being rendered while the coordinates for some of the tiles still have to be changed by Input.keyPressed. You could fix that by directly using scrollX and scrollY to draw the tile images in Core.render, instead of changing the coordinates for each of the tiles. If you copy the scroll values to two local variables at the begin of the while loop in render, the same values will be used for each tile.
Another option is to create a new list with tiles that have the modified coordinates (you could use the images from the current list). When the new list is complete, you could set a flag like newRenderQueue which will be picked up in render. When a new iteration of the while loop in render starts, you can replace the render queue with the new list and reset the flag.
P.S. Welcome to Stack Overflow! As Andrew Thompson already mentioned, it's very helpful to provide a complete example of your problem. This way people can quickly investigate the issue and provide (hopefully useful) advice... ;-)

if/then with pixel finding and looping, all of which is above me at the moment

I want to take a screenshot, and if the pixel is the correct value RGB then take another screenshot and find next pixel or else repeat.
this is the code to get the pixel and it works like a charm!
{
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())
{
break search;
}
}
}
}
what i want to know i guess is how would i go about asking it to repeat this segment of code until the pixel equals the true color. the color i am looking for is:
Color color3 = new Color(114, 46, 33);
Ok context, i am building a program that goes through steps, one opens the given puzzle, i have that down because i can use simple pixel data, then it needs to center the mouse on the center pixel. The problem is i cant just use a second get pixel image because it takes a while for the game to open the relevant jpanel so i need my program to wait until it can find a pixel indicating the game is open before it starts to look for the pixel to center the mouse.
You can probably separate the screenshot code into a method and call it until you get the desired result:
public boolean checkColor(Color inputColor) {
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 true;
}
}
}
return false;
}
This method will return true if it can find the given inputColor in the screenshot. You might then use it in a loop as follows:
Color newColor = ...;
while (!checkColor(newColor)) {
new Color = new Color(114, 46, 33);
// Or change color in here for every iteration
}
This loop will terminate if it can't match the screenshot to newColor.

Categories

Resources