openFrameworks – パーティクルを動かしてみた

openFrameworks – パーティクルを動かしてみた

oFの勉強として、まずはパーティクルのアニメーションを実装してみました。

of-test01 from asialounge on Vimeo.

アニメーションは衝突+反射+バネ+摩擦のロジックで実装。
また、画面タップ時に、タップしたポイントへパーティクルが集まってくるインタラクションも実装。

#define NUM 100 //パーティクルの数
float posX[NUM]; //パーティクルのx座標
float posY[NUM]; //パーティクルのy座標
float speedX[NUM]; //パーティクルのx方向の移動量
float speedY[NUM]; //パーティクルのy方向の移動量
float radius[NUM]; //パーティクルの半径
float bounce = -1.0; //反射の係数
float friction = 0.95; //摩擦の係数
float spring = 0.4; //バネの係数
int red[NUM];
int green[NUM];
int blue[NUM];
bool isMousePressed;

//--------------------------------------------------------------
void ofApp::setup() {
    ofSetBackgroundAuto(NO);
    ofBackground(0, 0, 0);
    ofSetFrameRate(60);
    ofSetCircleResolution(64);
    ofEnableSmoothing();
    isMousePressed = NO;
    for (int i=0; i<NUM; i++) {
        posX[i] = ofRandom(0, ofGetWidth());
        posY[i] = ofRandom(0, ofGetHeight());
        speedX[i] = ofRandom(-4, 4);
        speedY[i] = ofRandom(-4, 4);
        radius[i] = ofRandom(5, 15);
        red[i] = ofRandom(0, 255);
        green[i] = ofRandom(0, 255);
        blue[i] = ofRandom(0, 255);
    }
}

//--------------------------------------------------------------
void ofApp::update() {
    for (int i=0; i<NUM; i++) {
        for (int j=i+1; j<NUM; j++) {
            float dx = posX[j] - posX[i];
            float dy = posY[j] - posY[i];
            float dist = sqrt(dx * dx + dy * dy);
            float minDist = radius[i] + radius[j];

            if (dist < minDist) {
                float angle = atan2(dy, dx);
                float tx = posX[i] + cos(angle) * minDist;
                float ty = posY[i] + sin(angle) * minDist;
                float ax = (tx - posX[j]) * spring;
                float ay = (ty - posY[j]) * spring;
                speedX[i] -= ax;
                speedY[i] -= ay;
                speedX[j] += ax;
                speedY[j] += ay;
                speedX[i] *= friction;
                speedY[i] *= friction;
                speedX[j] *= friction;
                speedY[j] *= friction;
            }
        }
    }

    for (int i=0; i<NUM; i++) {
        if (isMousePressed) {
            speedX[i] = (mouseX - posX[i]) * 0.1;
            speedY[i] = (mouseY - posY[i]) * 0.1;
        }
        posX[i] += speedX[i];
        posY[i] += speedY[i];
        if (posX[i] - radius[i] < 0){
            posX[i] = radius[i];
            speedX[i] *= bounce;
        }
        else if (posX[i] + radius[i] > ofGetWidth()) {
            posX[i] = ofGetWidth() - radius[i];
            speedX[i] *= bounce;
        }
        if (posY[i] - radius[i] < 0) {
            posY[i] = radius[i];
            speedY[i] *= bounce;
        }
        if (posY[i] + radius[i] > ofGetHeight()) {
            posY[i] = ofGetHeight() - radius[i];
            speedY[i] *= bounce;
        }
    }
}

//--------------------------------------------------------------
void ofApp::draw() {
    ofSetColor(0, 0, 0, 23);
    ofRect(0, 0, ofGetWidth(), ofGetHeight());
    for (int i=0; i<NUM; i++) {
        ofSetColor(red[i], green[i], blue[i]);
        ofCircle(posX[i], posY[i], radius[i]);
    }
}

//--------------------------------------------------------------
void ofApp::touchUp(ofTouchEventArgs & touch) {
    isMousePressed = NO;
    for (int i=0; i<NUM; i++) {
        speedX[i] = ofRandom(-5, 5);
        speedY[i] = ofRandom(-5, 5);
    }
}

次回は音や映像の取り込み方について勉強してみたいと思います。

TAG

  • このエントリーをはてなブックマークに追加
意識 高丸
エンジニア 意識 高丸 takamaru

Rubyについて日々勉強している新人エンジニアです。初心者向けRuby勉強会のレポートなどを投稿していきます。