Trying to use multiple instances of Mouse pressed - processing

I’m trying to add a feature where you can click on different parts of the sketch and have an image randomly generated. It worked for the first time, but when I add another if mouse pressed function, it triggers all the mouse pressed code and all of the sets of images go off at the same time. I’m not sure how to isolate it so that just one goes off if it’s in the right spot.
Here is my code for the last attempt, I tried to isolate the mouse pressed function with a push and pop Matrix, which didn’t work.
PImage stage;
PImage model;
PImage [] hat = new PImage [5];
PImage [] pants = new PImage [4];
PImage [] shirt = new PImage [5];
int choice = 0;
int page = 0;
void setup() {
size (800, 800);
stage = loadImage("background.png");
background(255);
image(stage, 0, 0);
hat[0] = loadImage ("hat1.png");
hat[1] = loadImage ("hat2.png");
hat[2] = loadImage ("hat3.png");
hat[3] = loadImage ("hat4.png");
pants[0] = loadImage ("pant1.png");
pants[1] = loadImage ("pant2.png");
pants[2] = loadImage ("pant3.png");
pants[3] = loadImage ("pant4.png");
}
void draw() {
println(mouseX, mouseY); //398, 237 for hats.
image(stage, 0, 0);
pushMatrix();
if (dist(398, 237, mouseX, mouseY) <90 && mousePressed) choice = floor(random(4));
image(hat[choice], 349, 98);
popMatrix();
pushMatrix();
if (dist(404, 363, mouseX, mouseY) <90 && mousePressed) choice = floor(random(4));
image(pants[choice], 228, 263);
popMatrix();
}

The issue is that you're using the same variable for all the clothing items. So when you click on the hat button, it sets choice to a random number (let's say 2). Then you display hat[choice] and then you also display pants[choice]. One way around this is to have multiple different choice variables, hatChoice and pantsChoice. When you click on the hat button, it randomizes hatChoice, and when you click on the pants button, it randomizes pantsChoice. Something like this:
if (dist(398, 237, mouseX, mouseY) <90 && mousePressed) hatChoice = floor(random(4));
image(hat[hatChoice], 349, 98);
if (dist(404, 363, mouseX, mouseY) <90 && mousePressed) pantsChoice = floor(random(4));
image(pants[pantsChoice], 228, 263);
I also second #rjw1428's recommendation of using mouseClicked() instead of if (mousePressed). You can do something like this:
//your global variables...
int hatChoice = 0;
int pantsChoice = 0;
void setup() {
//your setup stuff...
}
void draw() {
image(stage, 0, 0);
image(hat[hatChoice], 349, 98);
image(pants[pantsChoice], 228, 263);
}
void mouseClicked() {
if (dist(mouseX, mouseY, 398, 237) < 90) {
hatChoice = floor(random(4));
}
if (dist(mouseX, mouseY, 404, 363) < 90) {
pantsChoice = floor(random(4));
}
}

This isn't a perfect solution, but to implement what you're trying to do, i might do this
PImage stage;
PImage model;
PImage [] hat = new PImage [5];
PImage [] pants = new PImage [4];
PImage [] shirt = new PImage [5];
int selectedHat = -1;
int selectedPants = -1;
int selectedShirt = -1;
int choice = 0;
int page = 0;
void setup(){
size (800,800);
stage = loadImage("background.png");
background(255);
image(stage,0,0);
initializeImages()
}
void draw(){
println(mouseX, mouseY); //398, 237 for hats.
image(stage,0,0);
if (selectedHat > 0) {
image(hat[selectedHat], 349,98);
}
if (selectedPants > 0) {
image(pants[choice], 228,263);
}
}
void mouseClicked() {
if(dist(404,363, mouseX, mouseY) <90 && mousePressed) {
selectedPants = floor(random(4));
}
if(dist(398,237, mouseX, mouseY) <90 && mousePressed) {
selectedHat = floor(random(4));
}
}
void initializeImages() {
hat[0] = loadImage ("hat1.png");
hat[1] = loadImage ("hat2.png");
hat[2] = loadImage ("hat3.png");
hat[3] = loadImage ("hat4.png");
pants[0] = loadImage ("pant1.png");
pants[1] = loadImage ("pant2.png");
pants[2] = loadImage ("pant3.png");
pants[3] = loadImage ("pant4.png");
}
Then if you wanted to clear, have an IF check for the location (button) that you want to select to clear, and your function could return all the 'selected' values back to -1

