WindowメニューからReferenceを選ぶとOnLineReferenceを開くことが出来ます。ここにはサンプルコードがたくさんありますので、ぜひそのままPushButtonなどにドラッグして各コントロールやメソッドの使い方を試してみて下さい。
第11回 - 2球の弾性衝突 -
2球の弾性衝突の様子を表してみます。Classを利用したサブルーチンのサンプルも用意しました。
- - 衝突現象について -
2 球の直衝突(一直線上での衝突)では、衝突直前直後での運動量の和が保存されます、この関係式(運動量保存則)とはね返りの式をそれぞれの速度で作ることで衝突直後の速度が求められます。
これに対して、2 球の偏心衝突(一直線上の衝突ではなく、平面上で2つの球が角度をなして衝突し、別々の方向にはね返る衝突)では、衝突した瞬間の2つの球のそれぞれの重心を結ぶ方向、及びそれとは直角方向に分けて考える必要があります。重心を結ぶ方向の速度成分では、一直線上での衝突と同様に、衝突直前直後での運動量保存則とはね返りの式をそれぞれの速度で作ります。重心を結ぶ方向とは直角方向の速度成分では、衝突前後で速度は変化しません。
このように、偏心衝突を考える場合は、
- 衝突する瞬間の2球の位置関係を調べる。
- 重心を結ぶ方向の速度成分を調べる。
- 重心を結ぶ方向、及びそれとは直角方向に分けて衝突後の速度を調べる。
- 元の速度成分に戻す。
のような手順が必要になります。
- - プログラムです -
今回は、衝突前後での速度変化を求める部分がメインとなります。
初めに、ベースとなる座標系を、右に x 軸、上にy 軸とした( x 、 y )座標とします。
さて、衝突直前の速度の( x 、y )成分を球1で( vx1a 、vy1a )、球2で( vx2a 、vy2a )。衝突直後の速度の( x 、y )成分を球1で( vx1b 、vy1b )、球2で( vx2b 、vy2b )とします。
- 2球が衝突する瞬間の球1、球2の位置を表す座標をそれぞれ( x1、y1 )、( x2 、y2 )とすると、2つの球の重心を結ぶ方向は、 x 軸となす角度を「th」とすると、sin(th)の値s1とcos(th)の値c1は、次のように求められます。
r=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)) s1=(y2-y1)/r c1=(x2-x1)/r
さらに、衝突直前の速度の(重心を結ぶ方向の成分、それとは直角方向の成分)を球1で( vx1a d、vy1ad )、球2で( vx2ad 、vy2ad )。衝突直後の速度の成分を球1で( vx1bd 、vy1bd )、球2で( vx2bd、vy2bd )とします。
この部分の説明には、座標系の図があればわかりやすいと思います。
まず、( vx1a d、vy1ad )や( vx2ad 、vy2ad )を( vx1a 、vy1a )や( vx2a 、vy2a )で表してみます。
以上が、衝突ルーチンです。
- 衝突直前のそれぞれの(x,y)方向の速度成分を、衝突方向(重心を結ぶ方向)の速度成分に変換する。
// vx1ad=vx1a*c1+vy1a*s1 vy1ad=-vx1a*s1+vy1a*c1 // vx2ad=vx2a*c1+vy2a*s1 vy2ad=-vx2a*s1+vy2a*c1- 次は、衝突での速度変換です。今回は簡単のために2球は同一の質量で弾性衝突とします。このとき、衝突方向(重心を結ぶ方向)の速度成分は、球1球2で交換される結果となります。衝突方向(重心を結ぶ方向)とは直角方向の速度成分は変化しませんので。
// vx1bd=vx2ad vx2bd=vx1ad vy1bd=vy1ad vy2bd=vy2ad //- 最後に、これらの速度を、もう1度( x、y )座標系に戻します。
// vx1b=vx1bd*c1-vy1bd*s1 vy1b=vy1bd*c1+vx1bd*s1 vx2b=vx2bd*c1-vy2bd*s1 vy2b=vy2bd*c1+vx2bd*s1 //
これをプログラム内でどのように使うか、方法はいくつかあります。
Window1内でのサブルーチンとして使う方法や、Moduleにサブルーチンを置く方法があります。しかしながら、完全なサブルーチンとは呼べない使い方しかできません。通常のサブルーチンでは、結果となる値が1つしか戻すことが出来ません。Return Type も1種類、戻り値も1つというものしか作ることは出来ません。今回の衝突ルーチンでは、どうしても、結果が4つ必要となります。解決方法としては、サブルーチン内の4つの結果を戻す変数を、サブルーチン内だけの変数つまりローカル変数(サブルーチン内で定義する)にせずに、グローバル変数(Module やWindow1内のNewProperties で宣言する)にする方法です。この方法が手っ取り早くて簡単ですが、せっかく作ったサブルーチンに汎用性がなくなります。もう1つの方法は、Class を利用する方法です。今どきの言語の考え方だと思いますが、慣れてくるに従って、REALbasic の柔軟性に気づきます。Class の利用法には、Canvas やButton などのコントロールに新しい機能をつけ加えたものを作り出すというREALbasic 独特の使い方もあります。Class のサブルーチンとしての利用方法は、覚え書きのページに詳しく説明がありますので参考にして下さい。
- 衝突したときの、2球の表示について
画面のちらつきを押さえるためには、NewPicture を利用することが出来ます。しかしサイズの大きいPicture では表示速度が遅くなっておもしろくありません。本来「Sprite」を使うべきプログラムですが、まだのREALbasicの「Sprite」は私の思うようには動いてくれません。従いまして、残された方法は、はじめにボールを描き、次に描く前に、はじめのボールをボールの部分だけ背景色で塗りつぶす、というものです。塗りつぶす領域が小さいので、表示スピードがそれほど遅くなりません。将来は「Sprite」が使えるようになるはずです。
- ゲーム「ビリヤード」について
2球の衝突のルーチンを使ってビリヤードゲームを作ってみました。ビリヤードのルール自体をよく知りませんので、ビリヤードとしてはおかしなものになっていると思いますが、それはそれとして二人でお楽しみ下さい。
今回のサンプルは、
- ボールを発射する方向をマウスで決めるようにしました。クリックで表れる点の方向にボールが進みます。
- ボールの数は配列を使っていますので何個でも計算可能ですが、10個以上になると計算と表示時間がかかり面白くありません。また画面のちらつきが気になります。PICTやPictuerを張り付ける操作をすると、ちらつきは収まりますが、表示時間がかかってしまいます。今回はちらつきを我慢してスピードを優先しました。
- 衝突条件の数式を変更すると予想できない動きをします。試してみると面白いです。
- 6カ所にポケットを作りました。ポケットに入った条件判断と点数の処理やプレイヤー交代のルーチンがプログラムを複雑にしている1番の理由です。
- REALbasicを初めて使う方へ
今回のビリヤードですが、はじめからこのように大きなプログラムを書けるはずはありません。でもソースをいじって、どんな変化があるのか自分で試してみることが簡単にできます。たとえば、ボールの色を変えてみる。ボールの数や大きさを変えてみる。はねかえりの係数や摩擦係数を変えてみる。ポケットの大きさを変えてみる。もっと簡単なところではボタンの位置を変えてみる。などなど......。これらのことから少しずつ自分でもプログラムできそうだな、と思いはじめた方はぜひこの機会に気軽にチャレンジしてみてください。
ボールの数の変更の仕方
0 REALbasicで「ビリヤード」のファイルを開きます。
1 EditメニューからEditorSettingsを開きSource EditorのFontをOsakaにします。
2 ProjectのウインドウからWindow1をダブルクリックすると「ビリヤード」とタイトルの付いたウインドウが開きます。このウインドウの中にあるスタートボタンの少し上の辺りをダブルクリックするとCode Browser(Window1)とタイトルの付いたウインドウが開きます。
3 このウインドウの「Events」の「Open」を開きます。
4 このウインドウに書かれた初期条件の部分のプログラムをいじればよいわけです。
以下の部分です
//ボールの数は15までです
//15以上にするときは配列も増やします
nob=10
//ボールの半径
rb=7
10や7の数字を変更してみて下さい。
5 プログラムの実行はEditメニューのDebugからRunを選択します。
グローバル変数を使ったサブルーチンを用いた「弾性衝突g」
Class を利用したサブルーチンを用いた「弾性衝突c」
ゲーム「ビリヤード1.2」
以上、3点セットとしました。
今回の「3点セット」の ソースプログラムです
プロジェクトファイルのみです。REALbasicの最新バージョンが必要です。50 kバイト
ソースコードについての質問やご意見がありましたら以下のアドレスまでご連絡下さい。
koko-@mx2.tiki.ne.jp