Boid

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(全体の記述)
(アルゴリズム)
1行: 1行:
=== アルゴリズム ===
 
 
Boidは以下の3つの規則にしたがって動く。
 
 
# 分離(Separation)
 
#* 互いの距離が近すぎると、個体は他の個体とぶつからないように距離を広げる。
 
# 整列(Alignment)
 
#* 適度な距離にいる個体同士は、同じ方向に飛ぶように速度を合わせる。
 
# 結合(Cohesion)
 
#* ある程度距離が離れると、個体同士は、群れの中心方向へ向かうような速度をとる。
 
 
 
=== Birdクラスのヘッダー ===
 
=== Birdクラスのヘッダー ===
  

2020年10月31日 (土) 00:19時点における版

目次

Birdクラスのヘッダー

  • vec2fクラスは、2次元のベクトルを表す。位置、速度、加速度など、(x,y)の2次元座標で表せるデータに使用している。
    • vec2fは、従来のofPointに相当する。
    • http://openframeworks.cc/documentation/math/ofVec2f/
    • set( , )は、値をセットする
    • getNormalize()は、正規化する(単位ベクトル化する)
    • distancet( , )は、2つのベクトルの距離を求める
    • scale( )は、ベクトルの大きさを指定した値にする
  • クラスの動的配列として、、vector <クラス名>を使う
  • Birdクラスの引数
    1. 自分の群れ(ポインタ) vector<Bird>* const
    2. 個体番号 const int
    3. 個体の色 ofColor
    4. 敵対する群れ(ポインタ) vector<Bird>* const
    5. 友好的な群れ(ポインタ) vector<Bird>* const
    6. 友好的な群れ2(ポインタ) vector<Bird>* const
Bird.h
#pragma once
#include "ofMain.h"

class Bird
{
public:
    Bird(vector<Bird>* const, const int, ofColor, vector<Bird>* const, vector<Bird>* const, vector<Bird>* const);
    virtual ~Bird();
    
    virtual void update();
    virtual void draw();
    
    int id; //群れの中の個体の識別番号
    float head; //個体の頭の半径
    float tail; //個体の尾の長さ
    ofVec2f pos; //個体の位置
    ofVec2f vel; //個体の速度
    ofVec2f acc; //個体の速度変化(加速度)
    ofColor ourColor; //個体の色
    
protected:
    vector<Bird>* pSelfGroup; //自分の所属する群れ
    vector<Bird>* pEnemyGroup; //敵対する群れ
    vector<Bird>* pFriendGroup; //友好的な群れ
    vector<Bird>* pFriendGroup2; //友好的な群れ2
    
    ofVec2f separationVel; //分離
    ofVec2f alignmentVel; //整列
    ofVec2f cohesionVel; //結合
    ofVec2f groupCenterPos; //群れの中心位置
};

Birdクラス本体

  • Birsクラスは、複数の個体からなる群れである。
  • 個体同士は、距離60未満のとき、相互作用する。
  • 同じ群れの個体同士または友好的な群れの個体同士の場合
    1. 分離(Separation)距離 10 未満のとき
    2. 整列(Alignment)距離 10以上 35未満のとき
    3. 結合(Cohesion)距離 35以上 60未満のとき
  • 敵対する群れ同士の場合
    1. 分離(Separation)距離 60未満のとき
Bird.cpp
#include "Bird.h"

Bird::Bird( vector<Bird>* const _pSelfGroup, const int _id, const ofColor _ourColor, vector<Bird>* const _pEnemyGroup, vector<Bird>* const _pFriendGroup, vector<Bird>* const _pFriendGroup2 )
{
	pSelfGroup = _pSelfGroup;
	pEnemyGroup = _pEnemyGroup;
	pFriendGroup = _pFriendGroup;
	pFriendGroup2 = _pFriendGroup2;
	id = _id;
	ourColor = _ourColor;
	pos.set( ofRandom(0,ofGetWidth() ) , ofRandom(0,ofGetHeight() ) );
	vel.set( ofRandom(-2,2), ofRandom(-2,2) );
	head = 2;
	tail = head * 4.0;
}

Bird::~Bird()
{
}

void Bird::update()
{
	int separationCount = 0;
	int alignmentCount = 0;
	int cohesionCount = 0;
	separationVel.set(0,0);
	alignmentVel.set(0,0);
	cohesionVel.set(0,0);
	groupCenterPos.set(0,0);

	for(int i = 0; i < pSelfGroup->size(); i++){  //自分自身の群れ内での相互作用
		Bird& rAnother = pSelfGroup->at(i);
		if(rAnother.id != id){ //自分自身との相互作用は除く
			float dist = pos.distance( rAnother.pos );
			if(dist < 10){ //分離
				separationVel += pos - rAnother.pos;
				separationCount++;
			}
			else if(dist < 35){ //整列
				alignmentVel += rAnother.vel.getNormalized();
				alignmentCount++;
			}
			else if(dist < 60){ //結合
				groupCenterPos += rAnother.pos;
				cohesionCount++;
			}
		}
	}

	for(int i = 0; i < pFriendGroup->size(); i++){ //友好的な群れとの相互作用
		Bird& rAnother = pFriendGroup->at(i);
		float dist = pos.distance( rAnother.pos );

		if(dist < 10){
			separationVel += pos - rAnother.pos;
			separationCount++;
		}
		else if(dist < 35){
			alignmentVel += rAnother.vel.getNormalized();
			alignmentCount++;
		}
		else if(dist < 60){
			groupCenterPos += rAnother.pos;
			cohesionCount++;
		}
	}

	for(int i = 0; i < pFriendGroup2->size(); i++){ //友好的な群れとの相互作用
		Bird& rAnother = pFriendGroup2->at(i);
		float dist = pos.distance( rAnother.pos );

		if(dist < 10){
			separationVel += pos - rAnother.pos;
			separationCount++;
		}
		else if(dist < 35){
			alignmentVel += rAnother.vel.getNormalized();
			alignmentCount++;
		}
		else if(dist < 60){
			groupCenterPos += rAnother.pos;
			cohesionCount++;
		}
	}

	for(int i = 0; i < pEnemyGroup->size(); i++){   //敵対的な群れとの相互作用
		Bird& rAnother = pEnemyGroup->at(i);
		float dist = pos.distance( rAnother.pos );

		if(dist < 60){
			separationVel += pos - rAnother.pos;
			separationCount++;
		}
	}

//速度ベクトルの正規化(大きさを1にする)
	separationVel /= separationCount;
	separationVel.normalize();
	alignmentVel /= alignmentCount;
	alignmentVel.normalize();

	groupCenterPos /= cohesionCount;
	cohesionVel = groupCenterPos - pos;
	cohesionVel.normalize();

//分離、整列、結合の速度を重み付けをして速度に足しこむ
	vel += (separationVel*0.15) + (alignmentVel*0.035) + (cohesionVel*0.02);

	vel.scale(1.5);
	pos += vel;

//壁際処理:壁にぶつかると反射する。(速度の符号反転)
	if( pos.x < 0 ){
		vel.x *= -1;
	}
	else if( pos.x >= ofGetWidth() ){
		vel.x *= -1;
	}
	if( pos.y < 0 ){
		vel.y *= -1;
	}
	else if( pos.y >= ofGetHeight() ){
		vel.y *= -1;
	}
}

