2013年8月5日月曜日

LeapMotion と openFrameworks で シューティング macアプリ

前回(Three.js)前々回(box2dweb)につづいてLeapMotionネタです。

今回はmacアプリ。つくるのは前回みたいなシューティングゲームっぽいもの。
openFrameworksを使って
そこにLeapMotionを繋いでみます。
3次元に表示にするのでopenFrameworksアドオンのofxBt を使います。
そして初めてのC++。

参考サイト

openFrameworks のプロジェクトにLeapMotionを入れる

入れるところからソースの修正から情報取得まで↑の秘密研究所さんの記事が分かりやすい。
秘密研究所さんありがとう!

僕の場合は
Library not loaded: @loader_path/libLeap.dylib
なんていうエラーが出てしまったので
superuserを参考に「Edit Scheme」から「DYLD_LIBRARY_PATH」を追加。

作るクラス

testApp.cpp, .h
openFrameowrksのプロジェクトに最初からあるやつ
LeapMotion.cpp, .h
秘密研究所さんの記事からのコピペ
Typical.cpp, .h
的クラス
Bullet.cpp, .h
弾丸クラス

的 Typical


#include <iostream>
#include "ofxBt.h"
#include <vector>
using namespace std;

class Typical{
    
// property =============================
private:
    ofxBt::RigidBody body;
    
// method ===============================
    
private:
    Typical();
    static void onDeleteTypical(Typical* typical);
    static void deleteTypical(Typical* typical);
    void update_();
    void draw_();
    ofxBt::RigidBody getBody();
    
public:
    static void createTypical();
    static void setup(ofxBt::World* world_);
    static void update();
    static void draw();
    
    ~Typical();

};

// 以下、cpp

#include "Typical.h"

// static ===================================

static ofxBt::World* world;
static vector<Typical*> typicalList;
static vector<Typical*> destroyList;
static int insNum;

void Typical::createTypical(){
    Typical* typical = new Typical();
    typicalList.push_back(typical);
};

void Typical::setup(ofxBt::World* world_){
    world = world_;
};

void Typical::update(){
    destroyList.clear();
    for(int i=0,max=typicalList.size();i<max;i++){
        typicalList[i]->update_();
    }
    for(int i=0,max=destroyList.size();i<max;i++){
        Typical::deleteTypical(destroyList[i]);
    }
};

void Typical::draw(){
    for(int i=0,max=typicalList.size();i<max;i++){
        typicalList[i]->update_();
    }
};

void Typical::onDeleteTypical(Typical* typical){
    destroyList.push_back(typical);
}

void Typical::deleteTypical(Typical* typical){
    for(int i=0,max=typicalList.size();i<max;i++){
        if(typicalList[i] == typical){
            typicalList.erase(typicalList.begin()+i);
            break;
        }
    }
    world->removeRegidBody(typical->getBody());
    
    // 破棄
    delete typical;
}

// instance ===================================

Typical::Typical(){
    ofVec3f size = ofVec3f(ofRandom(5, 15), ofRandom(5, 15), ofRandom(5, 15));
    ofVec3f pos = ofVec3f(ofRandom(-100, 100), ofRandom(-100, 100), 2000);
    ofVec2f rot = ofVec2f(ofRandom(0, 90), ofRandom(0, 90));
    body = world->addBox(size, pos, rot);
    body.setMass(0.1);
    
    ofLog() << "insNum:" << insNum << ", Typical.construct";
    insNum++;
};

Typical::~Typical(){
    ofLog() << "insNum:" << insNum << ", Typical.destruct";
    insNum--;
}

void Typical::update_(){
    body.applyForce(ofVec3f(0, 0, -15)); // 加速
    ofVec3f position = body.getPosition();
    // 吹っ飛んだら消す
    if(position.z < 0 || abs(position.z) > 2000 || abs(position.x) > 1000 || abs(position.y) > 1000){
        Typical::onDeleteTypical(this);
    }
};

void Typical::draw_(){
    
};

ofxBt::RigidBody Typical::getBody(){
    return body;
}

ずっとガベージコレクションのある言語やってたので、delete が新鮮。
メモリリーク起こさないか不安。

弾丸 Bullet

的とほぼいっしょ。


#include <iostream>
#include "ofxBt.h"
#include <vector>
using namespace std;

class Bullet{
    
    // property =============================
private:
    ofxBt::RigidBody body;
    
    // method ===============================
    
private:
    Bullet(int x, int y, ofVec3f direction);
    static void onDeleteBullet(Bullet* bullet);
    static void deleteBullet(Bullet* bullet);
    void update_();
    void draw_();
    ofxBt::RigidBody getBody();
    
public:
    static void createBullet(int x, int y, ofVec3f direction);
    static void setup(ofxBt::World* world_);
    static void update();
    static void draw();
    
    ~Bullet();
};

// 以下、cpp


#include "Bullet.h"

// static ===================================

static ofxBt::World* world;
static vector<Bullet*> bulletList;
static vector<Bullet*> destroyList;
static int insNum; // 確認用

void Bullet::createBullet(int x, int y, ofVec3f direction){
    Bullet* bullet = new Bullet(x, y, direction);
    bulletList.push_back(bullet);
};

void Bullet::setup(ofxBt::World* world_){
    world = world_;
};

void Bullet::update(){
    destroyList.clear();
    for(int i=0,max=bulletList.size();i<max;i++){
        bulletList[i]->update_();
    }
    for(int i=0,max=destroyList.size();i<max;i++){
        Bullet::deleteBullet(destroyList[i]);
    }
};

