Question

At the moment I'm working at an assignment for which I have to make a flocking system with different subclasses that behave different. I'm working with OpenFrameworks and C++. I'm pretty new to Open Frameworks and C++.

As a basis I us this code: https://sites.google.com/site/ofauckland/examples/ofxflocking-example

The thing however is, that the structure of this code is different then I'm used to; making new class objects with 'new ...'

My question is, how can I use two flocking classes? To get started, first only with a different color for instance.

One of the subclasses I've added until now is this:

class Team1 : public Boid {
public:

   Team1(): Boid() {};
   Team1(int x, int y): Boid(x,y) {};



   void draw()
    {

    }
};

I used a virtual void draw for the void draw of the superclass Boid and used boids.push_back(*new Team1()); in setup and and mousedrag. This gives the following errors:

  • expected type-specifier before Team1
  • expected ) before Team1
  • no matching function for call to std::vector<Boid, std::allocator<Boid> >::push_back(int&)

WHOLE CODE: (all the code is in one testapp.cpp file to exclude linking problems)

//number of boids
const int BoidAmount = 25;

Superclass Boid:

class Boid {
public:
Boid();
Boid(int x, int y);

void update(vector<Boid> &boids);
virtual void draw() {};

void seek(ofVec2f target);
void avoid(ofVec2f target);
void arrive(ofVec2f target);

void flock(vector<Boid> &boids);

ofVec2f steer(ofVec2f target, bool slowdown);   

ofVec2f separate(vector<Boid> &boids);
ofVec2f align(vector<Boid> &boids);
ofVec2f cohesion(vector<Boid> &boids);

ofVec2f location,direction

,acceleration;

float r;
float attraction;
float maxspeed;
};

Constructors:

 //---Constructors(overload)-----------------------------------------
Boid::Boid() {
location.set(ofRandomWidth(),ofRandomHeight());
direction.set(0,0);
acceleration.set(0,0);
r = 3.0;
maxspeed = 4;
attraction = 0.05; 
}

Boid::Boid(int x, int y) {
location.set(x,y); //initial location
direction.set(0,0); //initial direction
acceleration.set(0,0); //initial acceleration   
r = 3.0;
maxspeed = 4; // initial max speed
attraction = 0.1; // initial max force
}

Subclasses:

class Team1 : public Boid {
public:

Team1(): Boid() {};
Team1(int x, int y): Boid(x,y) {};



void draw()
{
    // Draw a triangle rotated in the direction of direction
    float angle = (float)atan2(-direction.y, direction.x);
    float theta =  -1.0*angle;
    float heading2D = ofRadToDeg(theta)+90;

    ofPushStyle();
    ofFill();


    ofPushMatrix();
    ofTranslate(location.x, location.y);

    ofRotateZ(heading2D);
    ofSetColor(255,255,255,80);

    ofEllipse(0, -r*2, 7, 12);
    ofBeginShape();
    ofVertex(0, -r*2);
    ofVertex(-r, r*2);
    ofVertex(r, r*2);
    ofEndShape(true);   
    ofPopMatrix();
    ofPopStyle();
}
};

class Team2 : public Boid {
public:

Team2(): Boid() {};
Team2(int x, int y): Boid(x,y) {};


void draw()
{


}

};

Methods:

// Method to update location
void Boid::update(vector<Boid> &boids) {

flock(boids);

direction += acceleration;   // Update direction
direction.x = ofClamp(direction.x, -maxspeed, maxspeed);  // Limit speed
direction.y = ofClamp(direction.y, -maxspeed, maxspeed);  // Limit speed
location += direction;
acceleration = 0;  // Reset accelertion to 0 each cycle

if (location.x < -r) location.x = ofGetWidth()+r;
if (location.y < -r) location.y = ofGetHeight()+r;

if (location.x > ofGetWidth()+r) location.x = -r;
if (location.y > ofGetHeight()+r) location.y = -r;
}

//SEEK
void Boid::seek(ofVec2f target) {
acceleration += steer(target, false);
}



// A method that calculates a steering vector towards a target
// Takes a second argument, if true, it slows down as it approaches the target
ofVec2f Boid::steer(ofVec2f target, bool slowdown) {
   ofVec2f steer;  // The steering vector
   ofVec2f desired = target - location;  // A vector pointing from the location to the target

float d = ofDist(target.x, target.y, location.x, location.y); // 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) {

    desired /= d; // Normalize desired

    // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
    if ((slowdown) && (d < 100.0f)) {
        desired *= maxspeed * (d/100.0f); // This damping is somewhat arbitrary
    } else {
        desired *= maxspeed;
    }
    // Steering = Desired minus direction
    steer = desired - direction;
    steer.x = ofClamp(steer.x, -attraction, attraction); // Limit to maximum steering force
    steer.y = ofClamp(steer.y, -attraction, attraction); 

}
return steer;
}



//----------FLOCKING-BEHAVIOUR-------------------------------------------

void Boid::flock(vector<Boid> &boids) {
ofVec2f Seperation = separate(boids);
ofVec2f Alignment = align(boids);
ofVec2f Cohesion = cohesion(boids);

// Arbitrarily weight these forces
Seperation *= 1.5;
Alignment *= 1.0;
Cohesion *= 1.0;

acceleration += Seperation + Alignment + Cohesion;
}

