トップページ > 記事閲覧
ソードと敵の当たり判定について
名前:north 日時: 2015/06/15 23:37

いつも質問に答えてくださりありがとうございます。 前回ソードのことについてお聞きしたことがあると思うのですが、その後敵のショットを消すことには成功しました。 しかし肝心の敵とソードの当たり判定が機能せず、どこがおかしいのか分からず苦戦しております。 また、以前から敵がショットを打たずに行ってしまうバグが発生しておりこちらも原因がわからず困っております。 下記にプログラムをアップいたしました。 ttp://xfs.jp/aaMZrh password:stg お忙しい中申し訳ないですがどこがおかしいのか教えていただけないでしょうか? どうかよろしくお願い致します。
メンテ

Page: 1 |

Re: ソードと敵の当たり判定について ( No.1 )
名前:管理人 日時:2015/06/16 00:55

敵とソードの当たり判定を行っている箇所( ソースファイル名・関数名等 )と 敵がショットを撃つ処理を行っている箇所( ソースファイル名・関数名等 )を教えていただけないでしょうか? 毎回問題の箇所を自分で調べてしまうのですが、少し時間が掛かってしまうので 申し訳ありませんが調べる時間の短縮のために教えてください
メンテ
Re: ソードと敵の当たり判定について ( No.2 )
名前:north 日時:2015/06/16 01:00

敵の当たり判定についてはあの後もう一度自分で調べ直し、自己解決いたしました。 ただ、当たり判定をもう少し正確にしたい・・・・ ソードの先から柄の部分を除いた根本までを当たり判定にしたいのと ソードを正面に180度だけ回転させ、その後消したいのですが、どのようにしたらよろしいでしょうか? また、敵がショットを打たずに行ってしまうバグは相変わらずわからないままです・・・・ 修正したプログラムを下記にアップいたしました。 ttp://xfs.jp/kEJZPy password:stg 敵とソードの当たり判定を行っているのは CheckHit.cppのSwordAndEnemy()関数です。 敵がショットを打つ処理を行っているのは Bullet.cppです。 ソードの回転を行っているのは Model.cppのDrawWepon()関数で行っています。 お忙しい中、度々申し訳ないですがどうかよろしくお願い致します。
メンテ
Re: ソードと敵の当たり判定について ( No.3 )
名前:管理人 日時:2015/06/17 01:31

敵がショットを打たずに行ってしまうバグの原因は分かりました Bullet.cpp の CBullet::ShotEntry にバグがあります、この関数内のある部分を変更すれば直ります ヒントです、tShot[ii].Number に代入する値は何に使われているでしょうか? > ソードの先から柄の部分を除いた根本までを当たり判定にしたいのと > ソードを正面に180度だけ回転させ、その後消したいのですが、どのようにしたらよろしいでしょうか? こちらの件ですが、とりあえず > ソードを正面に180度だけ回転させ、その後消したい こちらを先に実装しましょう まず仕様を確認させてください 現在は「ソードボタンを押している間だけソードが表示される」ですが、 「ソードを正面に180度だけ回転させ、その後消す」 になった場合は、どうなるのでしょうか? 180度回転してソードが消えた直後はソードボタンが押されていますから 消えた直後に再びソードが表示されるのでしょうか?
メンテ
Re: ソードと敵の当たり判定について ( No.4 )
名前:north 日時:2015/06/17 02:26

お忙しい中ありがとうございます。 頂いたヒントのおかげで無事にバグを修正することができました。 ソードの仕様としましては ・ボタンを1回押したら最後まで振り切り最後まで振り切ったら消える ・ボタンを離してもう一度押したときは常に最初の位置から降り始める という仕様に変更しようと思っております。 説明不足で申し訳ありません。 お忙しい中度々申し訳ありませんがどうかよろしくお願い致します。
メンテ
Re: ソードと敵の当たり判定について ( No.5 )
名前:管理人 日時:2015/06/17 23:57

