javascriptp5.jsrectangles

How can I simplify this code with for loop?


How can I change this code with for loop, so that I can create more bigger rectangles with same functions? When I use for loop, when I point to the smaller rectangle, the bigger rectangle will also change color. I can't make it exclusive to the rectangle I am pointing at. Thankss.

let rectX = 200;
let rectY = 200;

let rect1Width = 80;
let rect1Height = 80;

let rect2Width = 40;
let rect2Height = 40;

let isMouseOverRect1 = false;
let isMouseOverRect2 = false;
let rect1 = false;
let rect2 = false;

function setup() {
  createCanvas(400, 400);
  rectMode(CENTER);
}

function draw() {
  background(200);

  if (
    mouseX > rectX - rect1Width / 2 &&
    mouseX < rectX + rect1Width / 2 &&
    mouseY > rectY - rect1Height / 2 &&
    mouseY < rectY + rect1Height / 2
  ) {
    isMouseOverRect1 = true;
    rect1 = true;
  } else {
    isMouseOverRect1 = false;
    rect1 = false;
  }

  if (
    mouseX > rectX - rect2Width / 2 &&
    mouseX < rectX + rect2Width / 2 &&
    mouseY > rectY - rect2Height / 2 &&
    mouseY < rectY + rect2Height / 2
  ) {
    isMouseOverRect2 = true;
    rect2 = true;
  } else {
    isMouseOverRect2 = false;
    rect2 = false;
  }

  if (isMouseOverRect1 && !rect2) {
    fill(0);
  } else {
    fill(255);
  }
  rect(rectX, rectY, rect1Width, rect1Height);

  if (isMouseOverRect2 && rect1) {
    fill(0);
  } else {
    fill(255);
  }
  rect(rectX, rectY, rect2Width, rect2Height);
}

Drawing with for loop with same function.


Solution

  • You can encapsulate reusable functionalities, for example:

    There are multiple ways to implement this depending on your level of comfort. For example you could do something this:

    let rect1 = {x:160, y:160, w:80, h:80}
    let rect2 = {x:180, y:180, w:40, h:40};
    
    function setup() {
      createCanvas(400, 400);
    }
    
    function draw() {
      background(200);
      
      let isOver1 = isOverRectangle(mouseX, mouseY, rect1);
      let isOver2 = isOverRectangle(mouseX, mouseY, rect2);
      
      fill(isOver1 && !isOver2 ? 0 : 255);
      drawRectangle(rect1);
      fill(isOver2 ? 0 : 255);
      drawRectangle(rect2);
    }
    
    function isOverRectangle(mx, my, rectangle){
      return (mx >= rectangle.x && mx <= (rectangle.x + rectangle.w)) && 
             (my >= rectangle.y && my <= (rectangle.y + rectangle.h));
    }
    
    function drawRectangle(r){
      rect(r.x, r.y, r.w, r.h);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>

    Alternatively you could define a class:

    class Rect{
      
      constructor(x, y, w, h){
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
      }
      
      draw(){
        rect(this.x, this.y, this.w, this.h);
      }
      
      isOver(mx, my){
        return (mx >= this.x && mx <= (this.x + this.w)) && 
               (my >= this.y && my <= (this.y + this.h));
      }
      
    }
    
    let rect1 = new Rect(160, 160, 80, 80);
    let rect2 = new Rect(180, 180, 40, 40);
    
    function setup() {
      createCanvas(400, 400);
    }
    
    function draw() {
      background(200);
      
      let isOver1 = rect1.isOver(mouseX, mouseY);
      let isOver2 = rect2.isOver(mouseX, mouseY);
      
      fill(isOver1 && !isOver2 ? 0 : 255);
      rect1.draw();
      fill(isOver2 ? 0 : 255);
      rect2.draw();
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>

    For two rectangles you might not need a for loop, however if you do choose to encapsulation will make this a bit easier now. It will be a fun challenge for yourself, especially working out the logic to check which boxes to ignore and take into account to change the fill color. Have fun!