質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.35%

  • C#

    4766questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Windows Forms

    67questions

    Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

ボールとカゴの当たり判定について

解決済

回答 1

投稿 2017/12/07 14:11

  • 評価
  • クリップ 0
  • VIEW 70

rsetuhbcln

score 5

いつもありがとうございます。
当たり判定についてなのですが、現在、ボールをカゴに入れるゲームを作成しています。
そこで、ボールがカゴの上辺以外に当たり判定をつけ、反射させたいと思っているのですが、なかなかうまくいかず、カゴに当たると反射してしまいます。
なにか良い方法はありませんか?よろしくお願いします。

namespace _1108_ボール_斜方投射
{
public partial class Formballshoot : Form
{

double ballPos_x;
double ballPos_y;
double vx = 10;          //x座標の初速度
double vy = -30;       //y座標の初速度
double g = 1.0;          //加速度
double power = 1;
int t = 0;                   //時間
int ballRadius = 10;      //ボールの半径
double deg;                  //打ちだし角度
Timer timer = new Timer();
Random rand = new Random();  //乱数を発生させるrandを生成

public Formballshoot()
{

//角度を30度~60度の間で発生
deg = rand.Next(30, 60); 

this.ballPos_x = 10;      //x座標の初期位置
this.ballPos_y = 650;     //y座標の初期位置
InitializeComponent();

PictureBox1.Left = 150;   //カゴのy座標の初期位置
PictureBox1.Top = 500;    //カゴのx座標の初期位置

//マウスホイールイベントの追加
this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.Scroll_MouseWheel);

//タイマーイベント
Timer timer = new Timer();
timer.Interval = 50;
timer.Tick += new EventHandler(Update);
//timer.Start();

}

private void Update(object sender, EventArgs e)
{

ballPos_x += vx * Math.Cos(deg * (Math.PI / 180));
ballPos_y += vy * Math.Sin(deg * (Math.PI / 180)) + g * t;
this.t++;

//再描写
Invalidate();

//ボールが画面の下を超えた場合
//繰り返しボールを飛ばす
if (ballPos_y > 650)
{

this.vx = power;             //初速をpowerにする
this.vy = -30;          //y座標の初速度を再び示す 
this.g = 1.0;                //加速度を再び示す
this.ballPos_x = 10;         //x座標の初期位置に戻す
this.ballPos_y = 650;        //y座標の初期位置に戻す
deg = rand.Next(30, 60);     //角度を30度~60度に設定
this.t = 0;
this.t++;
ballPos_x += vx * Math.Cos(deg * (Math.PI / 180));
ballPos_y += vy * Math.Sin(deg * (Math.PI / 180)) + g * t;

}

//ボールとカゴの当たり判定
if ((ballPos_x > PictureBox1.Location.X) &&
(ballPos_x < PictureBox1.Left + PictureBox1.Size.Width) &&
(ballPos_y > PictureBox1.Location.Y) &&
(ballPos_y < PictureBox1.Top + PictureBox1.Size.Height))
{

this.vx = -1;
this.vy = -1;

}

}

}

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Bongo

    2017/12/07 15:45

    当たり判定はカゴのピクチャーボックスの形(単なる長方形)でいいのでしょうか?それともカゴに合った形(たとえば半球状)の方がいいでしょうか。後者の場合、カゴの画像もご提示いただけると方法を検討しやすいかと思います。また、ボールがカゴに入った後(カゴ上辺を通過した後)のボールの動きをどうしたいかも要検討でしょうね。場合によっては、カゴ内壁との当たり判定をどうするか考えなくてはならないかもしれません。

    キャンセル

  • rsetuhbcln

    2017/12/07 17:05

    返信ありがとうございます 当たり判定は単なる長方形で大丈夫です。またボールがカゴに入ったらボールを初期位置に戻すように考えています。

    キャンセル

  • Bongo

    2017/12/07 19:33

    なるほど、それならだいぶシンプルになりそうですね。もう一つ確認事項として、ボールの大きさは考慮するべきでしょうか?今のご質問者さんのコードですと、ボールのふちではなく、中心点がカゴ領域に入った時に「当たった」と判定されているものと想像します。現状通り、ボールの大きさを考慮しなくてよいならさらにシンプルに作れそうですが...

    キャンセル

  • rsetuhbcln

    2017/12/07 20:00

    ボールの大きさを考慮していなかったので、ボールの半径を条件に加えました。

    キャンセル

回答 1

checkベストアンサー

0