ご説明ありがとうございます、仕様を理解できました では、それをプログラムにしてみてください ヒントは 「CModel::DrawWeapon の中のソードを振るプログラムを変更するだけでその仕様を実現することができる」 です まずは現在0度から360度まで回ってしまっているソードを0度から180度の範囲だけで 回るようにしてみてください
メンテ
Re: ソードと敵の当たり判定について ( No.6 )
名前:north 日時:2015/06/18 01:15

お忙しい中ありがとうございます。 頂いたヒントのおかげで無事に仕様通りの形にすることができました。恐らくほかにスマートな書き方があると思うのですが・・・・ 最後に ・ソードの先から柄の部分を除いた根本までを当たり判定にしたい こちらなのですが自分では処理の実装の方法が思いつかず一番困っているところです。 ソードの当たり判定の処理は 敵とソードの当たり判定を行っているのは CheckHit.cppのSwordAndEnemy()関数です。 また、サンプルコードを基に組んだのですが、 内積を利用している (恐らくですが181〜184行目) ところまではわかるのですが、上記の関数内の186行目と187行目が何をしているのかわからずこちらも教えていただけたらと思います。 念のためにソードの振り方の仕様を実装したプログラムをアップしたしました。 ttp://xfs.jp/e9Mz5i pass:stg お忙しい中度々申し訳ありませんがどうかよろしくお願い致します。
メンテ
Re: ソードと敵の当たり判定について ( No.7 )
名前:管理人 日時:2015/06/20 13:03

すみません、ご返信が遅くなりました ソードの回転のプログラムは無駄の無いものになっていると思います > ・ソードの先から柄の部分を除いた根本までを当たり判定にしたい こちらなのですが、「現在どのようになってしまっているのを、どのように変更したいのか」 を、もう少し詳しく教えていただけないでしょうか? 恐らく私が想像している仕様で合っていると思うのですが、偶に本人に訊ねてみると 自分の想像していたものとは違った、ということがあるので・・・
メンテ
Re: ソードと敵の当たり判定について ( No.8 )
名前:north 日時:2015/06/20 22:44

説明不足で申し訳ありません。 現在のプログラムだと弾の位置に関係なく剣が出てきた瞬間に弾や敵が消えたり、 剣先にかすってもいないのに消えてしまったりと当たり判定がしっかりとなっておらず、 そうではなくちゃんと先から柄の部分を除いた根本までのどこかにかすったら消えるようにしたいのです。 コード自体サンプルを見ながら内積を利用するところまではわかったのですが、 173行目と186行目と187行目が何をしているのかわからず完璧に理解しているとは言い難く、 どのようにすれば上記に書いたような正確な当たり判定が取れるのか分からない状態です。 説明が下手で申し訳ありません。 お忙しい中度々申し訳ありませんがどうかよろしくお願い致します。
メンテ
Re: ソードと敵の当たり判定について ( No.9 )
名前:管理人 日時:2015/06/21 04:38

