ページ 1 / 1
敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 20:36
by 葉月
初投稿です。よろしくお願いします!!。
いま自分は2Dのゲームを作っているのですが弾が出るようになったんですけど敵に当たり判定がないため敵を倒すことが出来ません。
どうやったら敵に当たり判定を付けることができるのでしょうか?
どうしても、わからないので質問しました。
宜しくお願いします!
プレイヤーは攻撃したり、ジャンプわ出来るようになってます。
いちよう、足場も作ったりしてみました。
ソースコードも載せるのでお願いします。
プログラムはガチ初心者ですので、その辺わかってくれると助かります。。
コード:
/////////////////////////////////////////////
///...インクルード
/////////////////////////////////////////////
#include "FPSsample.h"
#include "enemy.h"
#include "bullet.h"
////////////////////////////////////////////
///...マクロ定義(defineなど)
////////////////////////////////////////////
#define MAX_ENEMY (100)
ENEMY g_aEnemy[MAX_ENEMY];
/*-----------------------------------
関数名 :InitEnemy
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void InitEnemy()
{
for(int nLoop = 0 ; nLoop < MAX_ENEMY ; nLoop++ )//敵の数だけループ
{
g_aEnemy[nLoop].bUse = false;
//その他は全て0にする
}
SetEnemy(10.0f , 21.0f , 0); //敵作成
SetEnemy(52.0f , 11.0f , 0);
SetEnemy(43.0f , 12.0f , 0);
SetEnemy(44.0f , 11.0f , 0);
SetEnemy(45.0f , 23.0f , 0);
}
/*-----------------------------------
関数名 :UninitEnemy
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void UninitEnemy()
{
;
}
/*-----------------------------------
関数名 :UpdateEnemy
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void UpdateEnemy()
{
for(int nLoop = 0 ; nLoop < MAX_ENEMY ; nLoop++ )//敵の数だけループ
{
if(g_aEnemy[nLoop].bUse)//構造体が使用中
{
if((rand()%100) == 10)
{
SetBullet(g_aEnemy[nLoop].fPosX + g_aEnemy[nLoop].fMoveX + (g_aEnemy[nLoop].fDirect *2)
, g_aEnemy[nLoop].fPosY , -0.6f, 0.0f , BULLETTYPE_ENEMY);
}
}
}
}
/*-----------------------------------
関数名 :DrawEnemy
機能 :敵の表示
引数 :void
戻り値 :int
-----------------------------------*/
void DrawEnemy()
{
for(int nLoop = 0 ; nLoop < MAX_ENEMY ; nLoop++)//敵の数だけループ
{
if(g_aEnemy[nLoop].bUse)//構造体使用中
{
COLOR(BLUE);
LOCATE((int)g_aEnemy[nLoop].fPosXOId, (int)g_aEnemy[nLoop].fPosYOId);//前回の位置
printf(" ");
LOCATE((int)g_aEnemy[nLoop].fPosXOId, (int)g_aEnemy[nLoop].fPosYOId - 1);//前回の位置の一つ上
printf(" ");
LOCATE((int)g_aEnemy[nLoop].fPosX, (int)g_aEnemy[nLoop].fPosY);//現在位置
printf("");
LOCATE((int)g_aEnemy[nLoop].fPosX, (int)g_aEnemy[nLoop].fPosY - 1);//現在位置の一つ上
printf("H");
}
}
}
/*-----------------------------------
関数名 :SetEnemy
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void SetEnemy(float posx ,float posy , int type)
{
for(int nLoop = 0 ; nLoop < MAX_ENEMY ; nLoop++ )//敵の数ループ
{
if(!g_aEnemy[nLoop].bUse)//構造体未使用
{
g_aEnemy[nLoop].fPosX = posx;
g_aEnemy[nLoop].fPosY = posy;
g_aEnemy[nLoop].fPosXOId = posx;
g_aEnemy[nLoop].fPosYOId = posy;
g_aEnemy[nLoop].fMoveX = 0;
g_aEnemy[nLoop].fMoveY = 0;
g_aEnemy[nLoop].fDirect = -1.0; //とりあえず左向き固定
g_aEnemy[nLoop].nType = type;
g_aEnemy[nLoop].bUse = true;
break;//構造体を作ったら終了
}
}
}
/*-----------------------------------
関数名 :fDirect
機能 :敵の当たり判定
引数 :void
戻り値 :int
-----------------------------------*/
void DirectEnemy();
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 20:43
by 葉月
いちよう今までに書いたプログラムも載せてみます。。。
見づらかったらすみません。
コード:
/////////////////////////////////////////////
///...インクルード
/////////////////////////////////////////////
#define _CRT_SECURE_NO_DEPRECATE
/////////////////////////////////////////////
///...インクルード
/////////////////////////////////////////////
#include "FPSsample.h"
#include "player.h"
#include "field.h"
#include "Bullet.h"
#include "enemy.h"
#include "stdio.h"
#include "taitoru.h"
#include "bgm.h"
#ifdef _DEBUG
void DispFPS();
void bgm_Date();
#endif
int g_nCountFPS;
/*-----------------------------------
関数名 :main
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void main()
{
//タイトルの変更
SetConsoleTitleA("FPSテスト FPSを表示させるプログラム");
TAITORU();
int nExecLastTime;
int nFPSLastTime;
int nCurrentTime;
int nFrameCount;
timeBeginPeriod(1); //ハードウェアタイマーの初期化
nExecLastTime = nFPSLastTime = timeGetTime(); //現在時刻取得
nCurrentTime = nFrameCount = 0;
InitPlayer(); //プレイヤーの初期化
InitField();
InitBullet();
InitEnemy();
//弾発射
//SetBullet( , , , , BULLETTYPE_PLAYER);
CUROFF(); //カーソル非表示
DrawField();
//メインループ
do
{
nCurrentTime = timeGetTime();
if((nCurrentTime - nFPSLastTime) >= 500)
{
g_nCountFPS = nFrameCount * 1000 / (nCurrentTime - nFPSLastTime);
nFPSLastTime = nCurrentTime;
nFrameCount = 0;
}
if((nCurrentTime - nExecLastTime) >= (1000 / 60))
{
nExecLastTime = nCurrentTime;
//ゲーム処理
UpdatePlayer(); //プレイヤー情報の更新
UpdateField();
UpdateBullet();
UpdateEnemy();
DrawPlayer(); //プレイヤーの表示
//DrawField();
DrawBullet();
DrawEnemy();
#ifdef _DEBUG
DispFPS();
#endif
nFrameCount++;
}
}while(!INP(KEY_ESC)); //ESC押して終了
CURON(); //カーソルをonに
UninitPlayer(); //プレイヤー後始末
UninitField();
UninitBullet();
timeEndPeriod(1); //ハードウェア設定の復帰
}
//main終了
#ifdef _DEBUG
void DispFPS()
{
COLOR(WHITE);
LOCATE(1 , 1);
printf("FPS:%d" ,g_nCountFPS);
}
#endif
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 20:49
by 葉月
これは、playerのプログラムです。
コード:
/////////////////////////////////////////////
///...インクルード
/////////////////////////////////////////////
#include "FPSsample.h"
#include "player.h"
#include "Field.h"
#include "bullet.h"
////////////////////////////////////////////
///...マクロ定義(defineなど)
////////////////////////////////////////////
#define VALUE_MOVE_X (0.75f) //移動量
#define VALUE_MOVE_X_AIR (0.30f) //空中での移動量
#define VALUE_JUMP (0.80f) //ジャンプ量
#define VALUE_RESIST_X (0.50f) //移動時の抵抗(空気抵抗?)
#define VALUE_RESIST_X_AIR (0.35f) //空中での抵抗(空気抵抗?)
#define VALUE_GRAVITY (0.06f) //重力加速値
#define LIMIT_LEFT (2.0f) //左移動限界
#define LIMIT_RIGHT (78.0f) //右移動限界
#define LIMIT_DOWN (24.0f) //下移動限界
//#define
//#define
//プロトタイプ宣言
bool CheckCollisionField(); //足場判定 tureで当たった事を表す
//グローバル変数
PLAYER g_player; //キャラクター管理構造体
#ifdef _DEBUG
//#defineの固定値を、変数にコピー
static float g_fValueMoveX = VALUE_MOVE_X; //staticを付けることによって、このファイル内でのみ使用できるグローバル関数となる。
static float g_fValueMoveXAir = VALUE_MOVE_X_AIR;
static float g_fValueResistX = VALUE_RESIST_X;
static float g_fValueResistXAir = VALUE_RESIST_X_AIR;
static float g_fValueJump = VALUE_JUMP;
static float g_fValueGravity = VALUE_GRAVITY;
//static float
#else
const float g_fValueMoveX = VALUE_MOVE_X; //書き換え不能な変数固定値
const float g_fValueMoveXAir = VALUE_MOVE_X_AIR;
const float g_fValueResistX = VALUE_RESIST_X;
const float g_fValueResistXAir = VALUE_RESIST_X_AIR;
const float g_fValueJump = VALUE_JUMP;
const float g_fValueGravity = VALUE_GRAVITY;
#endif
/*-----------------------------------
関数名 :InitPlayer
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void InitPlayer()
{
//最終的には、右側の初期値も#defineが好ましい?
g_player.fPosX = 20.0f; //初期表示座標
g_player.fPosY = 24.0f; //表示座標(x:20 , y:24)
g_player.fPosXOld = 20.0f;
g_player.fPosYOld = 24.0f;
g_player.fMoveX = 0.0f;
g_player.fMoveY = 0.0f;
g_player.bJump = false;
g_player.bLand = false;
g_player.bShot = false;
g_player.bMove = false;
g_player.fDirect = 1.0f;
}
/*-----------------------------------
関数名 :UninitPlayer
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void UninitPlayer()
{
//今は空っぽ
}
/*-----------------------------------
関数名 :UpdatePlayer
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void UpdatePlayer()
{
//現在位置を保存
g_player.fPosXOld = g_player.fPosX; //X座標
g_player.fPosYOld = g_player.fPosY; //Y座標
//左移動の処理
if(INP(PK_LEFT))
{
//ジャンプ中
if(INP(PK_SP))
{
g_player.fMoveX -= g_fValueMoveXAir;
}
else
{
g_player.fMoveX -= g_fValueMoveX;
}
}
g_player.bMove = true; //移動が発生した場合、フラグON
g_player.fDirect = -1.0f; //左を表すデータをセット 普通、「左」はX方向の座標の増分として-1だから。
//右移動の処理
if(INP(PK_RIGHT))
{
//ジャンプ中
if(INP(PK_SP))
{
g_player.fMoveX += g_fValueMoveXAir;
}
else
{
g_player.fMoveX += g_fValueMoveX;
}
}
g_player.bMove = true; //移動が発生した場合、フラグON
g_player.fDirect = 1.0f; //右を表すデータをセット
//ジャンプチェック 多重ジャンプ禁止用
if(INP(PK_UP))
{
//ジャンプ中でない場合
if(!g_player.bJump)
{
//ジャンプ移動量リセット
g_player.fMoveY =- g_fValueJump;
g_player.bJump = true; //ジャンプフラグON
}
}
//ジャンプ移動処理
//ジャンプ中の場合
if(g_player.bJump)
{
g_player.bMove = true;
g_player.fMoveX += (0.0f - g_player.fMoveX) * g_fValueResistXAir;
}
else
{
g_player.fMoveX += (0.0f - g_player.fMoveX) * g_fValueResistX;
}
//X座標更新
g_player.fPosX += g_player.fMoveX;
//画面内チェック
//左画面から見切れる位置に移動した場合
if(g_player.fPosX < LIMIT_LEFT)
{
//左の限界を超えたら、強制的に座標を限界値に変更
g_player.fPosX = LIMIT_LEFT;
}
//右画面から見切れる位置に移動した場合
else if(g_player.fPosX > LIMIT_RIGHT)
{
//右の限界を超えたら、強制的に座標を限界値に変更
g_player.fPosX = LIMIT_RIGHT;
}
//Y座標更新
g_player.fMoveY += g_fValueGravity; //移動量にGを掛ける
g_player.fPosY += g_player.fMoveY;
//下画面から見切れる位置に移動した場合
if(g_player.fPosY > LIMIT_DOWN)
{
//地面にめり込んだ場合の処理
g_player.fPosY = LIMIT_DOWN;
g_player.fMoveY = 0.0f; //移動ストップ
g_player.bJump = false; //ジャンプ終了
}
//当たり判定?
if(CheckCollisionField())
{
g_player.bMove = true;
g_player.fMoveY = 0.0f;
g_player.bJump = false;
g_player.bLand = true;
}
else
{
if(g_player.bLand)
{
g_player.bJump = true;
g_player.bLand = false;
}
}
//弾発射
if(INP(PK_SP)) //スペースキーが押されている
{
if(g_player.bShot == false) //弾発射できない
{
SetBullet(g_player.fPosX + VALUE_MOVE_X + (g_player.fDirect *2) , g_player.fPosY = 24.0f , g_player.fDirect , 0.0f , BULLETTYPE_PLAYER);
g_player.bShot = true;
}
else
{
if(g_player.bShot == true)//弾発射中
{
g_player.bShot = false;
}
}
}
}
/*-----------------------------------
関数名 :DrawPlayer
機能 :キャラクター描画システム
引数 :void
戻り値 :int
-----------------------------------*/
void DrawPlayer()
{
COLOR(YELLOW);
if(g_player.bMove)
{
//前回のプレイヤーを消去
LOCATE((int)(g_player.fPosXOld) , (int)(g_player.fPosYOld)); //float型としての座標を、int型としてキャストし、引数にする。(少数点以下は切り捨てられる)
printf(" "); //スペースを表示
//1つ上を消去
LOCATE((int)(g_player.fPosXOld) , (int)(g_player.fPosYOld) - 1); //float型としての座標を、int型としてキャストし、引数にする。(少数点以下は切り捨てられる)
printf(" "); //スペースを表示
g_player.bMove = false;
//現在のキャラクターの位置に、キャラクターを描画
LOCATE((int)(g_player.fPosX) , (int)(g_player.fPosY));
printf("00"); //キャラクターの表示
//キャラクターの位置の1つ上に表示
LOCATE((int)(g_player.fPosX) , (int)(g_player.fPosY) - 1);
printf("Q"); //表示
}
}
/*-----------------------------------
関数名 :CheckCollisionField
機能 :足場の当たり判定
引数 :void
戻り値 :int
-----------------------------------*/
bool CheckCollisionField()
{
FIELD *pField; //足場情報を受け取る(field.hのおかげで、FIELD型を使用できる)
pField = GetField(); //足場配列ポインタを取得
//↑2行のおかげで、player.cppから足場の情報を、pFiledを使って自由に見る事が出来る
for(int nCntField = 0 ; nCntField < MAX_FIELD ; nCntField = nCntField + 1 , pField = pField + 1)
{
//構造体が使用中
if(pField->bExist)
{
//足場の上に乗っかっているかの判定
if((g_player.fPosX + 0.9f) > pField->fPosX && g_player.fPosX < (pField->fPosX + pField->fWidth - 0.1f))
{
if(g_player.fPosY > (pField->fPosY - 1.0f) && g_player.fPosYOld <= (pField->fPosY - 1.0f))
{
g_player.fPosY = pField->fPosY - 1.0f;
return true; //当たっているため
}
}
//足場に頭突きしたかの判定
if((g_player.fPosX + 0.9f) > pField->fPosX && g_player.fPosX < (pField->fPosX + pField->fWidth - 0.1f))
{
if((g_player.fPosY - 2.0f) < pField->fPosY && (g_player.fPosYOld - 1.0f) >= pField->fPosY)
{
//座標を補正する 移動量をリセット
g_player.fPosY = pField->fPosY + 2.0f;
g_player.fMoveY = 0.0f;
}
}
}
}
return false;
}
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 20:51
by SUE
これってもしやコンソールアプリケーションですか? 製作環境を教えてください。
見たところ基本的なプログラムの構造はしっかりしていて良いです。しかしコンソールでアクションってのもすごいですね。
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 20:56
by 葉月
足場のプログラムです!!
コード:
/////////////////////////////////////////////
///...インクルード
/////////////////////////////////////////////
#include "FPSsample.h"
#include "field.h"
////////////////////////////////////////////
///...マクロ定義(defineなど)
////////////////////////////////////////////
#define LIMIT_LEFT (2.0f) //左移動限界
#define LIMIT_RIGHT (78.0f) //右移動限界
#define LIMIT_DOWN (24.0f) //下移動限界
FIELD g_aField[MAX_FIELD]; //足場構造体配列
/*-----------------------------------
関数名 :CreateField
機能 :足場作成
引数 :void
戻り値 :int
-----------------------------------*/
void CreateField(float fposx , float fposy , float fwidth)
{
//全構造体の数だけループ
for(int nCntField = 0 ; nCntField < MAX_FIELD ; nCntField = nCntField + 1)
{
//真の場合、構造体を初期化
if(!g_aField[nCntField].bExist)
{
g_aField[nCntField].fPosX = fposx;
g_aField[nCntField].fPosY = fposy;
g_aField[nCntField].fWidth = fwidth;
g_aField[nCntField].bExist = true;
break; //1つ足場を作成したら終了
}
}
}
/*-----------------------------------
関数名 :InitField
機能 :足場の初期化
引数 :void
戻り値 :int
-----------------------------------*/
void InitField()
{
//メンバ変数の初期化
for(int nCntField = 0 ; nCntField < MAX_FIELD ; nCntField = nCntField + 1)
{
g_aField[nCntField].fPosX = 0.0f;
g_aField[nCntField].fPosY = 0.0f;
g_aField[nCntField].fWidth = 0.0f;
g_aField[nCntField].bExist = false;
}
//画面内に足場を配置する。(X , Y ,width) ※XとYが表示座標 一番右は半角での個数、30.0fなら、15個の全角の■が生成
//画面外へ出ないように、座標と幅に注意する。
CreateField(10.0f , 21.0f , 8.0f);
CreateField(22.0f , 18.0f , 14.0f);
CreateField(48.0f , 18.0f , 10.0f);
CreateField(36.0f , 14.0f , 8.0f);
CreateField(24.0f , 10.0f , 10.0f);
CreateField(64.0f , 14.0f , 6.0f);
CreateField(42.0f , 8.0f , 30.0f);
COLOR(GRAY);
LOCATE(2 , 25);
printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■");
}
/*-----------------------------------
関数名 :UninitField
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void UninitField()
{
//特になし
}
/*-----------------------------------
関数名 :UpdateField
機能 :
引数 :void
戻り値 :int
-----------------------------------*/
void UpdateField()
{
//特になし
}
/*-----------------------------------
関数名 :DrawField
機能 :足場表示
引数 :void
戻り値 :int
-----------------------------------*/
void DrawField()
{
COLOR(GRAY);
for(int nCntField = 0 ; nCntField < MAX_FIELD ; nCntField = nCntField + 1)
{
if(g_aField->bExist)
{
LOCATE((int)g_aField[nCntField].fPosX , (int)g_aField[nCntField].fPosY);
//全角キャラを表示するので、回数的には指定幅の1/2とする。
for(int nCntBlock = 0 ; nCntBlock < (int)g_aField[nCntField].fWidth / 2 ; nCntBlock = nCntBlock + 1)
{
COLOR(GRAY);
printf("■"); //顔文字ではない
}
}
}
}
//足場の構造体配列の先頭のポインタを、戻り値としてリターンする
FIELD *GetField()
{
return &g_aField[0];
}
/*---------------EOF---------------*/
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 20:58
by SUE
あ、すいません。Playerのプログラムが来ていましたね。
CheckCollisionField()ではフィールドとプレイヤーの当たり判定が行われていますが、それと同じことをEnemyとBulletで行い、290行目に相当する部分はEnemyを消滅させる処理(あるいは、HPをつけるなら、HPの値をいくらか引く処理)にすればOKです。forループは二重(Bullet一つごとにEnemy全部と判定、をBullet全部で)になりますが大丈夫ですよね。
追記
Fieldも来ていましたね。EnemyはFieldと違ってサイズは固定のようなので、もっと楽に出来るでしょうが、具体的に何で悩んでいるのですか?
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 21:09
by 葉月
SUEさん コメントありがとうございます!! 自分でも解ってるんですけどそれが解らなくて困ってます。。。
どう書けば良いのかわからなくて(泣)
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 21:15
by 葉月
SUEさん
playerが撃った弾で敵が消えるようにしたいんです!
それが出来なくて詰まっちゃった感じです。。。
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 21:23
by SUE
ううむ、難しい。何か難しいのかって、ここまで出来てるのにどう詰まるのかが判らないから難しいww
真面目に答えます。流れとしては、
Enemyのupdate()からCheckCollisionBullet( Enemy *pEnemy )(←新しく作ってください)を呼び出す。このとき、自分自身へのポインタthisを渡す。[最初のソースの66行目あたり]
↓
CheckCollisionBulletで、Bullet全部と判定を行う。どうやらBulletには自機属性と敵属性があるようなので、自機属性のものとのみ判定を行う。
↓
当たっていたら、pEnemy->bUsedをfalseにする。消滅。以降は描画されない。
てな感じが、このシステムだと一番収まりが良いのではないでしょうか?
オフトピック
実は当たり判定ってとても奥が深いです。ゲームで一番アルゴリズムが複雑になる部分でもあります。このシステムなら特に問題ないですが。てか現在進行で自分が詰んでます。そんな勢いで返答してみました。
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 21:34
by 葉月
SUEさん
ありがとうございます!!
そうやってみますね!
また解らないことがあったらお聞きしていいでしょうか?
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 21:36
by SUE
はい。・・・というか、完全に解決するまで何が起きるかは判らないので、是非聞いてください。
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月19日(日) 21:39
by 葉月
SUEさん
了解です!!!!
Re: 敵に当たり判定をつけたいんです!
Posted: 2012年2月22日(水) 19:40
by 葉月
無事出来ました。ありがとうございました!