読者です 読者をやめる 読者になる 読者になる

The jonki

呼ばれて飛び出てじょじょじょじょーんき

コード解説

Particleクラス

ただのofCircleによる円描画ですが、色々と遊びの要素を入れています。

testAppクラス

メインのクラスで、oscによるメッセージを受け取ります。
今回はTouchOSCというiPhoneのフリーの
アプリからOSCで送られてくる情報をもとに、Particleクラスに対して色々とアクションを投げかけています。

Particle.h

//
//  Particle.h
//  emptyExample
//
//  Created by jonki on 12/11/08.
//  Copyright (c) 2012年 jonki.net. All rights reserved.
//

#ifndef PARTICLE_H_
#define PARTICLE_H_

#include "ofMain.h"


class Particle
{
public:
    Particle(float x, float w);
    void update();
    void draw();
    
    void setTargetPosition(int x, int y);
    void expand();
    inline void setRadius(float radius) { m_radius = radius; };
    inline void setAlpha(float alpha) { m_alpha = alpha; };
    
private:
    float           m_x;                //!< particle x position
    float           m_y;                //!< particle y position
    
    float           m_expand;           //!< radius expand param
    
    ofPoint         m_speed;            //!< particle speed
    float           m_radius;           //!< particle radius 
    float           m_alpha;            //!< particle color alpha
    
    ofPoint         m_targetPos;        //!< destination for moving
    bool            m_isSetTargetPos;   //!< check new targetPos is set

};
#endif

Particle.cpp

//
//  Particle.cpp
//  emptyExample
//
//  Created by jonki on 12/11/08.
//  Copyright (c) 2012年 jonki.net. All rights reserved.
//

#include "Particle.h"

Particle::Particle(float x, float y)
: m_x(x)
, m_y(y)
, m_speed(ofPoint(ofRandom(-8.f, 8.f), ofRandom(-5.f, 5.f)))
, m_radius(0.3f)
, m_alpha(1.f)
, m_targetPos(ofPoint(0.f, 0.f))
, m_isSetTargetPos(false)
{
}
            
            
void Particle::update()
{
    //!< 画面端に出たらバウンドするように
    if(m_x > (float)ofGetWidth() || m_x < 0.f)
    {
        m_speed.x *= -1;
    }
    if(m_y > (float)ofGetHeight() || m_y < 0.f)
    {
        m_speed.y *= -1;
    }
    
    //!< 新しい目標座標がセットされてたら
    if(m_isSetTargetPos)
    {
        //!< 目標座標へ1割近づく計算
        m_speed.x = 0.9f * m_speed.x + 0.1f * (m_targetPos.x - m_x);
        m_speed.y = 0.9f * m_speed.y + 0.1f * (m_targetPos.y - m_y);
        
        //!< なんとなく遅くしてみる
        m_speed.x *= 0.5f;
        m_speed.y *= 0.5f;
        
        m_isSetTargetPos = false;
    }
    
    
    //!< 目標座標に近づける、乱数もちょっと足してばらけさせる
    m_x += (m_speed.x + ofRandom(-6.f, 6.f));
    m_y += (m_speed.y + ofRandom(-6.f, 6.f));

    //!< 5%ずつ減衰するようにする
    m_expand *= 0.95f;
    if (m_expand < 1.f) m_expand = 1.f;
}
            

void Particle::draw()
{
    //!< 色とかの情報をこの中だけに適用する
    //!< 適用範囲が他のクラスなどに影響しないので、とりあえずかけておくべし
    ofPushStyle();  
    {
        //!< 座標に応じたシャレ乙カラーリング
        //!< ofMapは値を好みの範囲にマッピングした値を返す
        //!< ofMap(inVal, inMaxVal, inMaxVal, outMinVal, outMaxVal)
        int r = ofMap(m_x, 0, ofGetWidth(), 0, 255);
        int g = ofMap(m_y, 0, ofGetHeight(), 0, 255);
        int b = 100;
        
        ofSetColor(r, g, b, 255.f * m_alpha);
        ofPushMatrix(); //!< glPushMatrix()的な
        {
            //!< particleのポジションはofTranslateで決めるようにする
            //!< ofCircleのパラメタで指定しても良い
            ofTranslate(m_x, m_y);
            ofCircle(0.f, 0.f, ofRandom(20.f, 40.f) * m_radius * m_expand);
        }
        ofPopMatrix();
    }
    ofPopStyle();
}

