ややプログラム紀行

博士2年のプログラムに関する日記

Havok 接触イベント編

最近全然更新してなかったので、まじめにプログラム系の記事でも書いてみます

前Havokを必要最低限使えるところまで持ってくっていうのはやったんですけど、あれからもちょっといじって、接触イベント周りは記事にできるくらいには使えるようになったと思います

・前準備

最低限hkpRigidBodyを作ってHavokの世界に登録できないと当然接触判定なんてできないっす

前回書いた記事参照してもらえると助かります

・ヘッダーファイル

#include <Physics/Dynamics/Collide/ContactListener/hkpContactListener.h>

多分これだけで十分です

足りなかったらごめんなさいm(__)m

Havokはヘッダーファイルが用途ごとに凄く細かく分かれてるんで、ヘッダーをいちいち書かないといけないのがだるい

・使い方

この接触イベント判定ふくめ、イベント検出系は大体やり方が決まっていて、Havok側が用意したクラス(~Listenerって名前が多いです)を自分で継承したクラスを作って、仮想関数を自分で実装するって流れになります

・クラスの定義

// 接触検出リスナー

class MyContactListener : public hkReferencedObject, public hkpContactListener

{

public:

void contactPointCallback( const hkpContactPointEvent& event ); // 接触時に呼ばれる

};

これだけでいいです、最低限っすけどね

実装に関しては、特に決まりは無いっぽいです、なので空白でも多分イイ

というか元クラスのhkpContactListenerの方で、関数は大体空白定義されてるので、もう定義部分は書かなくてもいいんじゃねっていう(確かめてないです、無責任です

・クラスの登録

hkpRigidBody* myRigidBody; // 接触リスナーを登録するオブジェクト

/*hkpRigidBodyの作成 詳しくは前回の記事で*/

myListener = new MyContactListener;

myRigidBody->addContactListener(myListener);

hkpWorldの方にもaddContactListener関数があったので、できるんじゃないでしょうか

安定の未確認です\(^o^)/

今回の例だと、myRigidBodyに物体が衝突したときにMyContactListenerのcontactPointCallback関数が呼ばれる仕組みです

・後処理

myRigidBody->removeContactListener(myListener);

myListener->removeReference();

myRigidBody->removeReference();

どうやら、リスナーの後処理をする場合、hkpRigidBodyを消す前にやる必要があるみたいです(上の順番)

でも、こんなこと言っちゃあれなんですが、ゲーム終了時にメモリ開放するとかそんなパターンだったら、もう解放しないっていうのもアリなんじゃないかと思います

別に開放しなくてもエラーにはならない(むしろ二重で開放したり、順番間違えるとエラー)し、メモリリークとかも気にする必要ないので敢えて目をつむるっていうのもね

・その他のこと

・hkpContactPointEventからhkpRigidBodyを取り出す

int size = sizeof(event.m_bodies) / sizeof(event.m_bodies[0]);

for(int i = 0; i < size; i++){

hkpRigidBody* contactBody = const_cast(event.getBody(i));

}

ぶっちゃけここは超疑惑のコードです

まず、const_castでconstを外して取得してます

const外すとかアホ!?って言われそうですが、サンプルにはそう書いてあったしなあ・・・

yaruo.png

しかもこれ、接触オブジェクトは1つでも、必ず「レイヤーA」というオブジェクトと本体の二つ反応します

つまり上のforループは2回まわるってことです

サンプルコードにはevent.getBody(event.m_source);っていう書き方でhkpRigidBodyを取得してたんですけど、このm_sourceっていうのが何なのかわからないんですよねー

どういうのものかプログラム見てみると、SOURCE_A, SOURCE_B, SOURCE_WORLDっていうやつらのenum型という・・・

hkpWorldにこの接触リスナーを登録するとSOURCE_WORLDになるような気はするんですけど、残りのAとBは何だ・・・

レイヤーAと関係がありそうですが、いまいちよくわかりません、どなたか知ってる人がいらっしゃいましたらご教授お願いしますm(__)m

・物理的な衝突をやめる

event.m_contactPointProperties->m_flags |= hkContactPointMaterial::CONTACT_IS_DISABLED;

これを書くと”物理的な”衝突が起こらなくなります、まあすり抜ける感じです

ただ勘違いしてはいけないのが、衝突検出はなくならないっていうことです

なので、すり抜けてる間はずっと接触判定が起こることになります

僕は接触検出をしなくなる方法をしりたい・・・orz

とりあえず衝突検出周りを書いてみました

これで少なくとも検出は出来るようになると思います

でもこれだけだと、床の上にオブジェクトがある場合、毎回呼ばれて他のオブジェクトと区別をどうつけるかだとか、いろいろやることはあるので、それはまた別の記事で書こうと思います

あー日付変わってた・・・こんなこと言うと書く意味あるのかってなりますけど、もっと詳しく知りたい方は、HavokSDK付属のドキュメントを見てみてくださいww