Traffic Light sequence in Processing - 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")){

Related

in Processing, how to hover over mouse to make numbers of rectangles change color?

I've finished a single rectangle code, but I'd like to know ways to make at least four rectangles change color while hovering the mouse over them. Any advice is much appreciated.
code is below:
int rectX, rectY;
int rectSize = 90;
color rectColor;
color baseColor;
boolean rectOver = false;
void setup() {
size(640, 360);
rectColor = color(0);
baseColor = color(102);
rectX = width/2;
rectY = height/2;
rectMode(CENTER);
}
void draw() {
update(mouseX, mouseY);
noStroke();
if (rectOver) {
rectColor = color(255);
}else
{
rectColor = color(0);
}
stroke(255);
fill(rectColor);
rect(rectX, rectY, rectSize, rectSize);
}
void update(int x, int y) {
if ( overRect(rectX, rectY, rectSize, rectSize) ) {
rectOver = true;}
else{rectOver = false;}
}
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x-width/2 && mouseX <= x+width/2 &&
mouseY >= y-height/2 && mouseY <= y+height/2) {
return true;
}
else {
return false;
}
}
First of all, you have to fix your overRect function since width and height are built-in variables, secondly what you need to do is to declare a rectangle class that will contain the x,y, width and height of your rectangle, plus two methods: one to check if the mouse if hovering (using your old method) and one to self draw the rectangle. Lastly, you need an array to store your rectangles. Here is the final code:
int rectX, rectY;
int rectSize = 90;
color rectColor;
color baseColor;
ArrayList<rectangle> list;
boolean rectOver = false;
class rectangle {
float x,y,w,h;
rectangle (float y, float x,float w, float h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
boolean checkInside() {
return overRect(x,y,w,h);
}
void selfDraw(){
if (this.checkInside()) {
rectColor = color(255);
}else
{
rectColor = color(0);
}
stroke(255);
fill(rectColor);
rect(x, y, w, h);
}
}
void setup() {
size(640, 360);
rectMode(CENTER);
list= new ArrayList<rectangle>();
list.add(new rectangle(40,40,50,60));
list.add(new rectangle(20,200,50,20));
list.add(new rectangle(300,200,50,50));
list.add(new rectangle(200,300,80,60));
}
void draw() {
for (int i = 0; i < list.size(); i++) {
list.get(i).selfDraw();
}
}
boolean overRect(float x, float y, float w, float h) {
if (mouseX >= x-w/2 && mouseX <= x+w/2 &&
mouseY >= y-h/2 && mouseY <= y+h/2) {
return true;
}
else {
return false;
}
}
Use inheritence. As in YOUSFI's answer, your nest net would be to build a rectangle class and write it's own mouse over function in there. Then, you can make an instance of that object in your main program and call it's mouseover function.
Instead of blindly copy pasting the code YOUSFI provided, my suggestion would be to read up on Object Oriented Programming or watch this introductory video series: https://www.youtube.com/watch?v=xG2Vbnv0wvg

How to use custom shapes in a repeating loop pattern?

I already made a custom shape (myFunction), and I also made patterns using simpler shapes. I want to know how to replace those simple shapes with my custom shape while maintaining the pattern drawn on processing...
You're already calling functions such as noFill(), noStroke(), etc.
It's the same for your function: call it by simply using it's name and () (because it has no arguments): myFunction();
Let's say you want to draw it in pattern 1, you could do something like:
if (pattern==1) {
for (int x=50; x<width; x+=100) {
for (int y=20; y<height; y+=100) {
myFunction();
}
}
}
You will need to pay attention to rendering though.
Running the above will not display anything you call in noFill() in myFunction() and also noStroke() in draw(), right after background(): you won't be able to see a shape with no fill and no stroke :)
One suggestion is to add a stroke:
void myFunction() {
noFill();
stroke(255);
ellipse(300, 300, 200, 400);
ellipse(300, 300, 400, 200);
translate(300, 300);
rotate(radians(130));
ellipse(0, 0, 200, 400);
translate(0, 0);
rotate(radians(0));
ellipse(0, 0, 400, 200);
}
Of course feel free to experiment and make this look nicer.
Here's a modified version of your sketch that uses a few key presses to change the pattern type and shape type at runtime:
int pattern = 1;
// 0 = pluseEllipseCluser, 1 = blobs, 2= myFunction spirograph circles
int shape = 0;
void setup() {
size(600, 600);
println("press 1,2 to change pattern");
println("press p/b/c to change shapes");
}
void draw() {
background(30);
noStroke();
if (pattern==1) {
for (int x=50; x<width; x+=100) {
for (int y=20; y<height; y+=100) {
drawSelectedShapes(x, y);
}
}
}
if (pattern==2) {
float rando = random(10, 90);
for (float x= rando; x >= 0; x-=random(2.5)) {
for (float y= rando; y >= 0; y-=random(2.5)) {
drawSelectedShapes(x, y);
}
}
}
}
void drawSelectedShapes(float x, float y){
if(shape == 0){
plusEllipseCluser(x, y);
}
if(shape == 1){
blobs();
}
if(shape == 2){
myFunction();
}
}
void plusEllipseCluser(float x, float y){
fill(random(255), random(255), random(255), random(255));
ellipse(x, y+30, 50, 20); //plus ellipse cluster
ellipse(x, y+30, 20, 50);
}
void blobs(){
noStroke();
fill(random(250), random(120), random(100));
ellipse(random(width), random(height), 20, 50);
noFill();
stroke(random(255));
ellipse(random(width), random(height), 50, 20);
}
void myFunction() {
noFill();
stroke(255);
ellipse(300, 300, 200, 400);
ellipse(300, 300, 400, 200);
translate(300, 300);
rotate(radians(130));
ellipse(0, 0, 200, 400);
translate(0, 0);
rotate(radians(0));
ellipse(0, 0, 400, 200);
}
void keyPressed(){
if(key == '1') {
pattern = 1;
}
if(key == '2') {
pattern = 2;
}
if(key == 'p'){
shape = 0;
}
if(key == 'b'){
shape = 1;
}
if(key == 'c'){
shape = 2;
}
}
Notice that the example above also calls plusEllipseCluser() passing two arguments: it's a basic example of defining and calling a function that takes two arguments. Of course you've already called functions with arguments before (e.g. random(min,max), ellipse(x,y,w,h), etc.)
Have fun with shapes and patterns.

Carousel of three ellipses in Processing

I am trying to create a vertical carousel in processing with three ellipses.
I am able to get this done with two ellipses – that the carousel repeats itself over and over.
So far so good – it thought I could use the same logic for three but I am wrong. I started to think it works with more variables but wrong again… what am I missing in the logic? I really can not figure out how to set the values to make it seamless repeating itself…
Here is the example with two (this one is "seamless"):
float yspeed = 5;
float circleY;
int d = 720;
void setup() {
size(1080, 1620 );
circleY = 0;
}
void draw() {
background(255);
fill(0);
noStroke();
ellipse(width/2, circleY+height/2, d,d);
ellipse(width/2, circleY-height/2, d,d );
circleY = circleY + yspeed;
if (circleY > height) {
circleY=0;}
}
Here is my WIP with three … (BTW colors are only to see better):
float yspeed1 = 5;
float yspeed2 = 5;
float yspeed3 = 5;
float circleY1;
float circleY2;
float circleY3;
int d = 720;
void setup() {
size(1080, 1620);
circleY1 = 0;
circleY2 = 0;
circleY3 = 0;
}
void draw() {
background(255);
noStroke();
fill(255, 0, 0);
ellipse(width/2, circleY1, d, d);
circleY1= circleY1 + yspeed1;
if (circleY1 > height+d/2 ) {
circleY1=0;
}
fill(0, 255, 0);
ellipse(width/2, circleY2-810, d, d);
circleY2= circleY2 + yspeed2;
if (circleY2 > height+d/2 ) {
circleY2=0 ;
}
fill(0, 0, 255);
ellipse(width/2, circleY2-1620, d, d);
circleY3= circleY3 + yspeed3;
if (circleY3 > height+d/2 ) {
circleY3=0 ;
}
}
The one with three always starts at the intital point for all of them – but I thought that using individual variables would change it?
Thank you for any kind of help!
I found a solution myself! I used a trick – I did it with a loop and used four instead of three – three is in the end the only ones you see anyway!
float yspeed = 1;
float circleY;
int d = 360;
void setup() {
size(540, 810 );
circleY = 0;
}
void draw() {
background(255);
fill(0);
noStroke();
// fill(255,0,0);
translate(0, - height/2);
for (int i = 0; i< 5; i++) {
ellipse(width/2, circleY+height/2*i, d, d);
}
circleY = circleY + yspeed;
if (circleY > 405) {
circleY= 0;
}
}

Making particles move around the object smoother

i was able to make particles go around the ellipse I created which was my previous question. Now I have another one, flow of the particles are not as smooth as i want, there is this diagonal looking shape they follow and when you move the mouse (the ellipse) you can see my lines of my "force" variable. Again I want particles to move like water floating around a rock in a river.
Link for the previous question I asked about same project
int NUM_PARTICLES = 9000;
ParticleSystem p;
Rock r;
void setup()
{
smooth();
size(700,700,P2D);
p = new ParticleSystem();
r = new Rock();
}
void draw()
{
background(0);
p.update();
p.render();
r.rock();
}
float speed = 2;
float rad = 100;
class Particle
{
PVector position, velocity;
float initialPosY;
Particle()
{
position = new PVector(random(width), random(height));
initialPosY = position.y;
velocity = new PVector();
}
void update()
{
velocity.x = speed;
velocity.y = 0;
float d = dist (position.x, position.y, mouseX, mouseY);
if (d < rad) {
float force = map(d, 0, rad, speed, 0);
if (position.x < mouseX) {
if (position.y < mouseY) {
velocity.y = -force;
} else {
velocity.y = force;
}
} else {
if (position.y < mouseY) {
velocity.y = force;
} else {
velocity.y = -force;
}
}
position.add(velocity);
} else {
position = new PVector(position.x+speed, initialPosY);
}
if (position.x<0)position.x+=width;
if (position.x>width)position.x-=width;
if (position.y<0)position.y+=height;
if (position.y>height)position.y-=height;
}
void render()
{
stroke(255, 255, 255, 80);
point(position.x, position.y);
}
}
class ParticleSystem
{
Particle[] particles;
ParticleSystem()
{
particles = new Particle[NUM_PARTICLES];
for (int i = 0; i < NUM_PARTICLES; i++)
{
particles[i]= new Particle();
}
}
void update()
{
for (int i = 0; i < NUM_PARTICLES; i++)
{
particles[i].update();
}
}
void render()
{
for (int i = 0; i < NUM_PARTICLES; i++)
{
particles[i].render();
}
}
}
class Rock{
void rock()
{
noFill();
stroke(255);
strokeWeight(4);
ellipse(mouseX,mouseY,50,50);
}
}
It'll be a lot easier if you try to narrow your problem down to a smaller MCVE, like I did in the answer to your first question:
PVector position;
PVector speed;
void setup() {
size(500, 500);
position = new PVector(250, 0);
speed = new PVector(0, 1);
}
void draw() {
background(0);
if (dist(position.x, position.y, mouseX, mouseY) < 100) {
fill(255, 0, 0);
if (position.x < mouseX) {
position.x--;
} else {
position.x++;
}
} else {
fill(0, 255, 0);
}
ellipse(mouseX, mouseY, 100, 100);
fill(0, 0, 255);
ellipse(position.x, position.y, 20, 20);
position.add(speed);
if (position.y > height) {
position.y = 0;
}
if (position.x < 0) {
position.x = width;
} else if (position.x > width) {
position.x = 0;
}
}
Now that we have that, we can talk about how we might improve it.
Right now, our logic for having the particles avoid our obstacle is here:
if (dist(position.x, position.y, mouseX, mouseY) < 100) {
if (position.x < mouseX) {
position.x--;
} else {
position.x++;
}
}
Notice that we're always moving the particle by 1 pixel, which is why it looks blocky. What we need to do is smooth our transition out by moving the pixel only a little bit at first, and then moving it more as it gets closer to the obstacle.
You might user the lerp() or map() function for this, but for this simple example, we can simply use the dist() function.
Here is a super simple approach you might take:
float distance = dist(position.x, position.y, mouseX, mouseY);
if (position.x < mouseX) {
position.x -= 1000/(distance*distance);
} else {
position.x += 1000/(distance*distance);
}
Notice that by squaring the distance, I'm setting up a polynomical interpolation. In other words, the particle moves faster the closer it gets to the center of the boundary.
Again, you're going to have to play with this to get the exact effect you're looking for, but the basic idea is there: what you're looking for is an interpolation (how fast the particle moves) that scales with the distance from the boundary. You can use squaring to exaggerate the effect.
You could also use basic trig to make the particle follow a circular path.

Dragging the mouse outside of a clickable area

I'm trying to code a slider from scratch and I've got a basic functionality, but I'd like to be able to drag the sliders beyond the bounds I created for clicking on it.
void slide()
{
if ((x+w >= mouseX) && (mouseX >= x) && (y+h >= mouseY) && (mouseY >= y) &&
(mousePressed == true))
{
h = (mouseY - y);
}
As you can see when the mouse is dragged outside of the slider dimensions, the height value no longer changes. How can I activate only within the dimensions then drag outside of them?
I have done this trough a boolean to control the click and lock, like:
class Test {
//global
float x;
float y;
float w, h;
float initialY;
boolean lock = false;
//constructors
//default
Test () {
}
Test (float _x, float _y, float _w, float _h) {
x=_x;
y=_y;
initialY = y;
w=_w;
h=_h;
}
void run() {
float lowerY = height - h - initialY;
float value = map(y, initialY, lowerY, 100, 255);
color c = color(value);
fill(c);
rect(x, initialY, 4, lowerY);
fill(200);
rect(x, y, w, h);
float my = constrain(mouseY, initialY, height - h - initialY );
if (lock) y = my;
}
boolean isOver()
{
return (x+w >= mouseX) && (mouseX >= x) && (y+h >= mouseY) && (mouseY >= y);
}
}
//end of class
Test[] instances = new Test[3];
void setup() {
size(200, 600);
noStroke();
instances[0] = new Test(20, 20, 40, 20);
instances[1] = new Test(80, 20, 40, 20);
instances[2] = new Test(140, 20, 40, 20);
}
void draw() {
background(100);
for (Test t:instances)
t.run();
}
void mousePressed() {
for (Test t:instances)
{
if (t.isOver())
t.lock = true;
}
}
void mouseReleased() {
for (Test t:instances)
{
t.lock = false;
}
}

Resources