こんな方針でどうでしょう。なお、この方法でやる場合、ご質問者さんの現在のコードballPos_x += vx * Math.Cos(deg * (Math.PI / 180));ballPos_y += vy * Math.Sin(deg * (Math.PI / 180)) + g * t;のような「毎回初速度と経過時間から現在の速度を求め、ボールの位置に加算する」方式はちょっと相性が悪いかと思います(跳ね返り後のボールの動きをご想像いただくとお分かりかと思いますが、跳ね返った後は軌道が変わるので、発射時の式のままではおかしな動きになってしまうはずです...あえてやるとしたら、「跳ね返り地点から跳ね返り方向へ跳ね返り速度でボールを再発射する」イメージで実装することになるでしょうか)。それよりも、

  • ボールの位置のほかに、「ボールの現在速度」を保持する変数を追加する(仮にballVel_xballVel_yとする)
  • ボール発射時に現在速度に初速度を代入する...ballVel_x = vx * Math.Cos(deg * (Math.PI / 180));ballVel_y = vy * Math.Sin(deg * (Math.PI / 180));
  • Update内では「現在速度に加速度を加算」してから「現在位置に現在速度を加算」する...ballVel_y += g;ballPos_x += ballVel_x;ballPos_y += ballVel_y;

といった方式の方が跳ね返りを実装しやすいように思います。

当たり判定ですが、まず、ボールの中心が下図1~9のどのエリアにいるか特定し、エリアに応じて判定方法を分けることにします。どのエリアにいるかはボール座標とピクチャーボックスの4辺の位置L、T、R、Bを比較すればいいでしょう。

イメージ説明

そして、ボールのエリアに応じてピクチャーボックスとの衝突判定を行い、併せてボールを跳ね返らせるのに使う、衝突面の法線ベクトルを求めます。各エリアごとに見てみると...

  1. 衝突する可能性があるのはa点。ボール中心とa点の距離を求め、ボール半径以下なら衝突とする。法線は(ボール中心座標 - a点座標) / ボール中心とa点の距離。
  2. 衝突する可能性があるのは辺ab。T - ボール座標Yがボール半径以下なら衝突とする。法線は(0、-1)。
  3. 衝突する可能性があるのはb点。ボール中心とb点の距離を求め、ボール半径以下なら衝突とする。法線は(ボール中心座標 - b点座標) / ボール中心とb点の距離。
  4. 衝突する可能性があるのは辺bd。ボール座標X - Rがボール半径以下なら衝突とする。法線は(1、0)。
  5. 衝突する可能性があるのはd点。ボール中心とd点の距離を求め、ボール半径以下なら衝突とする。法線は(ボール中心座標 - d点座標) / ボール中心とd点の距離。
  6. 衝突する可能性があるのは辺cd。ボール座標Y - Bがボール半径以下なら衝突とする。法線は(0、1)。
  7. 衝突する可能性があるのはc点。ボール中心とc点の距離を求め、ボール半径以下なら衝突とする。法線は(ボール中心座標 - c点座標) / ボール中心とc点の距離。
  8. 衝突する可能性があるのは辺ac。L - ボール座標Xがボール半径以下なら衝突とする。法線は(-1、0)。
  9. ボールが速すぎると、ボールの縁で衝突判定されることなくこのエリアに来てしまうと予想される。このケースに対処する方法の一例としては、このエリアに来た場合はボールを1フレーム前の位置に戻し、短い間隔で少しずつ移動させてみて当たり判定を行うという手が考えられる。

ここまででボールがピクチャーボックスのどの辺、あるいはどの角に当たったか、そして衝突面の法線が分かるので、後は...

  • 辺abに当たったケースでは「ボールがカゴに入った」と判定する
  • それ以外では跳ね返り処理を行う...C# - 当たり判定 反射するようにするには(103369)|teratailでozwkさんのおっしゃった方法が有効でしょう。「ボールの現在速度ベクトルと法線ベクトルの内積を求める」→「現在速度ベクトル - (2 * 内積 * 法線ベクトル)を新たな現在速度ベクトルとする」でいけるはずです。

こんな感じでいかがでしょうか...?どの方向から当たったかの場合分けがややこしいかもしれませんが、紙に図を描いたりして動きをイメージしてみるのもいいんじゃないかと思います。

投稿 2017/12/08 00:14

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/08 11:14

    詳しく説明していただきありがとうございます!
    ちょっと難しそうですが、やってみたいと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • C#

    4766questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Windows Forms

    67questions

    Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。