openFrameworksでBoids
openFrameworksでBoidsを実装した. Boidsとは
実装自体はProcessingの/examples/Simulate/Flockingをほぼパクリ.GUIは,ofxGuiを使用. 「f」キーを押すと,フルスクリーンに切り替えることができる.
現在の環境(Mac book Pro, 3GHz Intel Core i7)では,500体ぐらい動かすと動きがカクカクしてくる.正直,C++なら1000体ぐらい余裕で動くかと思っていた.冗長なところは多々あるので,そこを直せばもう少し動くかも.
以下,コード.
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