まとめ
- 円同士の衝突判定について
- 自機のショットと敵の衝突判定
はじめに
円同士の衝突判定
とりあえず
「円と円の当たり」
でググって一番上にヒットしたところを参考にする.
- 引用
判定方法
判定方法は二つの円の中心から距離を測り、その距離が二つの円の半径の和以下ならば
当たり、半径の和よりも大きければ当たっていないとなります。
とある通り.
非常に簡単で,
衝突判定の中で(おそらく)最も軽い処理で実現できる.
2点間の距離を測る公式は,
数式にするとこんな感じで,
r^2 = x^2 + y^2
それを衝突した(2点が一定の距離より小さくなった)
という条件式(if文)化するとこうなる.
if( x*x + y*y < r*r )
{
// 当たった!
}
敵とショットの衝突判定を行う
敵とショットの座標はわかっているので,
総当りチェックを行えば良い.
つまり,こんな感じ.
void ShotVSEnemy()
{
// ショットループ
for( int i = 0; i < ShotNum; i++ )
{
// エネミーループ
for( int j = 0; j < EnemyNum; j++ )
{
float x, y, r;
x = shotPosX[ i ] - enemyPosX[ j ];
y = shotPosY[ i ] - enemyPosY[ j ];
r = 32; // 雑に半径の和を決める
if( x*x + y * y < r*r )
{
// 当たった
}
}
}
}
敵の体力を減らし,消えるようにする
敵の残り体力を表す配列を用意する.
int enemyLife[ EnemyNum ] = {};
衝突が起きたらその敵の体力を減らし,
if( x*x + y * y < r*r )
{
enemyLife[j]--; // 敵体力を減らす
shotPosX[ i ] = -100; // 画面外に出す
}
敵の更新関数内で,
体力が 0 より小さくなったら,画面外に出すようにしてやれば良い.
if( enemyLife[ i ] < 0 )
{
enemyPosX[ i ] = -100; // 雑に画面外に
continue;
}
完成コード
#include "DxLib.h"
#define ShotNum 100
#define EnemyNum 10
float playerPosX = 320.0f;
float playerPosY = 340.0f;
float shotPosX[ ShotNum ];
float shotPosY[ ShotNum ];
float enemyPosX[ EnemyNum ] = {};
float enemyPosY[EnemyNum] = {};
int enemyLife[ EnemyNum ] = {};
int counter = 0;
int shotId = 0;
// 色を定義
int white = 0xffffffff;
int red = 0xffff0000;
int green = 0xff00ff00;
int blue = 0xff0088ff;
void DrawEnemy( float x, float y )
{
DrawBox(x-16, y-16, x+16, y+16, red, 0);
DrawPixel( x, y, red );
}
void DrawPlayer( float x, float y )
{
// 本体の表示
DrawBox(x-16, y-16, x+16, y+16, 0xff0088ff, 0);
}
void DrawShot( float x, float y )
{
DrawBox(x-2, y-16, x+2, y+16, 0xff0088ff, 0);
}
void ShotVSEnemy()
{
// ショットループ
for( int i = 0; i < ShotNum; i++ )
{
// エネミーループ
for( int j = 0; j < EnemyNum; j++ )
{
float x, y, r;
x = shotPosX[ i ] - enemyPosX[ j ];
y = shotPosY[ i ] - enemyPosY[ j ];
r = 32;
if( x*x + y * y < r*r )
{
enemyLife[j]--; // 敵体力を減らす
shotPosX[ i ] = -100; // 画面外に出す
}
}
}
}
void UpdateEnemy()
{
for( int i = 0; i < EnemyNum; i++ )
{
if( enemyLife[ i ] < 0 )
{
enemyPosX[ i ] = -100; // 雑に画面外に
continue;
}
DrawEnemy(enemyPosX[i], enemyPosY[i]);
enemyPosY[i] += 1;
}
}
void StartEnemy( float x, float y, int id )
{
enemyPosX[id] = x;
enemyPosY[id] = y;
}
void UpdateShot()
{
float speed = 40;
for( int i = 0; i < ShotNum; i++ )
{
shotPosY[ i ] -= speed;
DrawShot( shotPosX[ i ], shotPosY[ i ] );
}
}
void StartShot( float x, float y, int id )
{
shotPosX[id] = x;
shotPosY[id] = y;
}
void UpdatePlayer()
{
if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 )
{
playerPosX += 5;
}
if( CheckHitKey( KEY_INPUT_LEFT ) == 1 )
{
playerPosX -= 5;
}
if( CheckHitKey( KEY_INPUT_UP ) == 1 )
{
playerPosY -= 5;
}
if( CheckHitKey( KEY_INPUT_DOWN ) == 1 )
{
playerPosY += 5;
}
if( CheckHitKey( KEY_INPUT_Z ) == 1 )
{
StartShot( playerPosX, playerPosY, shotId );
shotId++;
// 100 発を超えたら 1 発目に戻す
if( shotId >= 100 )
{
shotId = 0;
}
}
DrawPlayer( playerPosX, playerPosY );
}
// プログラムは WinMain から始まります
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
//int main()
{
ChangeWindowMode( true );
if( DxLib_Init() == -1 ) // DXライブラリ初期化処理
{
return -1 ; // エラーが起きたら直ちに終了
}
for( int i = 0; i < EnemyNum; i++ )
{
StartEnemy( GetRand(500) + 32, -40*i, i );
}
// ゲームループ
while( ProcessMessage() == 0 )
{
ClearDrawScreen(); // 画面を消す
UpdatePlayer();
UpdateShot();
UpdateEnemy();
ShotVSEnemy();
counter++;
ScreenFlip(); //裏画面を表画面に反映
}
WaitKey();
DxLib_End() ; // DXライブラリ使用の終了処理
return 0 ; // ソフトの終了
}
衝突判定の更新関数を呼び出すのを忘れずに!
おわりに
敵を撃破できるようになった.
次は敵が自機狙い弾を撃ってくるようにする.