第12回:ボスを作る(1)

 それでは更に複雑なアクションをとるであろう敵キャラ・ボスを作ってみましょう。

 今回ボスに使うテクスチャはこれです。画像ファイルのサイズ削減のため、右半分の画像だけ登録し、左半分は左右反転して描画させるようにします。メモリが潤沢に使えるようになったので、2Dではあまり使われることのなくなったテクニックですが、ご参考までに。

#pragma once
#include "EnemyBase.h"

class CBoss : public CEnemyBase
{
public:
    CBoss(void);
protected:
    virtual void Init();
    virtual void Exec();
};
#include "Boss.h"

#define BOSS_HARDNESS 500

CBoss::CBoss(void)
{
    x = 320.0f;
    y = -65.0f;

    hardness = BOSS_HARDNESS;
}

void CBoss::Init()
{
    CEnemyBase::Init();

    sprite.SetTexture((CTexture*)FindItemBox("bosstex"));
    sprite.SetSpriteSize(200, 136);
    sprite.SetCenterPosition(CP_LEFT);
}

void CBoss::Exec()
{
    if(y < 100.0f){
        y += 1.0f;
    }

    sprite.Draw(x, y);                // 右半分描画
    sprite.Draw(x, y, -1.0f, 1.0f);    // 左右反転して左半分描画

    if(this->HitTest(player) && hardness > 0){
        player->Destroy();
    }
}
 まずはこれだけの状態でタスクにCBossクラスを追加し、プログラムを実行してみましょう。

 とりあえずボス自体を表示させることには成功しました。しかし、今の状態では右半分だけ当たり判定が適用されるとともに、領域があまりにも大きすぎます。だからといって、領域を単純に縮小しただけでは、全体的に中途半端な当たり判定になってしまいます。
 四角形ひとつで表すことのできないようなキャラクターの場合、そのキャラクターを複数の領域に分け、個別に衝突判定を試みるのがベストです。

 複数の領域座標を簡単に取得したいのであれば、グラフィックソフトのイメージマップ作成機能を利用するとよいでしょう。これはもともと、HTMLで表示するイメージ内でクリックできる領域を指定するためのタグを自動作成するためのものですが、これで生成された数値は、当たり判定領域としてすぐに転用することができます。


※上記ツールはPaintShop Proです
 それでは、イメージマップ作成機能で取得した座標をもとに、当たり判定ルーチンを作成することにしましょう。
CBoss::CBoss(void)
{
    x = 320.0f;
    y = -65.0f;

    hardness = BOSS_HARDNESS;

    // 当たり判定の領域を格納
    bodyarea[0].SetRect(0,26,83,128);
    bodyarea[1].SetRect(82,46,106,66);
    bodyarea[2].SetRect(105,22,125,46);
    bodyarea[3].SetRect(126,5,148,40);
    bodyarea[4].SetRect(149,25,174,49);
    bodyarea[5].SetRect(174,40,199,69);
}

bool CBoss::HitTest(CCharactor* target)
{
    if(hardness <= 0) return false;

    RECTF trect, brect;
    target->GetHitRect(trect);

    // 本体部分との当たり判定
    for(int i = 0; i < 2; i++){
        for(int j = 0; j < 6; j++){
            brect = bodyarea[j];

            // 左半分の判定用に左右逆転させる
            if(i == 0) brect.ReverseX();

            // 領域をボスの位置に合わせる
            brect.Shift(x, y - 64.0f);
            if(brect.IsCross(&trect)) return true;
        }
    }

    return false;
}
 このプログラム修正で、ボスのアーム部分直下にキャラクターを移動しても、プレイヤーが爆発することはなくなります。