Alphaam_RobotaPsyche/March1/vehicle.pde
// The vehicle class, more or less straight from the book

class Vehicle {

  PVector location;
  PVector velocity;
  PVector acceleration;
  float maxforce;
  float maxspeed;
  float energy;
  float metabolism; // how much energy is used in each frame
  DNA dna; // unique but fixed qualities
  boolean alive;
  //color c;
  float _red;
  float _green;
  float _blue;

  Vehicle(float x, float y, float r, float imsf, float ims, float ie, float metab, float dat, float red, float green, float blue) {
    acceleration = new PVector(0, 0);
    velocity = new PVector(0, 0);
    location = new PVector(x, y);
    dna = new DNA(r, imsf, ims, ie, metab, dat, red, green, blue);

    maxforce = dna.initialMaxSteeringForce;
    maxspeed = dna.initialMaxSpeed;
    energy = dna.initialEnergy;
    alive = true;
    
  }

  /*
  Different steering algorithms. A vehicle
   could use any, and you can create additional ones.
   Each algorithm calculates and returns a steering force
   */

  // Calculate steering force to seek a target
  // simpleSeek goes to target at max speed
  void simpleSeek(PVector target) {
    PVector desired = PVector.sub(target, location);
    applyForce(applyLimits(desired));
  }

  // Calculate the steering force to follow a flow field
  void follow(FlowField flow) {
    // Look up the vector at that spot in the flow field
    PVector desired = flow.lookup(location);
    desired.mult(maxspeed);

    // Steering is desired minus velocity
    PVector steer = PVector.sub(desired, velocity);
    applyForce(applyLimits(steer));
  }

  // Calculate a steering force to separate from other vehicles
  void separate (ArrayList<Vehicle> vehicles) {
    float desiredseparation = 200; // how close is too close.
    int count = 0;
    PVector sum = new PVector(0, 0);

    for (Vehicle other : vehicles) {

      // What is the distance between me and another Vehicle?
      float d = PVector.dist(location, other.location);

      // If the distance is zero we are looking at ourselves; exclude that
      if ((d > 0) && (d < desiredseparation)) {

        // calculate the location of this vehicle
        PVector diff = PVector.sub(location, other.location);
        diff.normalize();

        // We'll need the average, so add this location to the sum
        // of all locations and increment the count.
        sum.add(diff);
        count++;
      }
    } // end of loop over all vehicles

    // now calculate the average,
    // figure out the force
    // and apply the force:
    if (count > 0) { // If zero then no one is too close
      sum.div(count); // sum is now our desired velocity
      applyForce(applyLimits(sum));
    }
  }

  // Limit the steering force by the max speed and the max steering force
  PVector applyLimits(PVector desired) {
    desired.normalize();
    desired.mult(maxspeed);
    PVector steer = PVector.sub(desired, velocity);
    steer.limit(maxforce);
    return(steer);
  }

  // Newtonâ€™s second law; we could divide by mass if we wanted.
  // If there are multiple forces (e.g. gravity, wind) we use
  // this function for each one, and it is added to the acceleration
  void applyForce(PVector force) {
    acceleration.add(force);
  }

  void feed(PVector food) {
    PVector dist = PVector.sub(food, location);
    if (dist.mag() < 40) {
      energy++;
    }
  }

  void consumeEnergy() {
    if (abs(energy) < dna.deadAt) {
      alive = false;
    } else {
      energy -= dna.metabolism;
    }
  }

  void checkBoarders() {
    if (location.y > height || location.y < 0 || location.x > width || location.x < 0) {
      alive = false;
    }
  }

  // Update the velocity and location, based on the acceleration generated by the steering force
  void update() {
    velocity.add(acceleration);
    velocity.limit(maxspeed);
    location.add(velocity);
    acceleration.mult(0); // clear the acceleration for the next frame
  }

  void display() {
    float r = dna.radius;
    // Vehicle is a triangle pointing in
    // the direction of velocity; since it is drawn
    // pointing up, we rotate it an additional 90 degrees.
    float theta = velocity.heading() + PI/2;
    //
    fill(dna.shadeOfRed, dna.shadeOfGreen, dna.shadeOfBlue);
    noStroke();
    pushMatrix();
    translate(location.x, location.y);
    rotate(theta);
    //beginShape();
    //vertex(0, -r*2);
    //vertex(-r, r*2);
    ellipse(r, r*2, r, r);
    endShape(CLOSE);
    popMatrix();
  }

  DNA getDNA() {
    return(dna.getDNA());
  }

  // Originally for debugging, determine the distance to this vehicle
  float distance(PVector l) {
    return PVector.sub(l, location).mag();
  }

  void inspect() {
    println("\nVehicle inspector:");
    println("Location: " + location.x + ", " + location.y);
    println("Velocity = " + velocity + " acceleration = " + acceleration);
    println("Maximum steering force = " + maxforce + ", maximum speed = " + maxspeed);
    println("Current energy level = " + energy + ", metabolism rate = " +  metabolism);
    dna.inspect();
  }
}
