何かJavaのGraphics2Dクラスを使ったプログラミングの練習をしようと思って、昔作ったことがある思い出のアプリをJavaで作ってみた。
弾性衝突円盤アプレットのページへ
各円盤は面積に比例した質量を持ち、壁や他の円盤に完全弾性衝突する。
後は説明不要だと思う。
Pentium3だと動作がちょっと重いかも知れない。
大昔、X68000のHuman68k(つまりウィンドウシステムでない)上で動くものを作った時は、アセンブラで書いてスプライトを使って衝突計算アルゴリズムもかなり練って速度を出したのだが、今回、Javaのコードをほとんど工夫せずに書き、描画処理は単純に消して描いての繰り返しで、しかもJavaアプレットとしてブラウザ上で動かすと、遜色ない速度が出たので、驚いた。68000MPUとCeleron 3.2GHzの性能はかくも違うのか。PCの性能の進歩はなんと速いことか。
割とシンプルなコードになったので、ソースコード、説明を添えて公開するつもりだったが、時間が無かったので、とりあえずアプレットだけ先に公開することにした。
円盤の描画は、先にBufferedImageの画像を用意しておいて、背景を塗りつぶしてGraphics#drawImageでペタペタ貼っているだけである。当方の環境ではちらつきが目立たないので、ダブルバッファリングは省略した。
円盤同士の衝突の計算は、円盤の速度の衝突点方向の成分を求めて、高校の物理で習う完全弾性衝突の式を当てはめて、その方向の速度の変化を求めている。
結局Graphics2Dの機能は使わなかった。非矩形の画像の重ね合わせに必要だと思ったのだが、java.awt.imageのBufferedImageクラスのαプレーンを使えば難なくできた。
別の新たなネタを探さねばならない。
円盤の画像は、Graphics#drawArcで描いてるのだが、丸く見えない(ちょっと四角い)のは気のせいだろうか。
衝突の式は、理系なら高2くらいで習う程度の計算で、前に似たようなのを作った大学生の時は割と簡単に解けたのに、今回はベクトルの射影の計算がうまくできなくて、かなりてこずった。衝突方向の速度変化を元の速度ベクトルに戻す計算を、もう1度射影しないといけないとずっと勘違いしていて(正しくは衝突方向の速度変化を元の速度ベクトルに足すだけ)、なかなか思い通りにバウンドしてくれなかった。悲しいくらいに数式に弱くなっていた。
大体うまく動くようになったのだが、なぜか円盤同士の衝突の度に運動量の合計が変化してるので、まだどこか間違ってるのかも知れない。
1つの円盤が同時に2ヶ所以上で衝突する場合の式が最後までわからなくて、円盤はある瞬間には1ヶ所でしか衝突せず、残りの衝突は円盤がめり込むのを許して次のタイミングで計算する、とすることで逃げてしまった。昔のはそんな泥臭いことはせず、しかもきちんと運動量が保たれていたと記憶してるのだが、一体どういう手を使ったのだったか?
コメント