skip to Main Content
//traffic lights:red,yellow,green
    fill(trafficFirstLightColor)
    ellipse(315, 40, 20, 20)
    fill(trafficSecondLightColor)
    ellipse(315, 40 + 25 * 1, 20, 20)
    fill(trafficThirdLightColor)
    ellipse(315, 40 + 25 * 2, 20, 20)


    //if three lights with black, first light on
    x+=10
    if (trafficFirstLightColor === "black" && trafficSecondLightColor === "black" && trafficThirdLightColor === "black" && x == 3000) {
        setTimeout(() => {
            trafficFirstLightColor = 'red';
        }, x)
    } else if (trafficFirstLightColor === "red" && x == 6000) {
        trafficFirstLightColor = "black"
        setTimeout(() => {
            trafficSecondLightColor = 'yellow';
        }, x-3000)
    } else if (trafficSecondLightColor === "yellow" && x == 9000) {
        trafficSecondLightColor = "black"
        setTimeout(() => {
            trafficThirdLightColor = 'green';
        }, x-6000)
    }

I am trying to generate colors every 3 second for a traffic light; however, it failed….

I was initial with three traffic light with black color, and gives them specific varibale as well, I give another variable x to count as a varible in if-else statement, when all of traffic lights are black, the first traffic light become red. Then, when first traffic light became red, the second traffic light become yellow by 3 seconds. Last, the third traffic light become green when the second traffic light became yellow. By the way, plan is great but code is bad.

2

Answers


  1. Assuming this is a p5.js configuration using setup and draw, the draw function is executed up to 30/60 FPS, so you don’t have to manually call setTimeout to trigger the change. Instead you can compare the current millis() with the previous millis() for the time elapsed since last call to draw().

    Here’s an example trying to perform the traffic light animation using p5.js without the use of setTimeout:

    let trafficFirstLightColor = 'black';
    let trafficSecondLightColor = 'black';
    let trafficThirdLightColor = 'black';
    let start;
    
    function setup() {
      createCanvas(400, 400);
      trafficFirstLightColor = 'black';
      trafficSecondLightColor = 'black';
      trafficThirdLightColor = 'black';
      start = millis();
    }
    
    function draw() {
      fill(trafficFirstLightColor);
      ellipse(315, 40, 20, 20);
      fill(trafficSecondLightColor);
      ellipse(315, 40 + 25 * 1, 20, 20);
      fill(trafficThirdLightColor);
      ellipse(315, 40 + 25 * 2, 20, 20);
      
      const now = millis();
      const cycle = now - start;
      
      if (cycle < 3000) {
        if (trafficFirstLightColor === 'black' &&
        trafficSecondLightColor === 'black' &&
        trafficThirdLightColor === 'black') {
          trafficFirstLightColor = 'red';
          return;
        }
      } else if (cycle < 6000) {
        if (trafficFirstLightColor === 'red') {
          trafficFirstLightColor = 'black';
          trafficSecondLightColor = 'yellow';
          return;
        }
      } else if (cycle < 9000) {
        if (trafficSecondLightColor === 'yellow') {
          trafficSecondLightColor = 'black';
          trafficThirdLightColor = 'green';
          return;
        }
      }
    }
    
    Login or Signup to reply.
  2. Whenever you’re working with multiple values, use a data structure rather than thing1, thing2, thing3…. In this case, we can create an array that holds 3 objects containing color and duration properties, then cycle the array or use an index to step through the lights as we render them.

    const lights = [
      {
        color: "green",
        duration: 10_000,
      },
      {
        color: "yellow",
        duration: 3_000,
      },
      {
        color: "red",
        duration: 10_000,
      },
    ];
    
    function setup() {
      createCanvas(50, 50);
      noStroke();
      noLoop();
      renderLights();
    }
    
    const renderLights = () => {
      const {duration, color} = lights[0];
      fill(color);
      ellipse(width / 2, height / 2, width, height);
      setTimeout(renderLights, duration);
      lights.push(lights.shift());
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

    Not only does the code generalize well (you can add and remove lights at will), but by separating configuration and implementation logic, it becomes easier to adjust the durations without risking messing something up in the code.

    If your canvas is cleared on every frame in draw, you can separate light cycling from drawing:

    const lights = [
      {
        color: "green",
        duration: 10_000,
      },
      {
        color: "yellow",
        duration: 3_000,
      },
      {
        color: "red",
        duration: 10_000,
      },
    ];
    
    function setup() {
      createCanvas(50, 50);
      noStroke();
      runLightCycle();
    }
    
    function draw() {
      background(0);
      renderCurrentLight();
    }
    
    const renderCurrentLight = () => {
      fill(lights[0].color);
      ellipse(width / 2, height / 2, width, height);
    };
    
    const runLightCycle = () => {
      setTimeout(() => {
        lights.push(lights.shift());
        runLightCycle();
      }, lights[0].duration);
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

    Keep in mind setTimeout is a rough estimate, not a precise duration, so this will drift over time.

    If you want to avoid drift, you can keep track of the time of the last light change, then repeatedly check the elapsed milliseconds that have elapsed since the last light change. When it exceeds the current light duration, increment the last change time by the duration and repeat.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search