ご説明ありがとうございます、仕様を理解できました 内積を使用するという方法ではなく球と三角形の当たり判定を行う関数 HitCheck_Sphere_Triangle を 使用した方法ですが、正確な当たり判定を実現できましたのでよろしければご覧ください ( 少し計算が難しいので答えをそのまま・・・ ) まず「現在のソードの角度」の他に「1フレーム前のソードの角度」が必要なので、 Model.h の WEPON_PARAM 構造体に float AngleSub; を追加します 次に Model.cpp の CModel::DrawWepon に「AngleSub に角度を変化させる前の Angle の値を代入する」 という処理を追加します( 角度を固定するときは Angle と同じ値を代入します ) void CModel::DrawWepon() { tWeponParam.Pos = tPlayerParam.PlayerPos; tWeponParam.Pos.z = tPlayerParam.PlayerPos.z + 15.0f; MV1SetScale(tWeponParam.WeponHandle, VGet(20.0f, 20.0f, 20.0f)); MV1SetPosition(tWeponParam.WeponHandle, tWeponParam.Pos); MV1SetRotationXYZ(tWeponParam.WeponHandle, VGet(DX_PI_F / 2.0f, tWeponParam.Angle / -360.0f * DX_PI_F, 0.0f)); if(Input & PAD_INPUT_1) { tWeponParam.Flag = 1; } if(tWeponParam.Flag == 1) { MV1DrawModel(tWeponParam.WeponHandle); } if(tPlayerParam.PlayerFlag == 0 && tWeponParam.Flag == 1) { tWeponParam.AngleSub = tWeponParam.Angle; tWeponParam.Angle -= 10.0f; if(tWeponParam.Angle < -180.0f) { //初期の角度に戻す tWeponParam.AngleSub = 180.0f; tWeponParam.Angle = 180.0f; //ソードを消す tWeponParam.Flag = 0; } } //ソードの振リ初めの角度を固定する if(tWeponParam.Flag == 0) { tWeponParam.AngleSub = 180.0f; tWeponParam.Angle = 180.0f; } } あと、ソードの回転角度の x の値( VGet の第一引数 )が 90.0f となっていましたが、こちらで指定する角度の単位は「度」ではなく 「ラジアン」なので、ラジアンで 90度を示す π / 2 ( コードでは DX_PI_F / 2.0f ) に変更しました 次に CheckHit.cpp のソードと弾の当たり判定を行う CCheckHit::SwordAndBullet は大きく変化して以下のようになりました void CCheckHit::SwordAndBullet() { VECTOR SwordPos; VECTOR SwordPosSub; // ソードが出ていなかったら何もしない if(WeponInfo.Flag == 0) { return; } // ソードの先端の座標を算出 rad = ( WeponInfo.Angle + 180.0f ) / 360.0f * DX_PI_F; SwordSin = sin(rad); SwordCos = cos(rad); SwordPos = WeponInfo.Pos; SwordPos.x += SwordCos * 15.0f; SwordPos.z += SwordSin * 15.0f; // 1フレーム前のソードの先端の座標を算出 rad = ( WeponInfo.AngleSub + 180.0f ) / 360.0f * DX_PI_F; SwordSin = sin(rad); SwordCos = cos(rad); SwordPosSub = WeponInfo.Pos; SwordPosSub.x += SwordCos * 15.0f; SwordPosSub.z += SwordSin * 15.0f; //敵ショット総数 for(int ii = 0; ii < SHOT_MAX; ii++) { //そのショットが登録されていたら if(ShotInfo[ii].Flag > 0) { //弾総数 for(int jj = 0; jj < SHOT_BULLET_MAX; jj++) { //弾が登録されていたら if(ShotInfo[ii].tBullet[jj].Flag == 1) { // ソードの柄の座標とソードの先端の座標と1フレーム前のソードの先端の座標で形成する三角形と // 敵の弾が当たっているか調べる if( HitCheck_Sphere_Triangle( ShotInfo[ii].tBullet[jj].Pos, 3.0f, SwordPos, SwordPosSub, WeponInfo.Pos ) ) { ShotInfo[ii].tBullet[jj].Flag = 0; //弾をオフ } } } } } } ループの前にソードが出ていなかったら何もせず関数から抜ける処理と、「ソードの先端の座標」と「1フレーム前のソードの先端の座標」を 算出して、ループの中で「ソードの先端の座標」「1フレーム前のソードの先端の座標」「ソードの柄の座標」で形成する三角形と 「弾の座標」で当たり判定を行っています 先端の座標を算出する箇所に書かれている 15.0f はソードの長さ、HitCheck_Sphere_Triangle の引数に書かれている 3.0f は弾の大きさです ソードの長さはともかく弾の大きさは弾の種類によって異なると思いますので、こちらは弾のサイズが代入されたメンバー変数等に置き換えてください 最後にソードと敵の当たり判定です、当たり判定の処理に関しては弾の当たり判定とほぼ同じです int CCheckHit::SwordAndEnemy() { VECTOR SwordPos; VECTOR SwordPosSub; // ソードが出ていなかったら何もしない if(WeponInfo.Flag == 0) { return -1; } // ソードの先端の座標を算出 rad = ( WeponInfo.Angle + 180.0f ) / 360.0f * DX_PI_F; SwordSin = sin(rad); SwordCos = cos(rad); SwordPos = WeponInfo.Pos; SwordPos.x += SwordCos * 15.0f; SwordPos.z += SwordSin * 15.0f; // 1フレーム前のソードの先端の座標を算出 rad = ( WeponInfo.AngleSub + 180.0f ) / 360.0f * DX_PI_F; SwordSin = sin(rad); SwordCos = cos(rad); SwordPosSub = WeponInfo.Pos; SwordPosSub.x += SwordCos * 15.0f; SwordPosSub.z += SwordSin * 15.0f; int DeathEnemyNum = 0; for(int ii = 0; ii < ENEMY_MAX; ii++) { if(EnemyInfo[ii].Flag == 1) { // ソードの柄の座標とソードの先端の座標と1フレーム前のソードの先端の座標で形成する三角形と // 敵が当たっているか調べる if( HitCheck_Sphere_Triangle( EnemyInfo[ii].Pos, 5.0f, SwordPos, SwordPosSub, WeponInfo.Pos ) ) { return ii; } } } return -1; } 弾と同じく HitCheck_Sphere_Triangle の引数に書かれている 5.0f は敵の大きさですので、こちらも敵の大きさが代入された メンバー変数等に置き換えてください
メンテ
Re: ソードと敵の当たり判定について ( No.10 )
名前:north 日時:2015/06/21 20:39

ご返信が遅くなり申し訳ありません。 無事に実装することができました。 ご丁寧な解説までつけてくださりありがとうございます。 以前よりも正確になっていますのであとは弾や敵の当たり判定の大きさの調整だと思います。 計算部分で一部なんとなくはわかるのですがしっかりと理解したいので質問させてください。 rad = ( WeponInfo.Angle + 180.0f ) / 360.0f * DX_PI_F; SwordSin = sin(rad); SwordCos = cos(rad); SwordPos = WeponInfo.Pos; SwordPos.x += SwordCos * 15.0f; SwordPos.z += SwordSin * 15.0f; ここの計算部分が三角関数を使うのだなというのはわかるのですが具体的に何をしているのか理解しておきたいので、 お手数をおかけして申し訳ないですが教えていただいてもよろしいでしょうか? 何度も申し訳ありませんがよろしくお願い致します。
メンテ
Re: ソードと敵の当たり判定について ( No.11 )
名前:管理人 日時:2015/06/23 23:28

注釈に書きました通り、ソードの先端の座標を算出しています sin と cos を使用すると円周の座標を得ることができることはご存知でしょうか? ソードの先端の動きは円周をなぞる動きそのものなので、 sin と cos を使用してソードの先端の座標を算出しています 計算結果を見た目で分かるようにしてみたサンプルを作成しましたので、よろしければご覧ください #include "DxLib.h" #include <math.h> int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { float WeaponInfoAngle ; VECTOR WeaponInfoPos ; float SwordSin ; float SwordCos ; float rad ; VECTOR SwordPos ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ; // 角度を初期化 WeaponInfoAngle = 0.0f ; // 座標を初期化 WeaponInfoPos.x = 320.0f ; WeaponInfoPos.y = 0.0f ; WeaponInfoPos.z = 240.0f ; // メインループ while( ProcessMessage() == 0 ) { // 画面をクリア ClearDrawScreen() ; // 角度を変化させる WeaponInfoAngle -= 5.0f ; if( WeaponInfoAngle < -180.0f ) { WeaponInfoAngle += 360.0f ; } // 座標を算出 rad = WeaponInfoAngle / 180.0f * DX_PI_F; SwordSin = sin(rad); SwordCos = cos(rad); SwordPos = WeaponInfoPos; SwordPos.x += SwordCos * 128.0f; SwordPos.z += SwordSin * 128.0f; // 線分を描画 DrawLine( ( int )WeaponInfoPos.x, ( int )WeaponInfoPos.z, ( int )SwordPos.x, ( int )SwordPos.z, GetColor( 255,255,255 ) ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; }
メンテ
Re: ソードと敵の当たり判定について ( No.12 )
名前:north(解決) 日時:2015/06/24 11:07

わざわざサンプルまでご用意してくださりありがとうございます。 おかげさまで無事に理解することができました。 また、何かわからないことがありました際はどうかよろしくお願い致します。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存