void Bullet::draw(){
    for(int i=0,max=bulletList.size();i<max;i++){
        bulletList[i]->update_();
    }
};

void Bullet::onDeleteBullet(Bullet* bullet){
    destroyList.push_back(bullet);
}

void Bullet::deleteBullet(Bullet* bullet){
    for(int i=0,max=bulletList.size();i<max;i++){
        if(bulletList[i] == bullet){
            bulletList.erase(bulletList.begin()+i);
            break;
        }
    }
    
    world->removeRegidBody(bullet->getBody());
    
    // 破棄
    delete bullet;
}

// instance ===================================

static int INIT_SPEED = 100000;
Bullet::Bullet(int x, int y, ofVec3f direction){
        
    body = world->addSphere(10, ofVec3f(x, y, 0));
    body.applyForce(ofVec3f(INIT_SPEED*direction.x, INIT_SPEED * direction.y, INIT_SPEED*direction.z));
    
    insNum++;
    ofLog() << "insNum:" << insNum << ", Bullet.construct";
};

void Bullet::update_(){
    body.applyForce(ofVec3f(0, -300, 0));
    ofVec3f position = body.getPosition();
    // 吹っ飛んだら消す
    if(abs(position.z) > 2000 || abs(position.x) > 1000 || abs(position.y) > 1000){
        Bullet::onDeleteBullet(this);
    }
};

ofxBt::RigidBody Bullet::getBody(){
    return body;
}

void Bullet::draw_(){
    
};

// destruct
Bullet::~Bullet(){
    insNum--;
    ofLog() << "insNum:" << insNum << ",Bullet.destruct";
}

メイン testApp


#include "ofMain.h"
#include "ofxBt.h"
#include "Typical.h"
#include "Bullet.h"
#include <iostream>
#include "Leap.h"
#include "LeapMotion.h"


class testApp : public ofBaseApp{
    
    private:
        LeapMotion* leapMotion;
        Leap::Controller* leapController;
        ofxBt::World* world;
        ofCamera* cam;
    
 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);
};

// 以下、cpp

#include "testApp.h"

int typicalTiming;

//--------------------------------------------------------------
void testApp::setup(){
    ofSetFrameRate(60);
	ofSetVerticalSync(true);
	ofBackground(30);
    
    // 3次元世界
    world = new ofxBt::World();
	world->setup(ofVec3f(0, 0, 0));
    world->setGravity(ofVec3f(0, 0, 0));
    
    // カメラ設定
    cam = new ofCamera();
    cam->setPosition(0, 0, 0);
    cam->lookAt(ofVec3f(0, 0, 1));
    
    // leap情報
    leapController = new Leap::Controller();
    leapMotion = new LeapMotion();
    leapController->addListener(*leapMotion);
    
    // 物体セットアップ
    Typical::setup(world);
    Bullet::setup(world);
}

//--------------------------------------------------------------
void testApp::update(){
    typicalTiming++;
    
    // 的生成
    if(typicalTiming == 30){
        Typical::createTypical();
        typicalTiming = 0;
    }
    
    // 弾丸生成
    if(typicalTiming % 5 == 0){        
        // http://taishoh-lab.net/blog/?p=203 より
        vector<Leap::FingerList> fingers = leapMotion->getFingers();
        if(!fingers.empty()){
            for(int cnt = 0; cnt < fingers.size();cnt++){
                for(int fingerNum=0; fingerNum < fingers[cnt].count();fingerNum++){
                    Leap::Finger finger = fingers[cnt][fingerNum];
                    Leap::Vector pt = finger.tipPosition();
                    Leap::Vector direction = finger.direction();
                    //なんとなく*2
                    pt.x = pt.x*2 * -1;
                    pt.y = (pt.y - 200)*2;
                    
                    Bullet::createBullet(pt.x, pt.y, ofVec3f(-direction.x, direction.y, -direction.z));
                }
            }
        }
    }
    
    Typical::update();
    Bullet::update();
    world->update();
}

//--------------------------------------------------------------
void testApp::draw(){
    cam->begin();
	
	world->draw();
    
	cam->end();
}

openFrameworks シンプルでいいなー。

openFrameworksまとめ

初めて使ったけどいい感じ。
直接書いていく感じが分かりやすい。AS3の時にBitmapに書いてた感じと似てる気がする。

アドオンも充実してて、box2dやOpenCVなんかもある。
なんとなくの知識でけっこう高度なことができそうな気がする。

そしてiphoneアプリでも使える!

C++まとめ

生成と破棄のタイミングが分からない。コピーってなんだ

vector<Typical> typicalList;
void Typical::createTypical(){
 Typical typical(); // ここで生成して
 typicalList.push_back(typical); // コピーされる
 // typicalはここのスコープを抜けた時に破棄される
}

とするとTypicalが二回生成されてしまう。
そして、コピーされるときに呼ばれるのがコピーコンストラクタっていうやつ。
良く分からん。。
int とか float とかのプリミティブの扱いと一緒なのかな。

※をつける

vector<Typical*> typicalList;
void Typical::createTypical(){
    Typical* typical = new Typical(currentId++);
    typicalList.push_back(typical);
};

とすると、いつもの感じでいける。

結論:良くわからないけど、とりあえず※つけとこう

vectorからの削除ってどうするんだ

for(int i=0,max=bulletList.size();i<max;i++){
    if(bulletList[i] == bullet){
        bulletList.erase(bulletList.begin()+i);
        break;
    }
}
delete bullet;

ググっても分からなかった。
削除はこれであってるのかな。

0 件のコメント:

コメントを投稿