地面とか(2)

つうことで続き。
地面と足の衝突判定を用いて、接地判定を行うことが出来ることがわかりました。任意のオブジェクトが地面判定を登録して構いませんし、任意のオブジェクトが足との衝突を検出しても構いません。つまり、敵キャラの上に立つことの出来るような処理が書けるし、敵キャラが地面に立つような処理も書けるということです。しかしながら、「地面に立ち、かつ、地面の判定をもつオブジェクト」などの懸念事項があります。何も考えずに実装すると、足の判定と自分自身の地面判定が衝突し続けて空高く飛び上がってしまったりします。自分を踏み台にして昇り続けるだなんて、まるで「右足が落ちる前に左足を上げ、その左足が落ちる前に右足を」みたいな話ですね。足と自分自身の地面判定の衝突は無視するような処理が必要です。

また、別の例を挙げます。私なんかは、多関節キャラを作るときに、親と子をそれぞれ別のオブジェクトとしてリストに登録して管理していまして、当然、各種判定はそれぞれ個別に登録して処理します。しかしながら、そんなふうにしてしまうと、親と子の干渉が問題になることがあって、胴体オブジェクトと腕オブジェクトとの接触判定で腕が自由に動かせなくて難儀したりするわけです。

そんなわけで、解決策は色々あるかと思いますが、私の実装では判定にユニークIDを使用することにします。いままで使ってきた構造体AtariRectを拡張しましょう。

typedef struct _tagAtariRect
{
  int left,top,right,bottom;

  unsigned int id;  // <--- ここ追加
}AtariRect;

こんな感じです。んでもって、判定をする際に

int CHanteiList::IsAtari( AtariRect* pRect )
{
  int len = pos;
  for( int idx=0; idx<len; idx++ )
  {
    AtariRect* pTarget = &(mRect[idx]);

    if(   (pRect->left   < pTarget->right)
       && (pRect->top    < pTarget->bottom)
       && (pRect->right  > pTarget->left)
       && (pRect->bottom > pTarget->top)
       && (pRect->id != pTarget->id)  )  // <--- ここ追加
    {
      return 1;
    }
  }
  return 0;
}

こんな風にユニークIDとの比較を追加するわけです。これで、自分自身と接触することが避けられますし、多関節で親子の干渉が問題になる場合は、親と子で同じIDを振ってやればOKです。なお、ユニークIDの取得は、オブジェクトの生成時に各オブジェクトに保持させて実現しています。IDがあると、何かと便利だったりしますので。

class CObjBase
{
public:
  CObjBase(){mId = staticId++;};
  unsigned int GetId(){return mId;};

private:
  unsigned int mId;

  static unsigned int staticId;
};

unsigned int CObjBase::staticId = 0;

オブジェクトクラスを上みたいのから派生させてあげれば、GetId()で何も考えずにIDがとってこれるってあんばいです。4バイトとかあるIDを枯渇させるようなオブジェクトが生まれるなんてアプリはつくらないでね!

そいじゃまた。