void Particle::setTargetPosition(int x, int y)
{
    m_targetPos.x = x;
    m_targetPos.y = y;
    m_isSetTargetPos = true;
}

void Particle::expand()
{
    //!< particleの一気に半径が4.5倍になる
    //!< m_expandはupdate()で減衰し、最終的には1.fになる
    m_expand = 4.5f;
}

testApp.h

#include "ofMain.h"
#include "ofxOsc.h"

#include "Particle.h"

#include <vector>


typedef std::vector<Particle*>::iterator p_itr;

class testApp : public ofBaseApp{
public:
    void setup();
    void update();
    void draw();
    void exit();
    
    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:
    std::vector<Particle*>      m_particles;
    ofxOscReceiver              m_receiver;
    ofSoundPlayer               m_se;
    ofSoundPlayer               m_bgm;
};

testApp.cpp

//--------------------------------------------------------------
void testApp::setup(){
    ofSetFrameRate(60);
    ofBackground(0, 0, 0);
    ofEnableAlphaBlending();
    
    for (int i=0; i<100; i++) {
        m_particles.push_back(new Particle(ofRandom(ofGetWidth()), ofRandom(ofGetHeight())));
    }
    
    //!< set PORT
    m_receiver.setup(9000);    
}

//--------------------------------------------------------------
void testApp::update(){
    for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
    {
        (*it)->update();
    }
    
    while(m_receiver.hasWaitingMessages())
    {
        ofxOscMessage msg;
        m_receiver.getNextMessage(&msg);
        //!< ex) addr => "/1/push3"
        string addr = msg.getAddress();
        
        //!< TouchOSCのアドレスに合わせる
        std::vector<string>splitAddr = ofSplitString(addr, "/");
        if(splitAddr.size() != 3) break;
        
        //!< "/1/push/3" => addrIndex = 1
        int addrIndex = ofToInt(splitAddr[1]);
        
        //!< button address
        std::vector<string>splitCommand = ofSplitString(splitAddr[2], "push");
        if(splitCommand.size() == 2)  //!< ex) "/1/push3"
        {
            m_se.loadSound("se/" + splitCommand[1] + ".mp3");   //!< unkode
            m_se.play();
            for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
            {
                (*it)->expand();
            }
            break;  //!< 処理するアドレスは1個だけ
        }
        
        //!< fader address
        splitCommand = ofSplitString(splitAddr[2], "fader");
        if(splitCommand.size() == 2)
        {
            int num = ofToInt(splitCommand[1]);
            if (num == 1)
            {
                for(p_itr it = m_particles.begin();
                    it != m_particles.end(); ++it)
                {
                    (*it)->setAlpha(msg.getArgAsFloat(0));
                }
            }
            else if (num == 2)
            {
                for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
                {
                    (*it)->setRadius(msg.getArgAsFloat(0));
                }
            }
            break;  //!< 処理するアドレスは1個だけ
        }
        
        //!< xy position address
        if(splitAddr[2] == "xy")
        {
            float x = msg.getArgAsFloat(1) * ofGetWidth();
            float y = (1.f - msg.getArgAsFloat(0)) * ofGetHeight();
            for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
            {
                (*it)->setTargetPosition(x, y);
            }
            break;  //!< 処理するアドレスは1個だけ
        }   
    }
}

//--------------------------------------------------------------
void testApp::draw(){
    for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
    {
        (*it)->draw();
    }
}

void testApp::exit()
{
    for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
    {
        delete (*it);
        *it = 0;
    }
}

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

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
    for(p_itr it = m_particles.begin(); it != m_particles.end(); ++it)
    {
        (*it)->setTargetPosition(x, y);
    }
}