Related

drawing on screen after region clicked processing

I'm trying to make it so that when the user clicks the pencil icon in the program they are allowed to draw until the pencil has been clicked again. ive not added in a toggle yet but my current problem is that i get the desired behaviour in the mouse region which i specified but nowhere else on the screen, also please excuse my code its devolved a lot while playing with it, however by running it in its currrent state you should see what bug im talking about.
thanks
PImage[] img = new PImage[3];
boolean drawPencil = false;
boolean draw = false;
void setup() {
size(960, 720);
for (int i = 0; i < img.length; i++)
img[i] = loadImage("image"+i+".png");
//an array of images that sorts and load them into our program
image(img[0],0,0);
img[0].resize(width, height);
// set the desired image to screen size
}
void mousePressed() {
if (mouseX > 772 && mouseX < 864 && mouseY > 1 && mouseY < 74) {
drawPencil = true;
draw = true;
// if the user clicks the pencil icon they will begin to draw
}
}
void mouseReleased()
{
draw = false;
}
void draw() {
if (draw) {
stroke(255);
line(mouseX, mouseY, pmouseX, pmouseY);
}
if (key == 'w'||key == 'W') {
image(img[0],0,0);
img[0].resize(width, height);
println(drawPencil);
}
}
Way better post than the last. I think I now get what you want. I coded you a short example so you can get the hang of it. Here's what it will do:
PImage img;
boolean canDraw;
void setup() {
size(960, 720);
background(255);
img = loadImage("pencil.png");
}
void draw() {
if (canDraw) {
fill(color(0, 128, 0));
} else {
fill(color(128, 0, 0));
}
rect(800, 1, 100, 100);
image(img, 800, 1, 100, 100);
if (canDraw && mousePressed) {
stroke(0);
line(mouseX, mouseY, pmouseX, pmouseY);
}
}
void mouseClicked() {
if (mouseX > 800 && mouseX < 800+img.width && mouseY > 1 && mouseY < 1+img.height) {
canDraw = !canDraw;
}
}
I'll hang around in case you want to ask questions about this. Have fun!

Overlapping issue in P3D when rotating

