当たり判定のサンプルを作っているのですが、
前フレームの弾と現在の位置の弾の間を計算するところがうまく作れなくて困っています。
弾同士の距離の間を少しづつループで進めて計算して、
弾の間に判定を詰め込んで隙間をなくしたいです。
//main.cpp
#include "DxLib.h"
#include <cmath>
#define BULLET_MAX 10
char key[256];//キー入力用
struct vector2D {
float X;
float Y;
};
vector2D A, B, P;//座標用
vector2D AB, AP, BP,AO,BO;//ベクトル用
struct Bullet {
double X;
double Y;
double preX;
double preY;
double angle;
bool exist;
int speed;
int size;
int wait;
bool hit;
};
Bullet bullet[BULLET_MAX];
int rapid;
float R; //半径
float GetVector2D_Dot(vector2D A, vector2D B);
float GetVector2D_Cross(vector2D A, vector2D B);
float GetVector2D_Length(vector2D A, vector2D B);
bool LineCircleCollision(float r, vector2D A, vector2D B, vector2D P);
void Shot();
void DrawBullet();
void BulletUpdate();
void BulletInit();
void BulletCollision();
class Fps {
int mStartTime; //測定開始時刻
int mCount; //カウンタ
float mFps; //fps
static const int N = 60;//平均を取るサンプル数
static const int FPS = 60; //設定したFPS
public:
Fps() {
mStartTime = 0;
mCount = 0;
mFps = 0;
}
bool Update() {
if (mCount == 0) { //1フレーム目なら時刻を記憶
mStartTime = GetNowCount();
}
if (mCount == N) { //60フレーム目なら平均を計算する
int t = GetNowCount();
mFps = 1000.f / ((t - mStartTime) / (float)N);
mCount = 0;
mStartTime = t;
}
mCount++;
return true;
}
void Draw() {
DrawFormatString(600, 460, GetColor(255, 255, 255), "%.1f", mFps);
}
void Wait() {
int tookTime = GetNowCount() - mStartTime; //かかった時間
int waitTime = mCount * 1000 / FPS - tookTime; //待つべき時間
if (waitTime > 0) {
Sleep(waitTime); //待機
}
}
};
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
//初期化
R = 20;
P.X = 200;
P.Y = 200;
rapid = 0;
Fps fps;
BulletInit();
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
fps.Update(); //更新
fps.Draw(); //描画
fps.Wait(); //待機
A.X = 100;
A.Y = 300;
B.X = 400;
B.Y = 300;
GetHitKeyStateAll(key);
if (key[KEY_INPUT_RIGHT] != 0) { P.X++; }
if (key[KEY_INPUT_LEFT] != 0) { P.X--; }
if (key[KEY_INPUT_UP] != 0) { P.Y--; }
if (key[KEY_INPUT_DOWN] != 0) { P.Y++; }
if (key[KEY_INPUT_Z] !=0) {
rapid++;
rapid %= 10;
if (rapid == 1) {
Shot();
}
}
BulletCollision();
DrawBullet();
//円を描画
DrawCircle(P.X, P.Y, R, GetColor(255, 255, 0));
//線を描画
DrawLine(A.X, A.Y, B.X, B.Y, GetColor(255, 0, 0));
//当たり判定
if (LineCircleCollision(R, A, B, P));
}
DxLib_End(); // DXライブラリ終了処理
return 0;
}
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
key[i]++; // 加算
}
else { // 押されていなければ
key[i] = 0; // 0にする
}
}
return 0;
}
//内積
float GetVector2D_Dot(vector2D A, vector2D B) {
float Dot = A.X*B.X + A.Y*B.Y;
return Dot;
}
//外積
float GetVector2D_Cross(vector2D A, vector2D B) {
float Cross = A.X*B.Y - A.Y*B.X;
return Cross;
}
//大きさ
float GetVector2D_Length(vector2D A, vector2D B) {
float X = fabsf(B.X - A.X);
float Y = fabsf(B.Y - A.Y);
return pow(X * X + Y * Y, 0.5);
}
bool LineCircleCollision(float r, vector2D A, vector2D B, vector2D P) {
//座標からベクトルを得る
AB.X = B.X - A.X;
AB.Y = B.Y - A.Y;
AP.X = P.X - A.X;
AP.Y = P.Y - A.Y;
BP.X = P.X - B.X;
BP.Y = P.Y - B.Y;
//円と線分の距離を求める
//ベクトルAB、APの外積の絶対値が平行四辺形Dの面積になる
double D = abs(GetVector2D_Cross(AB, AP));
double L = GetVector2D_Length(A, B); //AB間の距離
double H = D / L;
DrawFormatString(0, 0, GetColor(255, 255, 255), "H%d", (int)H);
DrawFormatString(0, 20, GetColor(255, 255, 255), "D%d", (int)D);
DrawFormatString(0, 40, GetColor(255, 255, 255), "L%d", (int)L);
float dot1 = GetVector2D_Dot(AP, AB);
float dot2 = GetVector2D_Dot(BP, AB);
DrawFormatString(0, 60, GetColor(255, 255, 255), "dot%d", (int)dot1);
DrawFormatString(0, 80, GetColor(255, 255, 255), "dot%d", (int)dot2);
//線と円の中心の距離が半径より小さい
if (H <= r) {
if (dot1*dot2 <= 0) {//角度が90度以下なので円の中心が線分の両端の内側にある
DrawString(0, 460, "HIT!!!", GetColor(0, 255, 255));
return true;
}
//鈍角になるスペシャルケースの場合
float AP = GetVector2D_Length(A, P);
float BP = GetVector2D_Length(B, P);
DrawFormatString(0, 100, GetColor(255, 255, 255), "AP%d", (int)AP);
DrawFormatString(0, 120, GetColor(255, 255, 255), "BP%d", (int)BP);
if (AP < R || BP < R) {
DrawString(0, 460, "HIT!!!", GetColor(255, 0, 255));
return true;
}
}
}
void BulletInit(){
for (int i = 0; i < BULLET_MAX;i++) {
bullet[i].X = 0;
bullet[i].Y = 0;
bullet[i].preX = 0;
bullet[i].preY = 0;
bullet[i].angle = 0.75;
bullet[i].exist = false;
bullet[i].speed =8;
bullet[i].size = 2;
bullet[i].hit = false;
bullet[i].wait = 0;
}
}
void DrawBullet(){
BulletUpdate();
for (int i = 0; i < BULLET_MAX; i++) {
if (bullet[i].exist) {
DrawCircle(bullet[i].X,bullet[i].Y,bullet[i].size,GetColor(0,255,0));
}
}
}
void BulletUpdate() {
for (int i = 0; i < BULLET_MAX; i++) {
if (bullet[i].exist) {
bullet[i].preX = bullet[i].X;
bullet[i].preY = bullet[i].Y;
bullet[i].X = bullet[i].X + cos(bullet[i].angle)*bullet[i].speed;
bullet[i].Y = bullet[i].Y + sin(bullet[i].angle)*bullet[i].speed;
}
//画面外だと消える
if (bullet[i].X < 0 || bullet[i].X>640) {
if (bullet[i].Y < 0 || bullet[i].Y>480) {
bullet[i].exist = false;
bullet[i].angle = 0.75;
}
}
//判定が重ならないようにウェイト
if (bullet[i].wait == 3) {
bullet[i].hit = false;
bullet[i].wait = 0;
}
if (bullet[i].hit) {
bullet[i].wait++;
}
}
}
void Shot() {
for (int i = 0; i < BULLET_MAX; i++) {
if (!bullet[i].exist) {
bullet[i].X = P.X;
bullet[i].Y = P.Y;
bullet[i].exist = true;
return;
}
}
}
void BulletCollision() {
for (int i = 0; i < BULLET_MAX; i++) {
//当たり判定
vector2D O;
O.X = bullet[i].X;
O.Y = bullet[i].Y;
if (bullet[i].exist&&!(bullet[i].hit)) {
if (LineCircleCollision(bullet[i].size, A, B, O)) {
bullet[i].hit = true;
bullet[i].angle = bullet[i].angle*(-1);
return;
}
//弾と弾のすきま用
vector2D Q;
//前フレームと現在の弾の距離を求める
double x = abs(bullet[i].X - bullet[i].preX);
double y = abs(bullet[i].Y - bullet[i].preY);
double length = sqrt(x*x + y*y);
//弾何個分か調べる
//(弾同士の距離-それぞれの弾の半径)÷弾の直径
double b_num = (length - (bullet[i].size*2)) / (bullet[i].size*2);
DrawFormatString(200, 200, GetColor(255, 255, 255), "b_num%d", (int)b_num);
for (int j = 0; j <= b_num; j++) {
double b_x = bullet[i].preX;
double b_y = bullet[i].preY;
Q.X = b_x;
Q.Y = b_y;
if (LineCircleCollision(bullet[i].size, A, B, Q)) {
bullet[i].hit = true;
bullet[i].angle = bullet[i].angle*(-1);
return;
}
b_x += cos(bullet[i].angle)*bullet[i].size*2;
b_y += sin(bullet[i].angle)*bullet[i].size*2;
DrawCircle(b_x, b_y, bullet[i].size, GetColor(255, 0, 100));
}
}
}
}