座標も当たり判定オブジェクトとエネミーは別々にもたせます。
//"Collision.h"
namespace Collision{
enum {
OBJECT_TYPE_ENEMY ,
OBJECT_TYPE_PLAYER ,
OBJECT_TYPE_BULLET ,
OBJECT_TYPE_ITEM ,
COLLISION_NORMAL ,
COLLISION_HIT_ATTACK ,
COLLISION_HIT_ITEM ,
USER_PLAYER ,
USER_ENEMY ,
};
// 円形コリジョンオブジェクト
// 物体オブジェクトの衝突判定はすべてこれを経由する
class Circle{
private :
Vector pos;
float radius;
struct{
unsigned int objectId : 8; // オブジェクトID
unsigned int objectType : 8; // オブジェクト種類(エネミー、プレイヤー、弾幕、アイテムなど)
unsigned int user : 8; // 衝突判定オブジェクトの所持者
unsigned int collisionType : 8; // 衝突判定タイプ。通常の衝突、アイテムオブジェクト衝突、ダメージオブジェクト衝突など
unsigned int handleId : 30;
unsigned int isHit : 1;
unsigned int isActive : 1;
};
public :
Circle();
~Circle();
bool IsHit() { return isHit; }
bool IsActive() { return isActive; }
int getObjectId() { return objectId; }
int getObjectType() { return objectType; }
int getUser() { return user; }
int getCollisionType() { return collisionType; }
void disableCollision ();
void enableCollision ();
void setup ( int objectId , int objectType , int user , int collisionType );
void setPoint ( float x , float y , float radius );
void setPoint ( float x , float y );
bool checkCollision ( float x , float y , float radius );
bool checkCollision ( Circle* c );
void onHit();
void relHit();
virtual void draw();
};
// 攻撃判定コリジョン
// キャラクターオブジェクトへのダメージを与える
class HitAttack : public Circle{
private :
int damage;
public :
HitAttack()
{
damage = 0;
}
void setDamage( int damage ) { this->damage = damage; }
int getDamage() { return damage; }
};
// アイテム判定コリジョン
// アイテムによるパワーアップ、エクステンド、ボム増加などをコントロールする
class HitItem : public Circle{
private :
// 4バイト
struct{
unsigned int pow : 15;
unsigned int bonus : 15;
unsigned int extend : 1;
unsigned int bomb : 1;
};
public :
void setPowerUp ( int pow ){ this->pow = pow; }
void setExtend ( int extend ){ this->extend = extend; }
void setBomb ( int bomb ){ this->bomb = bomb; }
void setBonus ( int bonus ){ this->bonus = bonus; }
};
void initialize();
void update();
}
今後アイテムやエネミーなど種類が増えても
このオブジェクトをそれぞれのフィールドで生成するだけで当たり判定が取れるようになります。
判定タイプはいろいろあって、STGの場合は
・判定したらダメージを与える
・判定したらアイテム処理をする
などがあるのであらかじめそういったクラスは作っておきます。
ダメージ判定をプレイヤーやエネミーに指定したい場合はHitAttackクラスを持てば
設定したパラメータだけのダメージを指定のオブジェクトに与えられるし
アイテム判定を持たせれば指定した数値分のボーナスポイントやボム追加やエクステンドが行えます。
// Collision.cpp
#define MAX_HANDLER 15000
#define COLL_MAN CollisionManager::getInstance()
namespace Collision{
// ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□
// 衝突判定マネージャー
class CollisionManager{
private :
Circle* Handler[MAX_HANDLER];
CollisionManager()
{
initialize();
printf( "initialize \n" );
}
// 空いているハンドルを取得する。
// どこも空いていない場合はダミーとして設定されている0番を渡す。
int getHandleId( Circle* c )
{
for( int i = 1 ; i IsActive() ){
continue;
}
c->relHit();
for( int j = 1 ; j IsActive() ){
continue;
}
if( c != c2 ){
if( c->checkCollision( c2 ) ){
onHitEvent( c , c2 );
}
}
}
}
}
// 衝突判定イベント処理。
// オブジェクトの所持者情報によって処理が変化する
void onHitEvent( Circle* c1 , Circle* c2 )
{
c1->onHit();
if( c1->getObjectType() == OBJECT_TYPE_ENEMY )
{
if( c2->getObjectType() == OBJECT_TYPE_BULLET && c2->getUser() == USER_PLAYER )
{
if( c2->getCollisionType() == COLLISION_HIT_ATTACK )
{
HitAttack* attack = ( HitAttack* )c2;
Enemies::collisionAttack( c1->getObjectId() , attack ); // 指定のエネミーIDにダメージ情報ハンドリング
}
}
}
else if( c1->getObjectType() == OBJECT_TYPE_PLAYER )
{
if( c2->getObjectType() == OBJECT_TYPE_BULLET && c2->getUser() == USER_ENEMY )
{
if( c2->getCollisionType() == COLLISION_HIT_ATTACK )
{
HitAttack* attack = ( HitAttack* )c2;
// Player::collisionAttack( c1->getObjectId() , attack );
}
}
else if( c2->getObjectType() == OBJECT_TYPE_BULLET )
{
if( c2->getCollisionType() == COLLISION_HIT_ITEM )
{
HitItem* item = ( HitItem* )c2;
// Player::collisionItem( c1->getObjectId() , item );
}
}
}
else if( c1->getObjectType() == OBJECT_TYPE_BULLET )
{
}
else if( c1->getObjectType() == OBJECT_TYPE_ITEM )
{
}
}
};
// ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□
// Circle
Circle::Circle()
{
pos.x = 0;
pos.y = 0;
radius = 0;
handleId = 0;
isHit = false;
isActive = true;
handleId = COLL_MAN.setupHandler( this );
objectId = 0;
objectType = 0;
user = 0;
collisionType = 0;
printf( "setup id = %d \n" , handleId );
}
Circle::~Circle()
{
COLL_MAN.freeHandler( handleId );
printf( "free id = %d \n" , handleId );
}
void Circle::disableCollision()
{
isActive = false;
}
void Circle::enableCollision()
{
isActive = true;
}
void Circle::setup( int objectId , int objectType , int user , int collisionType )
{
this->objectId = objectId;
this->objectType = objectType;
this->user = user;
this->collisionType = collisionType;
}
void Circle::setPoint( float x , float y , float radius )
{
this->pos.x = x;
this->pos.y = y;
this->radius = radius;
}
void Circle::setPoint( float x , float y )
{
this->pos.x = x;
this->pos.y = y;
}
bool Circle::checkCollision( float x , float y , float radius )
{
if( !isActive ){
return false;
}
float xx = this->pos.x - x;
float yy = this->pos.y - y;
float rr = this->radius + radius;
if( ( xx * xx ) + ( yy * yy ) pos.x , c->pos.y , c->radius );
}
void Circle::onHit()
{
isHit = true;
}
void Circle::relHit()
{
isHit = false;
}
void Circle::draw()
{
DrawCircle( (int)pos.x , (int)pos.y , (int)radius , 0xAAAAAA , FALSE );
}
// 公開グローバル関数
void initialize()
{
COLL_MAN.getInstance();
}
void update()
{
COLL_MAN.update();
}
}
マネージャークラス内で処理を行い、
指定した番号のオブジェクトに対してダメージイベントを呼び出す、といった感じです。
エネミーの実装はこんな感じ
// EnemyObject.h
// 挙動のベースクラス。
// 移動パターンはここを派生して記述する
class EnemyBase : public Test::EnemyObject{
private :
int hp; // 体力
Visual visual; // ビジュアル
Vector pos; // 座標
Collision::Circle coll; // 衝突判定
int objectId; // オブジェクト番号
public :
EnemyBase( float x , float y , int ENEMY_ID );
~EnemyBase();
int getObjectId();
virtual void damage( int damage );
virtual void update();
virtual void draw();
};
void collisionAttack( int objectId , Collision::HitAttack* attack );
void initialize();
// EnemyObject.cpp
namespace Enemies{
// ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□
// 内部マネージャー
class EnemyManager{
private :
EnemyBase* Handler[MAX_ENEMY+1]; // エネミーへのイベントハンドラー
EnemyManager()
{
initialize();
}
public :
static EnemyManager getInstance()
{
static EnemyManager instance;
return instance;
}
void initialize()
{
memset( Handler , NULL , sizeof( Handler ) );
}
EnemyBase* findEnemyById( int objectId )
{
for( int i = 1 ; i getObjectId() == objectId ){
return Handler[i];
}
}
return Handler[0];
}
int entryEnemyHandler( EnemyBase* enemy )
{
for( int i = 1 ; i damage( attack->getDamage() );
}
}
void initialize()
{
ENEMY_MAN.initialize();
}
}
実験的にやってみているということでここはひとつ