class Rat { //----------------------------------------------------- private int imgIndex; private PVector loc; private PVector vel; private PVector acc; private boolean wandering; private float wanderTheta; private float maxForce; private float maxSpeed; private GeneralPath area; //----------------------------------------------------- public Rat(GeneralPath _area) { area = _area; float coin = (float)Math.random(); if (coin < .25f) imgIndex = 0; else if (coin < .55f) imgIndex = 1; else if (coin < .85f) imgIndex = 2; else imgIndex = 3; acc = new PVector(0,0); vel = new PVector(0,0); loc = new PVector(random(width), random(height)); wandering = false; wanderTheta = 0.0f; maxSpeed = 3.0f; maxForce = 0.1f; } //----------------------------------------------------- public void update() { if (wandering) { // wander float wanderRadius = 16.0f; float wanderDist = 60.0f; float change = 0.25f; wanderTheta += random(-change, change); // Now we have to calculate the new location to steer towards on the wander circle PVector circleLoc = vel.get(); // Start with velocity circleLoc.normalize(); // Normalize to get heading circleLoc.mult(wanderDist); // Multiply by distance circleLoc.add(loc); // Make it relative to boid's location PVector circleOffSet = new PVector(wanderRadius * PApplet.cos(wanderTheta), wanderRadius * PApplet.sin(wanderTheta)); PVector target = PVector.add(circleLoc, circleOffSet); acc.add(steer(target, true)); // Steer towards it } else { acc.add(steer(new PVector((float)area.getBounds().getCenterX(), (float)area.getBounds().getCenterY()), true)); } // update velocity vel.add(acc); // limit speed vel.limit(maxSpeed); loc.add(vel); if (wandering) { // bounce off the borders if (!area.contains(loc.x, loc.y)) { wandering = false; wanderTheta += PConstants.PI; } } else { // check if we reached the target if (area.contains(loc.x, loc.y)) { wandering = true; } } // reset acc.mult(0); } //----------------------------------------------------- // Calculates a steering vector towards a target // Takes a second argument, if true, it slows down as it approaches the target private PVector steer(PVector target, boolean slowdown) { PVector steer; // The steering vector PVector desired = PVector.sub(target, loc); // A vector pointing from the location to the target float d = desired.mag(); // Distance from the target is the magnitude of the vector // If the distance is greater than 0, calc steering (otherwise return zero vector) if (d > 0) { // Normalize desired desired.normalize(); // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed) if ((slowdown) && (d < 100.0f)) desired.mult(maxSpeed*(d/100.0f)); // This damping is somewhat arbitrary else desired.mult(maxSpeed); // Steering = Desired minus Velocity steer = PVector.sub(desired, vel); steer.limit(maxForce); // Limit to maximum steering force } else { steer = new PVector(0,0); } return steer; } //----------------------------------------------------- public void render() { fill(175); stroke(0); pushMatrix(); translate(loc.x,loc.y); float theta = vel.heading2D() + radians(90); rotate(theta); //ellipse(0, 0, 10, 10); translate(-ratImgs[imgIndex].width/2, 0); image(ratImgs[imgIndex], 0, 0); popMatrix(); } //----------------------------------------------------- public void setArea(GeneralPath _area) { area = _area; wandering = false; } }