- 締切済み
C++でのブロック崩しゲームの作成に関して
初めまして。C++で動くブロック崩しを作成していますがそれに関して2つ質問させて頂きます。 (1)オブジェクト指向によるブロック、パドルでのクラス宣言 オブジェクト指向に基づきプログラミングをしており、パドル、ブロック、ボールといった物体をクラス定義しそれらをゲームクラスで統括する方法をとっています。また、他クラスのインスタンスやメソッドはgetter/setter関数で取得し、その際に参照するクラスの宣言は"const Ball& ball"の様に行っています。 他クラスを参照する必要のある場合は、例えばBlockクラス内でBallとの衝突判定や衝突応答を行いたい時に宣言を行っています。衝突判定ならばBoolean型を返すだけなのでconstで宣言出来るのですが、衝突応答ではボールを反射させる(ボールの速度を変化させる)必要があるためconstで宣言出来ません。 現在は"Ball& ball"と宣言をしていますが、これでは他クラス内でインスタンスの値を変更できてしまうため行儀が良いとは思えません。言っている事が矛盾しているとは思いますが、何とか"const Ball& ball"で宣言しつつBlockクラス内でボールの速度を変化させる方法は無いでしょうか? (2)ブロックとボールの衝突応答 ブロックとボールの衝突応答について、以下の様に記述しています。 void Block::reflect(Ball& ball){ Vector ballnext; ballnext.x=ball.getx()+ball.getVx(),ballnext.y=ball.gety()+ball.getVy(); if(fabsf(ballnext.x-this->x) <= this->width/2 && fabsf(ball.getx()-this->x) >= this->width/2){ ball.setVx(-ball.getVx()); } else if(fabsf(ballnext.y-this->y) <= this->height/2 && fabsf(ball.gety()-this->y) >= this->height/2){ ball.setVy(-ball.getVy()); } } この関数より前にブロック内にボールが含まれるかどうかの衝突判定を行っています。この関数では、数秒先のボールの位置がブロック内に含まれており、現在のボールの位置が含まれていない場合のそれぞれの位置関係で反射方向を決めています。 ですがこれでは上手く反射されません。ボールがブロックに接触し暫く突き進んだ後に反射されます。 しかし、 ballnext.x=ball.getx()+ball.getVx()*2,ballnext.y=ball.gety()+ball.getVy()*4; の様に記述すると上手く反射されます。何故こうなるのかが理解出来ません。 長文になってしまい申し訳ありませんが、どなたかご教授して頂けたら幸いでございます。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
付け加えると、登場人物たちにあまり直接交渉させない方が良いです。 たとえば、あとひとつ user というクラス(のインスタンス)を参加させて while(1) { パドル.ユーザーの操作(ユーザー.操作()) // ユーザーの操作を与えて、次に進む位置を計算できるようにする if(ボール.次に進む位置() == パドル.次に進む位置()) { // ボールとパドルが接触する(ただし、単純に == で良いかどうか場別の問題として ボール.反射してね(パドル.スピード()) } for(int i = 0; i < ブロック::総数(); i++) // ブロックの総数を求めるために、static なメンバー関数が使える // 処理を簡単にするために、総数は消えてしまったブロックも含むことにしよう { if (個別のブロック[i].存在する && 個別のブロック[i].座標 == ボール.次に進む位置()) // ボールがぶつかるブロックが存在する { 個別のブロック[i].消えてね(); ここで、ブロックの「生存数」は -1 になるように処理しよう ボール.反射してね(0); // ブロックだから、ぶつかる方のスピードはゼロとして ] } if (ブロック::生存数 == 0) break; // 一面クリア パドル.ひとつ進む(); ボール.ひとつ進む(); } こんな感じの処理を念頭に置くと、うまく設計できるんではないかという気がします。(確かめてません)
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
一般的には、矛盾を感じたら設計がどこかおかしいというのは言えることです……が。 あと、setter() や getter() が単純にメンバーの値を返す/値を設定するとしたら、多分、設計がおかしいです。 基本的にメンバーは自分の挙動を決定するための情報ではありますが、逆に言えば、それをそのまま相手に渡す必要はないのです。 たとえば、衝突判断の場合、ボールの側から見れば、 ・次に進む予定の所に存在するブロックはないか? ・もしあったら、そのブロックに消えてもらって、(そのブロックにたとえば erase() メッセージを送る・C++ の実装では、そのブロックのたとえば、erase() メンバーを呼び出す) ・自分自身の速度やら進行方向を(自分で)変更する。 となりますし、ブロックの側から見れば(それぞれのブロックごとに) ・自分が存在している位置にボールが来るつもりはないか(たとえば、ボールに next() メッセージを送る) ・もし、自分の位置にボールが来るのなら、自分自身は消える ・ボールに対しては、「反射してね」というメッセージを送る(具体的に「反射」をどう表現するかは、ボールの責任) という流れが設定できるかと思います。 つまりは、お互いに相手の情報に手を出さないということです。 ボールはブロックに対して、「消えてね」というだけで良いですし、ブロックはボールに対しては(具体的な位置を指定するのではなく)「反射してね」といえば良いだけです。 ボールの進行方向や速度までブロックが決めようとすると、概ね全体の構成は破綻します。 後半の問題については、ボールとブロックの「位置」が実はどこなのかが影響している気がします。 ボールの位置が中心で、ブロックの位置が左下だったら、「ぶつかる」というのは、単純に判定していれば、ボールがブロックにめり込んだ後になりますね。
お礼
ご回答ありがとうございました。 お礼は上のものと合体させて頂きます。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
> 言っている事が矛盾しているとは思いますが、何とか"const Ball& ball"で宣言しつつBlockクラス内でボールの速度を変 化させる方法は無いでしょうか? メンバ変数を mutable にすれば可能ですが、それは「正しい設計」ですか?
お礼
早速のご返事ありがとうございます。 「正しい設計」かどうかは答え辛いですね。。。当方C++についてはまだ未熟なため、あまり自信がございません。 mutableの存在を忘れていました。本日帰宅後に一度挑戦してみたいと思います。 ありがとうございました。
お礼
返事が遅くなり申し訳ありません。 色々と手解きして頂きありがとうございます。とりあえず質問前にしようとしていたブロック、パドルのクラス内でのボール反射処理は止め、全てボールクラス内にて行うように修正しました。 また私の方で設計に多少の間違いがあり、その結果この様に不躾な質問をしてしまい反省しております。 ユーザ(user)というクラスで全ての物体の管理を行うアイデアは素晴らしいと思います。余力があれば実装させて頂きます。 回答して頂き本当にありがとうございました。