Search code examples
animationfor-loopprocessingeasing

Processing: How can I make multiple elements in a for() loop move to one location then return?


I have a grid of ellipses generated by two for() loops. What I'd like to do is have all of these ellipses ease into mouseX and mouseY when mousePressed == true, otherwise return to their position in the grid. How can I go about this? I've started with this template, which doesn't work as I can't figure out how affect the position of the ellipses, but the easing is set up.

float x;
float y;
float easeIn = 0.01;
float easeOut = 0.08;
float targetX;
float targetY;

void setup() {
  size(700, 700);
  pixelDensity(2);
  background(255);
  noStroke();
}

void draw() {
  fill(255, 255, 255, 80);
  rect(0, 0, width, height);

  for (int i = 50; i < width-50; i += 30) {
    for (int j = 50; j < height-50; j += 30) {

      fill(0, 0, 0);
      ellipse(i, j, 5, 5);

      if (mousePressed == true) {

        // go to mouseX
        targetX = mouseX; 
        // ease in
        float dx = targetX - x;
        if (abs(dx) > 1) {
          x += dx * easeIn;
        }

        //go to mouseY
        targetY = mouseY;
        // ease in
        float dy = targetY - y;
        if (abs(dy) > 1) {
          y += dy * easeIn;
        }
      } else {

        // return to grid
        targetX = i;
        // ease out
        float dx = targetX - x;
        if (abs(dx) > 1) {
          x += dx * easeOut;
        }

        // return to grid
        targetY = j;
        // ease out
        float dy = targetY - y;
        if (abs(dy) > 1) {
          y += dy * easeOut;
        }
      }
    }
  }
}

Any help would be greatly appreciated. I'm not sure in which order to do things/which elements should be contained in the loop.

Thanks!


Solution

  • You're going to have to keep track of a few things for each dot: its "home" position, its current position,its speed, etc.

    The easiest way to do this would be to create a class that encapsulates all of that information for a single dot. Then you'd just need an ArrayList of instances of the class, and iterate over them to update or draw them.

    Here's an example:

    ArrayList<Dot> dots = new ArrayList<Dot>();
    
    void setup() {
      size(700, 700);
      background(255);
      noStroke();
    
      //create your Dots
      for (int i = 50; i < width-50; i += 30) {
        for (int j = 50; j < height-50; j += 30) {
          dots.add(new Dot(i, j));
        }
      }
    }
    
    void draw() {
      background(255);
    
      //iterate over your Dots and move and draw each
      for (Dot dot : dots) {
        dot.stepAndRender();
      }
    }
    
    class Dot {
    
      //the point to return to when the mouse is not pressed
      float homeX;
      float homeY;
    
      //current position
      float currentX;
      float currentY;
    
      public Dot(float homeX, float homeY) {
        this.homeX = homeX;
        this.homeY = homeY;
        currentX = homeX;
        currentY = homeY;
      }
    
      void stepAndRender() {
    
        if (mousePressed) {
          //use a weighted average to chase the mouse
          //you could use whatever logic you want here
          currentX = (mouseX+currentX*99)/100;
          currentY = (mouseY+currentY*99)/100;
        } else {
          //use a weighted average to return home
          //you could use whatever logic you want here
          currentX = (homeX+currentX*99)/100;
          currentY = (homeY+currentY*99)/100;
        }
    
        //draw the ellipse
        fill(0, 0, 0);
        ellipse(currentX, currentY, 5, 5);
      }
    }
    

    Note that I'm just using a weighted average to determine the position of each ellipse, but you could change that to whatever you want. You could give each ellipse a different speed, or use your easing logic, whatever. But the idea is the same: encapsulate everything you need into a class, and then put the logic for one dot into that class.

    I'd recommend getting this working for a single dot first, and then moving up to getting it working with multiple dots. Then if you have another question you can post the code for just a single dot instead of a bunch. Good luck.