aa develop

開発と成長

openFrameworksでBoids

openFrameworksでBoidsを実装した. Boidsとは

実装自体はProcessingの/examples/Simulate/Flockingをほぼパクリ.GUIは,ofxGuiを使用. 「f」キーを押すと,フルスクリーンに切り替えることができる.

現在の環境(Mac book Pro, 3GHz Intel Core i7)では,500体ぐらい動かすと動きがカクカクしてくる.正直,C++なら1000体ぐらい余裕で動くかと思っていた.冗長なところは多々あるので,そこを直せばもう少し動くかも.

f:id:aa_debdeb:20160714102321p:plain

以下,コード.

ofApp.h

#pragma once

#include "ofMain.h"
#include "boid.h"
#include "flock.h"
#include "ofxGui.h"

class ofApp : public ofBaseApp{

    public:
        void setup();
        void update();
        void draw();

        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y );
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
    
    private:
        Flock flock;
    
        ofxPanel gui;
        ofxFloatSlider separateForce;
        ofxFloatSlider alignForce;
        ofxFloatSlider cohesionForce;
        ofxFloatSlider separateRadious;
        ofxFloatSlider alignRadious;
        ofxFloatSlider cohesionRadious;
        ofxFloatSlider maxSpeed;
    
};
ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofSetVerticalSync(true);
    ofBackground(50);
    flock = Flock();
    for(int i = 0; i < 300; i++){
        flock.addBoid(Boid(ofGetWidth() / 2.0, ofGetHeight() / 2.0));
    }
    
    gui.setup();
    gui.add(separateForce.setup("separation force", 1.5, 0, 3));
    gui.add(alignForce.setup("alignment force", 1, 0, 3));
    gui.add(cohesionForce.setup("cohesion force", 1, 0, 3));
    gui.add(separateRadious.setup("separation radious", 25, 0, 300));
    gui.add(alignRadious.setup("alignment radious", 50, 0, 300));
    gui.add(cohesionRadious.setup("cohesion radious", 50, 0, 300));
    gui.add(maxSpeed.setup("max speed", 2, 0, 4));
}


//--------------------------------------------------------------
void ofApp::update(){
    flock.run(separateForce, alignForce, cohesionForce,
              separateRadious, alignRadious, cohesionRadious, maxSpeed);
}

