2014年12月15日月曜日

ofxStateMachineおぼえがき

openFrameworksでの複数のシーンの切り替えに便利なofxStateMachineの使い方をようやく理解したのでここに書いてみます。

アドオンはここからダウンロード
https://github.com/neilmendoza/ofxStateMachine

まずprojectGeneratorでofxStateMachineをアドオンとして含むプロジェクトを作成。
srcに切り替えるシーン用のクラスを作成します。
今回はstateA, stateB, stateCの三つを作成



ofApp.hにofStateMachineをインクルードして、インスタンス化します

#pragma once

#include "ofMain.h"
#include "ofxStateMachine.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);
  
    
    itg::ofxStateMachine<> stateMachine; //アドオンをインスタンス化
};

 
次にofApp.cppに、切り替えるシーン全てをインクルードし、setup()にstateMachine.addState<クラス名>();の形式で追加します。

#include "ofApp.h"
#include "stateA.h"//シーンのインクルード
#include "stateB.h"
#include "stateC.h"

//--------------------------------------------------------------
void ofApp::setup(){
    //sharedDataの初期化
    stateMachine.addState();  //シーンの追加
    stateMachine.addState();
    stateMachine.addState();
    
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){

}

 
これでofAppでの設定は終わりです。

次に、切り替える三つのシーンの内容を書いていきます。
シーンのヘッダーフォルダでは必ずofxState.hをインクルードし、クラスの中でofxStateを継承できるようにします。
また、シーンの切り替えで使う状態名を宣言するためにstring getName()関数を書いておきます。

#pragma once
#include "ofxState.h"

class stateA : public itg::ofxState<>{ //ofxStateを継承
    
    void setup();
    void update();
    void draw();
    void mousePressed(int x, int y, int button);
    string getName(); //状態の名前を返す関数
    
};
 

cppにシーンの内容を描写し、シーンの切り替え用の状態名を以下の形式で書きます

string クラス名::getName(){
    return "状態名";

}


#include "stateA.h"

//--------------------------------------------------------------
void stateA::setup(){
    
}

//--------------------------------------------------------------
void stateA::update(){
    
}

//--------------------------------------------------------------
void stateA::draw(){
    ofBackground(0,0,0);
    ofSetColor(255, 0, 0);
    ofCircle(ofGetWidth()/2, ofGetHeight()/2, 200);
    

string stateA::getName(){
    return "stateA";
}

 
同じようにstateBとStateCクラスも作ります


<切り替えの方法>
さて、先ほど宣言した状態名を使って、シーンの切替方法を設定したいと思います。
切り替えには以下の関数を利用します

changeState("切り替え先の状態名")

今回は、左上に三つのボタンを設置し、そこをクリックすることでそれぞれのシーンを表示できるようにしたいと思います。
まずはofApp.cppで最初に表示するシーンを呼び出します。

#include "ofApp.h"
#include "stateA.h"//シーンのインクルード
#include "stateB.h"
#include "stateC.h"

//--------------------------------------------------------------
void ofApp::setup(){
    //sharedDataの初期化
    stateMachine.addState();  //シーンの追加
    stateMachine.addState();
    stateMachine.addState();
    
    stateMachine.changeState("stateA");//最初に呼び出すシーン
    
}

 
それぞれのクラスで、シーンの呼び出し方を指定します

#include "stateA.h"

//--------------------------------------------------------------
void stateA::setup(){
    
}

//--------------------------------------------------------------
void stateA::update(){
    
}

//--------------------------------------------------------------
void stateA::draw(){
    ofBackground(0,0,0);
    ofSetColor(255, 0, 0);
    ofCircle(ofGetWidth()/2, ofGetHeight()/2, 200);
    //ボタン
    ofSetColor(255, 0, 0);
    ofRect(10, 10, 50, 50);
    ofSetColor(0, 255, 0);
    ofRect(70, 10, 50, 50);
    ofSetColor(0, 0, 255);
    ofRect(130, 10, 50, 50);
    
}

string stateA::getName(){
    return "stateA";
}

void stateA::mousePressed(int x , int y, int button){
    //クリックした時に呼び出す
    if (10 < x && x < 60 && 10 < y && y < 60) {
        changeState("stateA");
    }
    
    if (70 < x && x < 120 && 10 < y && y < 60) {
        changeState("stateB");
    }
    
    if (130 < x && x < 180 && 10 < y && y < 60) {
        changeState("stateC");
    }
    
}


 

stateBとstateCでも同じように指定します。

すると、以下の画像の左上の簡単なボタンを押すことで、シーンの切り替えが行えるようになります。