//--SEPERATION--
// Method checks for nearby boids and steers away
ofVec2f Boid::separate(vector<Boid> &boids) {
float desiredseparation = 30.0;
ofVec2f steer;
int count = 0;

// For every boid in the system, check if it's too close
for (int i = 0 ; i < boids.size(); i++) {
    Boid &other = boids[i];

    float d = ofDist(location.x, location.y, other.location.x, other.location.y);

    // 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
        ofVec2f diff = location - other.location;
        diff /= d;          // normalize
        diff /= d;        // Weight by distance
        steer += diff;
        count++;            // Keep track of how many
    }
}
// Average -- divide by how many
if (count > 0) {
    steer /= (float)count;
}


// As long as the vector is greater than 0
//float mag = sqrt(steer.x*steer.x + steer.y*steer.y);

float mag = sqrt(steer.x*steer.x + steer.y*steer.y);
if (mag > 0) {
    // Steering = Desired - direction
    steer /= mag;
    steer *= maxspeed;
    steer -= direction;
    steer.x = ofClamp(steer.x, -attraction, attraction);
    steer.y = ofClamp(steer.y, -attraction, attraction);
}
return steer;
}

//--ALIGNMENT--
// For every nearby boid in the system, calculate the average direction
ofVec2f Boid::align(vector<Boid> &boids) {
float neighbordist = 60.0;
ofVec2f steer;
int count = 0;
for (int i = 0 ; i < boids.size(); i++) {
    Boid &other = boids[i];

    float d = ofDist(location.x, location.y, other.location.x, other.location.y);
    if ((d > 0) && (d < neighbordist)) {
        steer += (other.direction);
        count++;
    }
}
if (count > 0) {
    steer /= (float)count;
}

// As long as the vector is greater than 0
float mag = sqrt(steer.x*steer.x + steer.y*steer.y);
if (mag > 0) {
    // Implement Reynolds: Steering = Desired - direction
    steer /= mag;
    steer *= maxspeed;
    steer -= direction;
    steer.x = ofClamp(steer.x, -attraction, attraction);
    steer.y = ofClamp(steer.y, -attraction, attraction);
}
return steer;
}

//--COHESION--
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards     that location
ofVec2f Boid::cohesion(vector<Boid> &boids) {
float neighbordist = 50.0;
ofVec2f sum;   // Start with empty vector to accumulate all locations
int count = 0;
for (int i = 0 ; i < boids.size(); i++) {
    Boid &other = boids[i];
    float d = ofDist(location.x, location.y, other.location.x, other.location.y);
    if ((d > 0) && (d < neighbordist)) {
        sum += other.location; // Add location
        count++;
    }
}
if (count > 0) {
    sum /= (float)count;
    return steer(sum, false);  // Steer towards the location
}
return sum;
}

//--------------------------------------------------------------
bool isMouseMoving() {
static ofPoint pmouse;
ofPoint mouse(ofGetMouseX(),ofGetMouseY());
bool mouseIsMoving = (mouse!=pmouse);
pmouse = mouse;
return mouseIsMoving;
}

vector initialize:

std::vector<Boid*> boids;

-

//--------------------------------------------------------------
void testApp::setup() {
ofSetBackgroundAuto(false);
ofBackground(0,0,0);
ofSetFrameRate(60);
ofEnableAlphaBlending();
for(int i=0; i<10; i++) 
{
    boids.push_back(new Team1());
    //boids.push_back(Boid());
}
}

//--------------------------------------------------------------
void testApp::update() {


    for(int i=0; i<boids.size(); i++) {            
        boids[i]->seek(ofPoint(mouseX,mouseY));
    }



    for(int i=0; i<boids.size(); i++) {
        boids[i]->update(boids);
    }

}

//--------------------------------------------------------------
void testApp::draw() {

ofSetColor(0,0,0,20);
ofRect(0,0,ofGetWidth(),ofGetHeight());

for(int i=0; i<boids.size(); i++) 
{
    boids[i]->draw();
}
}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button) {


boids.push_back(new Team1(x,y));
    ////boids.push_back(Boid());
    //boids.push_back(Boid(x,y));
}
Was it helpful?

Solution

From the error, it seems like you have a std::vector<Boid>. You need to hold Boids polymorphically, so your vector should hold (preferably smart) pointers to Boid:

std::vector<Boid*> boids;

or

std::vector<std::unique_ptr<Boid>> boids;

which you then can fill like this:

boids.push_back(new Team1());

or

boids.push_back(std::unique_ptr<Boid>(new Team1()));

respectively.

Note that std::unique_ptr requires C++11 support. More on smart pointers here.

OTHER TIPS

It's hard to be certain without seeing more code, but I guess the code calling boids.push_back(*new Team1()); cannot see the definition of Team1. You need to #include a header file defining Team1 in every .cpp file where you want to use it.

Also, to be able to use polymorphism (virtual functions), you must store pointers in your vector, not the actual objects. So you must type your vector as std::vector<Boid*>. Or preferably use a smart pointer, such as std::vector<std::shared_ptr<Boid> >.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top