//--------------------------------------------------------------
void ofApp::draw(){
    flock.render();
    
    gui.draw();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    switch(key){
        case 'f':
            ofToggleFullscreen();
            break;
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

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

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){ 

}
flock.h

//
//  flock.h
//  boids
//
//  Created by aa_debdeb on 2015/11/13.
//
//

#ifndef __boids__flock__
#define __boids__flock__

#include 
#include "ofMain.h"
#include "boid.h"

class Flock{
public:
    Flock();
    void run(float separateForce, float alignForce, float cohesionForce,
             float separateRadious, float alignRadious, float cohesionRadious, float maxSpeed);
    void render();
    void addBoid(Boid b);
private:
    vector boids;
};


#endif /* defined(__boids__flock__) */
flock.cpp

//
//  flock.cpp
//  boids
//
//  Created by aa_debdeb on 2015/11/13.
//
//

#include "flock.h"

Flock::Flock(){
    boids = vector();
}

void Flock::run(float separateForce, float alignForce, float cohesionForce,
                float separateRadious, float alignRadious, float cohesionRadious, float maxSpeed){
    for(int i = 0; i < boids.size(); i++){
        boids[i].run(boids, separateForce, alignForce, cohesionForce, separateRadious, alignRadious, cohesionRadious, maxSpeed);
    }
}

void Flock::render(){
    for(int i = 0; i < boids.size(); i++){
        boids[i].render();
    }
}

void Flock::addBoid(Boid b){
    boids.push_back(b);
}
boid.h

//
//  boid.h
//  boids
//
//  Created by aa_debdeb on 2015/11/12.
//
//

#ifndef __boids__boid__
#define __boids__boid__

#include 
#include "ofMain.h"

class Boid {
public:
    Boid(float x, float y);
    void run(vector boids, float separateForce, float alignForce, float cohesionForce,
                                 float separateRadious, float alignRadious, float cohesionRadious, float maxSpeed);
    void render();
    
private:
    void applyForce(ofVec2f force);
    void flock(vector boids);
    void borders();
    void update();
    ofVec2f seek(ofVec2f target);
    ofVec2f separate(vector boids);
    ofVec2f align(vector boids);
    ofVec2f cohesion(vector boids);
    ofVec2f location;
    ofVec2f velocity;
    ofVec2f acceleration;
    float r;
    float maxForce;
    float maxSpeed;
    
    float separateForce;
    float alignForce;
    float cohesionForce;
    float separateRadious;
    float alignRadious;
    float cohesionRadious;
};

#endif /* defined(__boids__boid__) */
boid.cpp

//
//  boid.cpp
//  boids
//
//  Created by aa_debdeb on 2015/11/12.
//
//

#include "boid.h"

Boid::Boid(float x, float y){
    acceleration = ofVec2f(0, 0);
    float angle = ofRandom(TWO_PI);
    velocity = ofVec2f(cos(angle), sin(angle));
    location = ofVec2f(x, y);
    r = 3.0;
    maxForce = 0.03;
}

void Boid::run(vector boids, float separateForce, float alignForce, float cohesionForce,
                                   float separateRadious, float alignRadious, float cohesionRadious, float maxSpeed){
    this->separateForce = separateForce;
    this->alignForce = alignForce;
    this->cohesionForce = cohesionForce;
    this->separateRadious = separateRadious;
    this->alignRadious = alignRadious;
    this->cohesionRadious = cohesionRadious;
    this->maxSpeed = maxSpeed;
    flock(boids);
    update();
    borders();
}

void Boid::applyForce(ofVec2f force){
    acceleration += force;
}

void Boid::flock(vector boids){
    ofVec2f sep = separate(boids);
    ofVec2f ali = align(boids);
    ofVec2f coh = cohesion(boids);
    sep = sep * separateForce;
    ali = ali * alignForce;
    coh = coh * cohesionForce;
    applyForce(sep);
    applyForce(ali);
    applyForce(coh);
}

void Boid::update(){
    velocity += acceleration;
    velocity.limit(maxSpeed);
    location += velocity;
    acceleration *= 0;
}

ofVec2f Boid::seek(ofVec2f target){
    ofVec2f desired = target - location;
    desired.normalize();
    desired *= maxSpeed;
    ofVec2f steer = desired - velocity;
    steer.limit(maxForce);
    return steer;
}

void Boid::render(){
    ofVec2f origin = ofVec2f(1.0, 0.0);
    float theta = origin.angle(velocity) + 90;
    ofSetColor(200, 100);
    ofPushMatrix();
    ofTranslate(location.x, location.y);
    ofRotate(theta);
    ofBeginShape();
    ofVertex(0, -r * 2);
    ofVertex(-r, r * 2);
    ofVertex(r, r * 2);
    ofEndShape();
    ofPopMatrix();
}

void Boid::borders(){
    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;
}

ofVec2f Boid::separate(vector boids){
    float desiredSeparation = separateRadious;
    ofVec2f steer = ofVec2f(0, 0);
    int count = 0;
    for(int i = 0; i < boids.size(); i++){
        Boid other = boids[i];
        float d = location.distance(other.location);
        if((d > 0) && (d < desiredSeparation)){
            ofVec2f diff = location - other.location;
            diff.normalize();
            diff /= d;
            steer += diff;
            count++;
        }
    }
    if(count > 0){
        steer /= (float(count));
    }
    
    if(steer.length() > 0){
        steer.normalize();
        steer *= maxSpeed;
        steer -= velocity;
        steer.limit(maxForce);
    }
    return steer;
    
}

ofVec2f Boid::align(vector boids){
    float neighbordist = alignRadious;
    ofVec2f sum = ofVec2f(0, 0);
    int count = 0;
    for(int i = 0; i < boids.size(); i++){
        Boid other = boids[i];
        float d = location.distance(other.location);
        if((d > 0) && (d < neighbordist)){
            sum += other.velocity;
            count++;
        }
    }
    if(count > 0){
        sum /= (float(count));
        sum.normalize();
        sum *= maxSpeed;
        ofVec2f steer = sum - velocity;
        steer.limit(maxForce);
        return steer;
    } else {
        return ofVec2f(0, 0);
    }
}

ofVec2f Boid::cohesion(vector boids){
    float neighbordist = cohesionRadious;
    ofVec2f sum = ofVec2f(0, 0);
    int count = 0;
    for(int i = 0; i < boids.size(); i++){
        Boid other = boids[i];
        float d = location.distance(other.location);
        if((d > 0) && (d < neighbordist)){
            sum += other.location;
            count++;
        }
    }
    if(count > 0){
        sum /= (float(count));
        return seek(sum);
    } else {
        return ofVec2f(0, 0);
    }
}

プロジェクト全体は以下から. openFrameworks/boids at master · aa-debdeb/openFrameworks