void Bird::draw()
{
//個体の描画
	ofSetColor(ourColor);
	ofDrawCircle(pos, head);
	ofLine(pos.x + vel.x * tail * 0.5, pos.y + vel.y * tail * 0.5, pos.x - vel.x * tail, pos.y - vel.y * tail);
}

全体の記述

ofApp.h
#pragma once

#include "ofMain.h"
#include "ofGraphics.h"
#include "Bird.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);

//個体の群れを4つ宣言
    vector<Bird> birds1;
    vector<Bird> birds2;
    vector<Bird> birds3;
    vector<Bird> birds4;
    vector<Bird> nullBirds;

    bool active; //動きの制御
};

動的配列の個数(大きさは)は、例えば、

bird1.size()

で参照できる。

新しくインスタンスを配列の末尾に追加するには、

birds.push_back()

を使う。

ofApp.cpp
#include "ofApp.h"

//4つの群れの個体数
#define BOID1 100
#define BOID2 80
#define BOID3 120
#define BOID4 50

#define BGCOLOR ofColor(0,0,0,32) // black 背景色
#define COLOR1 ofColor(255,0,0,255) // red 群れの個体の色
#define COLOR2 ofColor(0,255,0,255)  // green
#define COLOR3 ofColor(0,255,255,255) //cyan
#define COLOR4 ofColor(255,255,0,255) // yellow

#define FRATE 20 //フレームレイト

//--------------------------------------------------------------
void ofApp::setup()
{
    ofSetFrameRate(FRATE);
    ofEnableAlphaBlending();
    ofSetBackgroundColor(0,0,0);
    ofSetBackgroundAuto(false);
    ofSetCircleResolution(64);
    ofHideCursor();
    ofSetBackgroundColor(BGCOLOR);
	active = true;

    // self, enemy, friend1, friend2 群れの生成
    birds1.reserve(BOID1);
    for(int i = 0; i < BOID1; i++){
        birds1.push_back(*new Bird( &birds1, i, COLOR1, &birds2, &birds3, &nullBirds));
    }
    birds2.reserve(BOID2);
    for(int i = 0; i < BOID2; i++){
        birds2.push_back(*new Bird( &birds2, i, COLOR2, &nullBirds, &birds3, &nullBirds));
    }
    birds3.reserve(BOID3);
    for(int i = 0; i < BOID3; i++){
        birds3.push_back(*new Bird( &nullBirds, i, COLOR3, &nullBirds, &birds2, &nullBirds));
    }
    birds4.reserve(BOID4);
    for(int i = 0; i < BOID4; i++){
        birds4.push_back(*new Bird( &birds4, i, COLOR4, &birds1, &birds3, &nullBirds));
    }
}

//--------------------------------------------------------------
void ofApp::update()
{
	if(active){ //activeのがtrueのとき、群れの更新
		for(int i = 0; i < birds1.size(); i++){
			birds1[i].update();
		}
		for(int i = 0; i < birds2.size(); i++){
			birds2[i].update();
		}
		for(int i = 0; i < birds3.size(); i++){
			birds3[i].update();
		}
		for(int i = 0; i < birds4.size(); i++){
			birds4[i].update();
		}
	}   
}

//--------------------------------------------------------------
void ofApp::draw()
{
    ofSetColor(BGCOLOR);
    ofDrawRectangle(0,0, ofGetWidth(),ofGetHeight() );
    
    for(int i = 0; i < birds1.size(); i++){
        birds1[i].draw();
    }
    for(int i = 0; i < birds2.size(); i++){
        birds2[i].draw();
    }
    for(int i = 0; i < birds3.size(); i++){
        birds3[i].draw();
    }
    for(int i = 0; i < birds4.size(); i++){
        birds4[i].draw();
    }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
	switch (key){
	case ' ':
		active = !active;
		break;
	case 'f':
		ofToggleFullscreen(); //フルスクリーン切り替え
		break;
	case 's':
		ofShowCursor(); //カーソル表示
		break;
	case 'h':
		ofHideCursor(); //カーソル非表示
		break;
	default:
		break;
	}
}

参考

ジェネラティブアート論

個人用ツール
名前空間

変種
操作
案内
ツールボックス