calling separate functions for subclasses
in
Programming Questions
•
10 months ago
Hey guys!
Once again I need your help! I have included the source code below. It's a simple sketch that generates some wandering autonomous agents on a 2D canvas. At this point, there is 1 superclass called "Capsules"and 2 subclasses called MW1 and FW1.
I have succeeded in implementing inheritance and polymorphism (at least I think so) and I generate the agents using this part:
agents = new ArrayList<Capsule>();
for (int i = 0; i < 40; i++) {
if (i < 20) agents.add(new MW1(random(width),random(height),color(255,0,0),i));
else agents.add(new FW1(random(width),random(height),color(0,255,0),i));
}
and inside draw() I am able to call some functions included in the superclass. My question is: how can I apply a function (like arrive() for example) only for the MW1 agents and NOT all of them(?) Cause right now, any method I call, is being applied to all of them, no matter how many agents I create, through this:
for( Capsule agent : agents) { // instancing - creating objects
agent.Default(); // default flocking behavior for ALL the agents
agent.separate(agents); // global separation that affects ALL the agents
}
here is the entire code, any kind of help would be much appreciated!
StopWatchTimer sw; // a visual timer-clock implementation on canvas
int time; // a counter for time triggering events
int wait = 1000; // 1 second
Facilities work; // wondering agent -- represents (W)
Facilities retail; // wondering agent -- represents (R)
Facilities school; // wondering agent -- represents (S)
Facilities leisure; // wondering agent -- represents (L)
ArrayList<Capsule> agents;
float d = 25;
int counter=0; // counter inception
int temp=0;
void setup() {
size(300,300); //generates the basic composition canvas
time = millis(); //store the current time
smooth(); //setup of visual time clock
println (millis());
sw = new StopWatchTimer();
sw.start();
// creating the facilities
work = new Facilities(random(width),random(height)); //generates a hypothetic invisible agent (W)
retail = new Facilities(random(width),random(height)); //generates a hypothetic invisible agent (R)
school = new Facilities(random(width),random(height)); //generates a hypothetic invisible agent (S)
leisure = new Facilities(random(width),random(height)); //generates a hypothetic invisible agent (L)
// creating the agents
agents = new ArrayList<Capsule>();
for (int i = 0; i < 40; i++) {
if (i < 20) agents.add(new MW1(random(width),random(height),color(255,0,0),i));
else agents.add(new FW1(random(width),random(height),color(0,255,0),i));
}
}
//--------------configuring the canvas & the counter-------------
void draw() {
background(255);
time(); //reference to the visual timer
//check the difference between now and the previously stored time is greater than the wait interval
if(millis() - time >= wait){
println(counter);//if it is, do something
temp=counter;
time = millis();//also update the stored time
counter++; // counter augmentation
if(counter >180){ // check whether time exceeds 180 sec. aka 24:00 hours
counter=0;
}
}
//-------------------------------------------------------------
work.Default(); //main-basic functions of (W) facility
retail.Default(); //main-basic functions of (R) facility
school.Default(); //main-basic functions of (S) facility
leisure.Default(); //main-basic functions of (L) facility
PVector vectorOfwork = new PVector(work.location.x, work.location.y); //creates a vector that connects all individual agents with the (W) facility
PVector vectorOfretail = new PVector(retail.location.x, work.location.y); //creates a vector that connects all individual agents with the (R) facility
PVector vectorOfschool = new PVector(school.location.x, school.location.y); //creates a vector that connects all individual agents with the (S) facility
PVector vectorOfleisure = new PVector(leisure.location.x, leisure.location.y); //creates a vector that connects all individual agents with the (L) facility
for( Capsule agent : agents) { // instancing - creating objects
agent.Default(); // default flocking behavior for ALL the agents
agent.separate(agents); // global separation that affects ALL the agents
}
}
//-------------------------------------------------------------
void time() { //visual configuration for the timer-clock
background(#FFFFFF);
fill(#000000);
textAlign(CENTER);
text(nf(sw.hour(), 2)+":"+nf(sw.minute(), 2)+":"+nf(sw.second(), 2)+":"+nf(sw.hundrensec(), 2), 260, 290);
}
//---------------------------------------------superclass----------------------------------------------------//
class Capsule { //the super-class that defines the chararacteristics of the agents
PVector location;
PVector velocity;
PVector acceleration;
float r; //the radius of the circles-spheres/ agents
float wandertheta;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
color fillColor; //differentiation of agent types are based on complementary coloring
int name; // gives an ID - number to each different agent
Capsule(float x, float y, color c, int nam) { //the class constructor
acceleration = new PVector(0,0);
velocity = new PVector(0,0);
location = new PVector(x,y);
r = 6;
wandertheta = 0;
maxspeed = 0.5;
maxforce = 0.05;
fillColor = c;
name = nam;
}
void Default() {
boundaries();
update();
display();
wander();
}
void update() { // Method to update location
velocity.add(acceleration); // Update velocity
velocity.limit(maxspeed); // Limit speed
location.add(velocity); // Reset accelertion to 0 each cycle
acceleration.mult(0);
}
void wander() { // Method that makes the agent float into 2D space
float wanderR = 25; // Radius for our "wander circle"
float wanderD = 200; // Distance for our "wander circle"
float change = 0.05;
wandertheta += random(-change,change); // Randomly change wander theta
// calculating the new location to steer towards on the wander circle
PVector circleloc = velocity.get(); // Start with velocity
circleloc.normalize(); // Normalize to get heading
circleloc.mult(wanderD); // Multiply by distance
circleloc.add(location); // Make it relative to boid's location
float h = velocity.heading2D(); // We need to know the heading to offset wandertheta
PVector circleOffSet = new PVector(wanderR*cos(wandertheta+h),wanderR*sin(wandertheta+h));
PVector target = PVector.add(circleloc,circleOffSet);
seek(target);
}
void applyForce(PVector force) { // Newton's second law; We could add mass here if we want A = F / M
acceleration.add(force);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
void seek(PVector target) {
PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target
desired.normalize(); // Normalize desired and scale to maximum speed
desired.mult(maxspeed);
PVector steer = PVector.sub(desired,velocity); // Steering = Desired minus Velocity
steer.limit(maxforce); // Limit to maximum steering force
applyForce(steer);
}
// Method that lowers the speed of the agent by the time he reaches the target - see: "buffer zone"
void arrive(PVector target) {
PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target
float d = desired.mag();
desired.normalize(); // Normalize desired and scale with arbitrary damping within 100 pixels
if (d < 6) {
float m = map(d,0,15,0,maxspeed);
desired.mult(m);
} else {
desired.mult(maxspeed);
}
PVector steer = PVector.sub(desired,velocity); // Steering = Desired minus Velocity
steer.limit(5*maxforce); // Limit to maximum steering force
applyForce(steer);
}
void display() { // Draws an ellipse that represents an agent-capsule
fill(fillColor);
stroke(0);
pushMatrix();
translate(location.x, location.y);
ellipse(0, 0, r, r);
popMatrix();
}
//Method that checkes the maximum floating range of the agents
void boundaries() {
PVector desired = null;
if (location.x < d) {
desired = new PVector(maxspeed, velocity.y);
}
else if (location.x > width -d) {
desired = new PVector(-maxspeed, velocity.y);
}
if (location.y < d) {
desired = new PVector(velocity.x, maxspeed);
}
else if (location.y > height-d) {
desired = new PVector(velocity.x, -maxspeed);
}
if (desired != null) {
desired.normalize();
desired.mult(maxspeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(2*maxforce);
applyForce(steer);
}
}
// Method that separates the agents from one-another -- see: "buffer zone"
void separate (ArrayList<Capsule> agent) {
float desiredseparation = r*4; //4*r = separation ONLY for wandering
PVector sum = new PVector();
int count = 0;
// For every agent in the system, check if it's too close
for (Capsule v : agent) {
float d = PVector.dist(location, v.location);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
PVector diff = PVector.sub(location, v.location);
diff.normalize();
diff.div(d); // Weight by distance
sum.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
sum.div(count);
sum.normalize(); // Our desired vector is the average scaled to maximum speed
sum.mult(maxspeed);
// Implement Reynolds: Steering = Desired - Velocity
PVector steer = PVector.sub(sum, velocity);
steer.limit(maxforce);
applyForce(steer);
}
}
// Method that separates the agents from one-another -- see: "buffer zone"
void separateSpecial (ArrayList<Capsule> agent) {
float desiredseparation = r; //
PVector sum = new PVector();
int count = 0;
// For every agent in the system, check if it's too close
for (Capsule v : agent) {
float d = PVector.dist(location, v.location);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
PVector diff = PVector.sub(location, v.location);
diff.normalize();
diff.div(d); // Weight by distance
sum.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
sum.div(count);
sum.normalize(); // Our desired vector is the average scaled to maximum speed
sum.mult(maxspeed);
// Implement Reynolds: Steering = Desired - Velocity
PVector steer = PVector.sub(sum, velocity);
steer.limit(maxforce);
applyForce(steer);
}
}
// Alignment
// For every nearby agent in the system, calculate the average velocity
PVector align (ArrayList<Capsule> agent) {
float neighbordist = 50;
PVector sum = new PVector(0,0);
int count = 0;
for (Capsule v : agent) {
float d = PVector.dist(location,v.location);
if ((d > 0) && (d < neighbordist)) {
sum.add(v.velocity);
count++;
}
}
if (count > 0) {
sum.div((float)count);
sum.normalize();
sum.mult(maxspeed);
PVector steer = PVector.sub(sum,velocity);
steer.limit(maxforce);
return steer;
} else {
return new PVector(0,0);
}
}
}
//--------------------------------------------------------subclasses-----------------------------------------------------------------------//
class MW1 extends Capsule { // subclass: male_worker_single
MW1(float x_mw1, float y_mw1, color c_mw1, int nam_mw1) {
super(x_mw1,y_mw1,c_mw1,nam_mw1);
}
void display() {
fill(255,0,0);
stroke(0);
pushMatrix();
translate(location.x, location.y);
ellipse(0, 0, r, r);
popMatrix();
}
}
class FW1 extends Capsule { // subclass: female_worker_single
FW1(float x_fw1, float y_fw1, color c_fw1, int nam_fw1) {
super(x_fw1,y_fw1,c_fw1,nam_fw1);
}
void display() {
fill(0,255,0);
stroke(0);
pushMatrix();
translate(location.x, location.y);
ellipse(0, 0, r, r);
popMatrix();
}
}
//----------------------------------------------rest parts------------------------------------------------------//
class Facilities { //the class that defines the chararacteristics of institutions
PVector location;
PVector velocity;
PVector acceleration;
float r; //the radius of the circles-spheres/ facilities
float wandertheta;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
Facilities(float x, float y) { //the class constructor
acceleration = new PVector(0,0);
velocity = new PVector(0,0);
location = new PVector(x,y);
r = 6;
wandertheta = 0;
maxspeed = 1;
maxforce = 0.05;
}
void Default() { // the basic, default functions for the facility
wander();
run();
boundaries();
}
void run() {
update();
display();
}
void update() { // Method to update location
velocity.add(acceleration); // Update velocity
velocity.limit(maxspeed); // Limit speed
location.add(velocity);
acceleration.mult(0); // Reset accelertion to 0 each cycle
}
void wander() { // Method that makes the agent float into 2D space
float wanderR = 25; // Radius for our "wander circle"
float wanderD = 30; // Distance for our "wander circle"
float change = 2;
wandertheta += random(-change,change); // Randomly change wander theta
// calculating the new location to steer towards on the wander circle
PVector circleloc = velocity.get(); // Start with velocity
circleloc.normalize(); // Normalize to get heading
circleloc.mult(wanderD); // Multiply by distance
circleloc.add(location); // Make it relative to boid's location
float h = velocity.heading2D(); // We need to know the heading to offset wandertheta
PVector circleOffSet = new PVector(wanderR*cos(wandertheta+h),wanderR*sin(wandertheta+h));
PVector target = PVector.add(circleloc,circleOffSet);
seek(target);
}
void applyForce(PVector force) { // We could add mass here if we want A = F / M
acceleration.add(force);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
void seek(PVector target) {
PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target
desired.normalize(); // Normalize desired and scale to maximum speed
desired.mult(maxspeed);
// Steering = Desired minus Velocity
PVector steer = PVector.sub(desired,velocity);
steer.limit(maxforce); // Limit to maximum steering force
applyForce(steer);
}
void display() { // Draw an ellipse that represents a facility-capsule
fill(255);
stroke(255);
pushMatrix();
translate(location.x, location.y);
ellipse(0, 0, r, r);
popMatrix();
}
//Method that checkes the maximum floating range of the facilities
void boundaries() {
PVector desired = null;
if (location.x < d) {
desired = new PVector(maxspeed, velocity.y);
}
else if (location.x > width -d) {
desired = new PVector(-maxspeed, velocity.y);
}
if (location.y < d) {
desired = new PVector(velocity.x, maxspeed);
}
else if (location.y > height-d) {
desired = new PVector(velocity.x, -maxspeed);
}
if (desired != null) {
desired.normalize();
desired.mult(maxspeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(2*maxforce);
applyForce(steer);
}
}
}
// class timer -- the visual counting clock on the canvas
class StopWatchTimer {
int startTime = 0, stopTime = 0;
boolean running = false;
void start() {
startTime = millis();
running = true;
}
void stop() {
stopTime = millis();
running = false;
}
int getElapsedTime() {
int elapsed;
if (running) {
elapsed = (millis() - startTime);
}
else {
elapsed = (stopTime - startTime);
}
return elapsed;
}
int hundrensec() // And add in the class before int second() this :
{
return (getElapsedTime() / 10) % 100;
}
int second() {
return (getElapsedTime() / 1000) % 60;
}
int minute() {
return (getElapsedTime() / (1000*60)) % 60;
}
int hour() {
return (getElapsedTime() / (1000*60*60)) % 24;
}
}
1