Multiple Groups

back

Notes

The object will follow where you point.

Because of the following logic is self-contained in the Follower class, you can have as many different Followers or groups of Followers as you need. In this example, a second group of Followers is added that targets a flag moving around the stage.

Source

/* @pjs preload="player.png, flag.png"; */

PImage player;
PImage flag;

float flag_x, new_flag_x;
float flag_y, new_flag_y;

Follower[] followers;
Follower[] flagFollowers;
int NUMBER_OF_FOLLOWERS = 10;

// Setup the example
void setup(){
  size(640, 480);
  
  imageMode(CENTER);
  
  // Load images
  player = loadImage("player.png");
  flag = loadImage("flag.png");
  flag_x = width/2;
  flag_y = height/2;
  
  // Create 5 followers, each one following the one ahead of it
  // The first one will follow the mouse pointer
  followers = new Follower[NUMBER_OF_FOLLOWERS];
  Follower lastFollower = null;
  for(int i = 0; i < followers.length; i++){
    followers[i] = new Follower(player, width/2 + i * 32, height/2, lastFollower);
    lastFollower = followers[i];
  }
  
  // Create 5 more followers, each one following the one ahead of it
  // The first one will follow the target
  lastFollower = null;
  flagFollowers = new Follower[NUMBER_OF_FOLLOWERS];
  for(int i = 0; i < flagFollowers.length; i++){
    flagFollowers[i] = new Follower(player, width/2 + i * 32, height/2, lastFollower);
    lastFollower = flagFollowers[i];
  }
}

void draw(){
  background(#4488cc);
  
  for(Follower f : followers){
    f.otherX = mouseX;
    f.otherY = mouseY;
    f.display();
  }
  
  for(Follower f : flagFollowers){
    f.otherX = flag_x;
    f.otherY = flag_y;
    f.display();
  }
  
  if(random(100) < 2){
    new_flag_x = random(flag.width, width-flag.width);
    new_flag_y = random(flag.height, height-flag.height);
  }
  
  flag_x = lerp(flag_x, new_flag_x, 0.1);
  flag_y = lerp(flag_y, new_flag_y, 0.1);
  image(flag, flag_x, flag_y);
}

class Follower{
  // Save the target that this Follower will follow
  Follower other;
  float otherX, otherY;
  
  PImage img;
  float follower_x;
  float follower_y;
  float velocity_x;
  float velocity_y;
  
  // Define constants that affect motion
  float MAX_SPEED = 4;
  float MIN_DISTANCE = 48;
  
  // Each Follower will record its position history in
  // an list of point objects (objects with x,y members)
  // This will be used to make each Follower follow the
  // same track as its target
  int HISTORY_LENGTH = 5;
  ArrayList history;
  
  // Follower constructor
  Follower(PImage img, int x, int y, Follower other){
    this.img = img;
    follower_x = x;
    follower_y = y;
    this.other = other;
    history = new ArrayList();
  }
  
  void display(){
    // Get the target x and y position.
    //
    // This algorithm will follow targets that may or may not have a position
    // history.
    //
    // The targetMoving flag tells this object when its target is moving
    // so that it knows when to move and when to stop.
    PVector t = new PVector(otherX, otherY);
    boolean targetMoving = false;
    if(other != null){
      if(other.history.size() > 0){
        // This target has a history so go towards that
        t = other.history.get(0);
        if(other.velocity_x != 0 || other.velocity_y != 0){
          targetMoving = true;
        }
      }else{
          // This target doesn't have a history defined so just
          // follow its current x and y position
          t.x = other.follower_x;
          t.y = other.follower_y;
          
          // Calculate distance to target
          // If the position is far enough way then consider it "moving"
          // so that we can get this Follower to move.
          float distance = dist(follower_x, follower_y, t.x, t.y);
          if(distance > MIN_DISTANCE) targetMoving = true;
      }
    }else{
      float distance = dist(follower_x, follower_y, t.x, t.y);
      if(distance > MIN_DISTANCE) targetMoving = true;
    }
    
    if(targetMoving){
       // Add current position to the end of the history array
      history.add(new PVector(follower_x, follower_y));
      
      // If the length of the history array is over a certain size
        // then remove the oldest (first) element
      if(history.size() > HISTORY_LENGTH){
        history.remove(0);
      }
      
      // Calculate the angle to the target
      float rotation = atan2(t.y - follower_y, t.x - follower_x);
      
      // Calculate velocity vector based on rotation and this.MAX_SPEED
      velocity_x = cos(rotation) * MAX_SPEED;
      velocity_y = sin(rotation) * MAX_SPEED;
      
    }else{
      velocity_x = velocity_y = 0;
    }
    
    follower_x += velocity_x;
    follower_y += velocity_y;
    
    image(img, follower_x, follower_y);
  }
}

Warning: Cannot load module "http" because required module "raphf" is not loaded in Unknown on line 0