こんにちは。以前一度だけ質問させていただきましたC-TA-Kと申します。
開発環境はvisualstudio2008 C++、 DXライブラリ使用です。
今回私はブロック崩しを作っているのですが、そのときのバーとボールとの当たり判定で
詰まってしまいました。詳細は下に記述します。
class Bar_base
{
public:
int img; //画像
int spd; //移動スピード
double x,y; //座標
};
class Nomal_bar : public Bar_base
{
public:
};
class Ball_base
{
public:
int img; //画像
int spd; //移動スピード
double x,y; //座標
};
class Nomal_ball : public Ball_base
{
public:
};
このようにバーならバー基本クラスを継承したノーマルバー等のバーを実装し、
ボールならボールの基本クラスを継承したノーマルボール等を実装する形で種類を増やすつもりです。
しかし、その場合当たり判定を行う場合はバーの座標とボールの座標が必要ですが、
ノーマルバーとノーマルボールの判定するならそれぞれインスタンス化し、当たり判定用の関数を用意して
void hit_bar_ball()
{
nomal_bar.座標 と nomal_ball.座標の当たり判定処理
}
のようにすればいいのですがこれがまた新しく継承し
class Long_bar : public Bar_base
{}
等を作った場合などにはこの関数は適用できません。
だからといってほとんど同じ処理なのに当たり判定用の関数を何個も作るのはどうかと思います。
これをどうにか1つの当たり判定用の関数にまとめることはできないでしょうか?
クラス間での当たり判定
Re:クラス間での当たり判定
void hit_bar_ball(Bar_base *bar, Ball_base *ball)
{
bar->座標 と ball->座標の当たり判定処理
}
というふうにすると呼び出すときの引数にNomal_barとLong_barのインスタンスのどちらでも渡せます。
{
bar->座標 と ball->座標の当たり判定処理
}
というふうにすると呼び出すときの引数にNomal_barとLong_barのインスタンスのどちらでも渡せます。
Re:クラス間での当たり判定
お早い回答ありがとうございます。 しかし私ポインタについては最近やっと分かり始めたところでして
教えていただいた関数の引数に何を渡せば良いのか考えあぐねています。
インスタンスを渡すというのはどういうことなのでしょうか?
教えていただいた関数の引数に何を渡せば良いのか考えあぐねています。
インスタンスを渡すというのはどういうことなのでしょうか?
Re:クラス間での当たり判定
調べたところインスタンスを渡すというのは解決しました(参照渡し?というやつでよろしいのでしょうか)
そしてこの後に先程教えていただいた方法でhit_bar_ball()を実装したのですが、
確かに1つの関数で当たり判定を実装できるのですが、引数に&nomal_bar等で渡さなければなりません。
そうするともしnomal_bar と nomal_ballを入れたとき、long_bar と nomal_ballを入れたとき
nomal_bar と fast_ballなどの組み合わせを一つ一つ書き込まなければならないと思います。
例えば
hit_bar_ball(&nomal_bar, &nomal_ball);
hit_bar_ball(&nomal_bar, &fast_ball);
hit_bar_ball(&long_bar, &nomal_ball);
hit_bar_ball(&lobg_bar, &fast_ball);
するとバーやボールの種類が10種類になったころには凄まじい組み合わせの数を記述
しなければいけないのではないのでしょうか。関数を1つ挟んだとしても組み合わせによって
自動に切り替えられるようにしたいのですがどうすればよいでしょうか。
非常にわがままといいますか、都合の良すぎることを言っていると思いますがご助言いただければありがたいです。
そしてこの後に先程教えていただいた方法でhit_bar_ball()を実装したのですが、
確かに1つの関数で当たり判定を実装できるのですが、引数に&nomal_bar等で渡さなければなりません。
そうするともしnomal_bar と nomal_ballを入れたとき、long_bar と nomal_ballを入れたとき
nomal_bar と fast_ballなどの組み合わせを一つ一つ書き込まなければならないと思います。
例えば
hit_bar_ball(&nomal_bar, &nomal_ball);
hit_bar_ball(&nomal_bar, &fast_ball);
hit_bar_ball(&long_bar, &nomal_ball);
hit_bar_ball(&lobg_bar, &fast_ball);
するとバーやボールの種類が10種類になったころには凄まじい組み合わせの数を記述
しなければいけないのではないのでしょうか。関数を1つ挟んだとしても組み合わせによって
自動に切り替えられるようにしたいのですがどうすればよいでしょうか。
非常にわがままといいますか、都合の良すぎることを言っていると思いますがご助言いただければありがたいです。
Re:クラス間での当たり判定
public: int img; //画像 int spd; //移動スピード double x,y; //座標の重複があったので私なりに書いてみました
#include <iostream> using namespace std; class base { int img; // 画像 int spd; // 移動スピード double x, y; // 座標 public: double GetX() { return x; } double GetY() { return y; } }; class Normal_bar : public base { }; class Normal_ball : public base { }; bool hit_bar_ball( base *a, base *b ) { double x1 = a->GetX(); double y1 = a->GetY(); double x2 = b->GetX(); double y2 = b->GetY(); // x1, y1, x2, y2 を使ってあたり判定処理 bool hit = false; return hit; } int main() { base *bar = new Normal_bar(); base *ball = new Normal_ball(); hit_bar_ball( bar, ball ); return 0; }継承と、ポリモーフィズムを理解してないと分からないかもしれないです
Re:クラス間での当たり判定
No:64760の関数を
hit_bar_ball(&nomal_bar, &nomal_ball);
と呼びだすと
> void hit_bar_ball()
> {
> nomal_bar.座標 と nomal_ball.座標の当たり判定処理
> }
のコードと同じことになります。
ポインタを使うと汎用的な関数を作ることができます。
hit_bar_ball(&nomal_bar, &nomal_ball);
と呼びだすと
> void hit_bar_ball()
> {
> nomal_bar.座標 と nomal_ball.座標の当たり判定処理
> }
のコードと同じことになります。
ポインタを使うと汎用的な関数を作ることができます。
Re:クラス間での当たり判定
総当たりでの衝突判定です
2回判定していたりしてますので、期待どおりの処理にするにはカスタマイズが必要です
2回判定していたりしてますので、期待どおりの処理にするにはカスタマイズが必要です
#include <iostream> using namespace std; class base { int img; // 画像 int spd; // 移動スピード double x, y; // 座標 public: double GetX() { return x; } double GetY() { return y; } }; class Normal_bar : public base { }; class Normal_ball : public base { }; class Fast_ball : public base { }; bool hit_bar_ball( base *a, base *b ) { if( a == NULL ) return false; if( b == NULL ) return false; double x1 = a->GetX(); double y1 = a->GetY(); double x2 = b->GetX(); double y2 = b->GetY(); // x1, y1, x2, y2 を使ってあたり判定処理 bool hit = false; return hit; } int main() { base *bar = new Normal_bar(); base *ball = new Normal_ball(); base *fast = new Fast_ball(); hit_bar_ball( bar, ball ); base *object[10]; memset( object, 0, sizeof(object) ); object[0] = bar; object[1] = ball; object[2] = fast; int i, j; for( i=0; i<10; i++ ) { for( j=0; j<10; j++ ) { hit_bar_ball( object, object[j] ); } } return 0; }
Re:クラス間での当たり判定
バーオブジェクトの配列と ボールオブジェクトの配列に分ければできますね int main() { base *bar = new Normal_bar(); // バー base *ball = new Normal_ball(); // 通常のボール base *fast = new Fast_ball(); // 早いボール hit_bar_ball( bar, ball ); // バーと通常のボールの判定 hit_bar_ball( bar, fast ); // バーと早いボールの判定 base *object_ball[10]; // バーオブジェクト base *object_bar[10]; // ボールオブジェクト memset( object_ball, 0, sizeof(object_ball) ); memset( object_bar, 0, sizeof(object_bar) ); object_bar[0] = bar; object_ball[0] = ball; object_ball[1] = fast; // バー10個とボール10個の当たり判定 int i, j; for( i=0; i<10; i++ ) { for( j=0; j<10; j++ ) { hit_bar_ball( object_bar, object_ball[j] ); } } return 0; }
Re:クラス間での当たり判定
ISle様、dic様お二方とも回答ありがとうございます
dic様の総当りの当たり判定は
int main()
{
base *bar = new Normal_bar(); // バー
base *long = new Long_bar(); // 長いバー
base *ball = new Normal_ball(); // 通常のボール
base *fast = new Fast_ball(); // 早いボール
hit_bar_ball( bar, ball ); // バーと通常のボールの判定
hit_bar_ball( bar, fast ); // バーと早いボールの判定
hit_bar_ball( long, ball ); // 長いバーとボールの判定
hit_bar_ball( long, fast ); // 長いバーと早いボールの判定
base *object_ball[10]; // バーオブジェクト
base *object_bar[10]; // ボールオブジェクト
memset( object_ball, 0, sizeof(object_ball) );
memset( object_bar, 0, sizeof(object_bar) );
object_bar[0] = bar;
object_bar[1] = long;
object_ball[0] = ball;
object_ball[1] = fast;
// バー10個とボール10個の当たり判定
int i, j;
for( i=0; i<10; i++ )
{
for( j=0; j<10; j++ )
{
hit_bar_ball( object_bar, object_ball[j] );
}
}
return 0;
}
長いバーを追加するとしたらこんな感じで改変していけばよいのでしょうか?
ちなみにこの場合の開放はmain()の最後で良いのですよね?
dic様の総当りの当たり判定は
int main()
{
base *bar = new Normal_bar(); // バー
base *long = new Long_bar(); // 長いバー
base *ball = new Normal_ball(); // 通常のボール
base *fast = new Fast_ball(); // 早いボール
hit_bar_ball( bar, ball ); // バーと通常のボールの判定
hit_bar_ball( bar, fast ); // バーと早いボールの判定
hit_bar_ball( long, ball ); // 長いバーとボールの判定
hit_bar_ball( long, fast ); // 長いバーと早いボールの判定
base *object_ball[10]; // バーオブジェクト
base *object_bar[10]; // ボールオブジェクト
memset( object_ball, 0, sizeof(object_ball) );
memset( object_bar, 0, sizeof(object_bar) );
object_bar[0] = bar;
object_bar[1] = long;
object_ball[0] = ball;
object_ball[1] = fast;
// バー10個とボール10個の当たり判定
int i, j;
for( i=0; i<10; i++ )
{
for( j=0; j<10; j++ )
{
hit_bar_ball( object_bar, object_ball[j] );
}
}
return 0;
}
長いバーを追加するとしたらこんな感じで改変していけばよいのでしょうか?
ちなみにこの場合の開放はmain()の最後で良いのですよね?
Re:クラス間での当たり判定
たびたびすいません、丁寧に解説していただいたおかげで少し自分でも考えついたことがあるのですが、
void hit_bar_ball(Bar_base *bar, Ball_base *ball)
{
bar->座標 と ball->座標の当たり判定処理
}
void hit_select( int i, int j )
{
base *bar[10];
base *ball[10];
bar[0] = new Nomal_bar(); //普通のバー
bar[1] = new Long_bar(); //長いバー
ball[0] = new Nomal_ball(); //普通のボール
ball[1] = new Fast_ball(); //早いボール
hit_bar_ball(bar, ball[j]);
}
そしてこのiとjにはどのバーとどのボールを当てるか決定するグローバル変数を入れると
その二つの当たり判定だけが処理される・・・とはいきませんかね・・・。
void hit_bar_ball(Bar_base *bar, Ball_base *ball)
{
bar->座標 と ball->座標の当たり判定処理
}
void hit_select( int i, int j )
{
base *bar[10];
base *ball[10];
bar[0] = new Nomal_bar(); //普通のバー
bar[1] = new Long_bar(); //長いバー
ball[0] = new Nomal_ball(); //普通のボール
ball[1] = new Fast_ball(); //早いボール
hit_bar_ball(bar, ball[j]);
}
そしてこのiとjにはどのバーとどのボールを当てるか決定するグローバル変数を入れると
その二つの当たり判定だけが処理される・・・とはいきませんかね・・・。
Re:クラス間での当たり判定
void hit_bar_ball( Bar_base *bar, Ball_base *ball)
{
double bar_left = bar->x - bar->width;
double bar_top = bar->y - bar->height;
double bar_right = bar->x + (bar->width+1);
double bar_down = bar->y + (bar->height+1);
if( bar_left - (BALL_R+1) < ball->x &&
bar_right + BALL_R > ball->x &&
bar_top < ball->y &&
bar_down > ball->y )
{
ball->sign_x *= -1;
}
if( bar_left < ball->x &&
bar_right > ball->x &&
bar_top - (BALL_R+1) < ball->y &&
bar_down + BALL_R > ball->y )
{
ball->sign_y *= -1;
}
}
void hit_select(int i, int j)
{
Bar_base *bar[10];
Ball_base *ball[10];
bar[0] = &nomal_bar; //普通のバー
ball[0] = &nomal_ball; //普通のボール
hit_bar_ball(bar, ball[j]);
}
本当にありがとうございました、自分でお二人のコードを凝視して導いた結論がこれになりました
hit_selectのi,jにはグローバルな変数で、どのバーとボールを当てたいかを選択するようにしました
これで解決とさせていただきます。
{
double bar_left = bar->x - bar->width;
double bar_top = bar->y - bar->height;
double bar_right = bar->x + (bar->width+1);
double bar_down = bar->y + (bar->height+1);
if( bar_left - (BALL_R+1) < ball->x &&
bar_right + BALL_R > ball->x &&
bar_top < ball->y &&
bar_down > ball->y )
{
ball->sign_x *= -1;
}
if( bar_left < ball->x &&
bar_right > ball->x &&
bar_top - (BALL_R+1) < ball->y &&
bar_down + BALL_R > ball->y )
{
ball->sign_y *= -1;
}
}
void hit_select(int i, int j)
{
Bar_base *bar[10];
Ball_base *ball[10];
bar[0] = &nomal_bar; //普通のバー
ball[0] = &nomal_ball; //普通のボール
hit_bar_ball(bar, ball[j]);
}
本当にありがとうございました、自分でお二人のコードを凝視して導いた結論がこれになりました
hit_selectのi,jにはグローバルな変数で、どのバーとボールを当てたいかを選択するようにしました
これで解決とさせていただきます。