I'd like to rotate a cube in P3D and my code uses live sensor data to do that.
The problem is the previous orientations of the cube are always visible and overlap (as you can see in this image: http://i.stack.imgur.com/txXw6.jpg), which I don't want. I already tried the functions "hint(DISABLE_OPTIMIZED_STROKE)" and "hint(ENABLE_DEPTH_TEST)", which did nothing. Besides the hint functions I found nothing on a similar issue.
How can I render ONLY the current orientation?
import processing.serial.*;
import toxi.geom.*;
Serial myPort;
float qW;
float qX;
float qY;
float qZ;
float[] axis = new float[4];
Quaternion quat = new Quaternion(1, 0, 0, 0);
void setup()
{
size(600, 400, P3D);
myPort = new Serial(this, "COM3", 9600);
background(0);
lights();
}
void draw()
{
serialEvent();
quat.set(qW, qX, qY, qZ);
axis = quat.toAxisAngle();
pushMatrix();
translate(width/2, height/2, -100);
rotate(axis[0], axis[1], axis[2], axis[3]);
noFill();
stroke(255);
box(330, 200, 40);
popMatrix();
}
void serialEvent()
{
int newLine = 13; // new line character in ASCII
String message;
do
{
message = myPort.readStringUntil(newLine); // read from port until new line
if (message != null)
{
String[] list = split(trim(message), " ");
if (list.length >= 4)
{
qW = float(list[0]);
qX = float(list[1]);
qY = float(list[2]);
qZ = float(list[3]);
}
}
} while (message != null);
}
It looks like you're not clearing the frame buffer. Try adding background(0); as the first line in draw();:
void draw()
{
//clear background
background(0);
serialEvent();
quat.set(qW, qX, qY, qZ);
axis = quat.toAxisAngle();
pushMatrix();
translate(width/2, height/2, -100);
rotate(axis[0], axis[1], axis[2], axis[3]);
noFill();
stroke(255);
box(330, 200, 40);
popMatrix();
}
Off topic, it might worth checking out serialEvent().
You could do something like this in setup()
myPort = new Serial(this, "COM3", 9600);
myPort.bufferUntil('\n');
you shouldn't need to call serialEvent() in draw(), the serial library will do that, as it's buffering.
Then in serialEvent() hopefully you can get away with just:
String message = myPort.readString();
if(message !=null){
String[] list = split(trim(message), " ");
if (list.length >= 4)
{
qW = float(list[0]);
qX = float(list[1]);
qY = float(list[2]);
qZ = float(list[3]);
}
}

Traffic Light sequence in Processing

I am trying to get this bit of code I have got and add another traffic light and car but going from right to left not from bottom to top. The car only moves when the light is amber or green and stops when red. I have tried copying the code and changing the names of the values but it just will not work. I have tried naming them all different names but it won't even show the other image I tried to put in for the other car. Can someone please tell/show me how I could add another traffic light and car but they move at different times?
TrafficLight light1 = new TrafficLight(100, 40);
int onTime = 2000;
int startTime = millis();
PImage car;
int carX, carY;
void setup() {
size(800, 600);
light1.changeColour("red");
light1.display();
car = loadImage("Car.png");
carX = 150;
carY = 300;
}
void draw() {
background(255);
if (millis() - startTime > onTime && light1.lightOn == "red") {
light1.changeColour("amber");
startTime = millis();
}
if (millis() - startTime > onTime && light1.lightOn == "amber") {
light1.changeColour("green");
startTime = millis();
}
if (millis() - startTime > onTime && light1.lightOn == "green") {
light1.changeColour("red");
startTime = millis();
}
light1.display();
image(car, carX, carY);
if (light1.lightOn == "green") {
carY -= 2;
}
{
}
if (light1.lightOn == "red") {
carY -= 0;
}
{
}
if (light1.lightOn == "amber") {
carY -= 1;
}
{
}
if (carY <= -200) {
carY = 500;
}
}
class TrafficLight {
int xpos;
int ypos;
String lightOn = "red";
TrafficLight(int x, int y) {
xpos = x;
ypos = y;
}
void changeColour(String lightColour) {
lightOn = lightColour;
}
void display() {
String lightColour = lightOn;
fill(0, 0, 0);
rect(xpos, ypos, 100, 220);//back panel
if (lightColour == "red") {
fill(255, 0, 0);
lightOn = "red";
} else {
fill(100, 0, 0);
}
ellipse(xpos + 50, ypos + 40, 60, 60);//red
if (lightColour == "amber") {
fill(255, 255, 0);
lightOn = "amber";
} else {
fill(100, 100, 0);
}
ellipse(xpos + 50, ypos + 110, 60, 60);//amber
if (lightColour == "green") {
fill(0, 255, 0);
lightOn = "green";
} else {
fill(0, 100, 0);
}
ellipse(xpos + 50, ypos + 180, 60, 60);//green
}
}
The code you've posted only contains one car, which makes this question hard to answer. Stack Overflow isn't really designed for general "how do I do this" type questions. It's more designed for specific "I tried X, expected Y, but got Z instead" type questions. That being said, I'll try to answer in a general sense:
Here's the short answer: you need to create a state for a second car, and then work with that state exactly how you work with the state of the first car. This might be easier if you encapsulate that state into a class, and then use two instances of that class.
Let's start out with a simpler example of a circle that moves vertically, and stops when we press the mouse:
MovingCircle verticalCircle;
void setup() {
size(600, 600);
verticalCircle = new MovingCircle(250, 250, 0, 5);
}
void mousePressed() {
verticalCircle.moving = !verticalCircle.moving;
}
void draw() {
background(0);
verticalCircle.step();
}
class MovingCircle {
float x;
float y;
float xSpeed;
float ySpeed;
boolean moving = true;
public MovingCircle(float x, float y, float xSpeed, float ySpeed) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
}
void step() {
if (moving) {
x+=xSpeed;
y+=ySpeed;
if (x > width) {
x = 0;
}
if (y > height) {
y = 0;
}
}
ellipse(x, y, 25, 25);
}
}
This program creates a circle that moves down the screen, and stops and starts when you click the mouse. Notice that I've encapsulated all of the information I need inside the MovingCircle class, so now if I want to add another one, I can just create another instance of that class and interact with it however I want.
Here's how I would add a horizontally moving circle:
MovingCircle verticalCircle;
MovingCircle horizontalCircle;
void setup() {
size(600, 600);
verticalCircle = new MovingCircle(250, 250, 0, 5);
horizontalCircle = new MovingCircle(250, 250, 5, 0);
}
void mousePressed() {
verticalCircle.moving = !verticalCircle.moving;
}
void keyPressed() {
horizontalCircle.moving = !horizontalCircle.moving;
}
void draw() {
background(0);
verticalCircle.step();
horizontalCircle.step();
}
This is just an example, but the principle is the same in your code: you need to encapsulate your state into a class, and then you can work with two instances of that class in order to have two moving cars.
Also, you should never use == to compare String values! Use the .equals() function instead!
if(lightColour.equals("red")){

Clearing out canvas

I'm trying to program an intro. I want the canvas to erase itself after it. I already have the trigger, but I do not know how to clear the canvas. Would just changing the background work? I still want to make stuff after it.
Here is the code:
void setup () {
frameRate(10);
stroke(255, 255, 255);
noFill();
rect(100,155,300,300);
size(500, 500);
}
void square () {
for (int x = 100; x <= 300; x += 100) {
for (int y = 155; y <= 355; y += 100) {
fill(random(0, 255), random(0, 255), random(0, 255));
rect(x, y,100,100);
}
}
};
void draw () {
int time = 0;
int logoLength = 100;
if (time < logoLength) {
fill(255, 255, 255);
background(0, 0, 0);
textFont(createFont("Lucida console", 19));
textAlign(CENTER,CENTER);
text("Ghost Cube Games presents",250,59);
time++;
print(time);
square();
} else if (time == logoLength) {
background(255, 255, 255);
}
}
You can simply call the background() function.
background(0); draws a black background.
background(255); draws a white background.
background(255, 0, 0); draws a red background.
More info can be found in the reference.
For a more specific example, if you want to show an intro screen, you can simply keep track of whether the intro screen is showing in a boolean variable. If that variable is true, then draw the intro screen. If not, then draw whatever else you want to draw. If you do this from the draw() function, then you don't really have to worry about clearing the screen, since calling the background() function will do that for you:
boolean showingIntro = true;
void draw() {
background(0);
if (showingIntro) {
text("INTRO", 20, 20);
} else {
ellipse(50, 50, 25, 25);
}
}
void mouseClicked() {
showingIntro = false;
}

Stop background from refreshing?

I am trying to get my gif to do something similar to this gif.
I have been able to get the line to draw, and the 'planets' to orbit, but can't figure out how to keep the line connecting the two circles, like the gif does.
Here's the basic code:
int x = 500;
int y = 500;
int radius = y/2;
int cX = x/2;
int cY = y/2;
String text1;
int lg_xBall;
int lg_yBall;
int sm_xBall;
int sm_yBall;
void setup() {
size(x, y);
smooth();
colorMode(RGB);
}
void draw() {
background(0);
stroke(255);
float t = millis()/1000.0f;
drawSmBallOrbit(100);
drawLgBallOrbit(100);
moveSmBall(t);
moveLgBall(t);
sun();
// showMouse();
connectingLines();
}
void drawCircle() { // This will draw a simple circle
stroke(1);
// x1=a+r*cos t, y1=b+r*sin t
ellipse(x/2, y/2, x/2, y/2);
}
void drawLines() { // This will draw lines from the center of the circle.
stroke(1);
line(x/2, y/2, radius/2, radius); // line from 6 to center
line(x/2, y/2, x/2, y/4); // line from 12 to center
for (int i = 0; i <= 5; i+=2.5) {
float x1 = x/2+radius/2*cos(i);
float y1 = y/2+radius/2*sin(i);
line(x/2, y/2, x1, y1);
}
}
void moveSmBall(float ky) { // This will create, and move, a small 'planet'
pushStyle();
stroke(100);
sm_xBall = (int)(cX+radius*cos(ky));
sm_yBall = (int)(cY+radius*sin(ky));
fill(190, 0, 0);
// background(0);
ellipse(sm_xBall, sm_yBall, 10, 10);
popStyle();
}
void drawSmBallOrbit(float opacity) {
pushStyle();
stroke(255, opacity);
strokeWeight(1);
noFill();
ellipse(x/2, y/2, cX+radius, cY+radius);
popStyle();
}
void moveLgBall(float kx) {
kx = kx/.7;
pushStyle();
lg_xBall = (int)(cX+radius*cos(kx)*.6);
lg_yBall = (int)(cY+radius*sin(kx)*.6);
fill(0, 0, 230);
ellipse(lg_xBall, lg_yBall, 30, 30);
popStyle();
}
void drawLgBallOrbit(float opacity) {
pushStyle();
stroke(255, opacity);
strokeWeight(1);
noFill();
ellipse(x/2, y/2, (cX+radius)*.6, (cY+radius)*.6);
popStyle();
}
void sun() {
pushStyle();
fill(250, 250, 0);
ellipse(cX, cY, 40, 40);
popStyle();
}
void connectingLines() {
line(sm_xBall, sm_yBall, lg_xBall, lg_yBall);
}
void showMouse() {
text("X: " + mouseX, x/2, y/2-30);
text("Y: " + mouseY, x/2, y/2-50);
}
Thanks for any help/advice!
The problem is that you're calling background() during every frame, which will clear away anything you've already drawn.
So you either need to stop calling background(), or you need to redraw the old lines every frame.
If you simply move the call to background() out of your draw() function and into your setup() function, you're about 50% there already:
void setup() {
size(x, y);
smooth();
colorMode(RGB);
background(0);
}
void draw() {
// background(0);
stroke(255);
float t = millis()/1000.0f;
drawSmBallOrbit(100);
drawLgBallOrbit(100);
moveSmBall(t);
moveLgBall(t);
sun();
// showMouse();
connectingLines();
}
However, the original animation does not show the previous positions of the ellipses. So you need to clear away the previous frame by calling the background() function, and then redraw previous line positions. You'd do that by having an ArrayList that holds those previous positions.
Here's a simple example that uses an ArrayList to redraw anywhere the mouse has been:
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size(500, 500);
}
void draw() {
background(0);
stroke(255);
points.add(new PVector(mouseX, mouseY));
for(PVector p : points){
ellipse(p.x, p.y, 10, 10);
}
}
You would need to do something very similar, but you'd have to keep track of two points at a time instead of one, since you're tracking two ellipses and not just the mouse position.

Resources