ビリヤード物理実験室
HTML、CSS、JavaScriptだけで動作する、ビリヤード風の物理シミュレーションゲームです。
ショットの方向や強さに加え、摩擦や反発係数を自由に変更し、ボールの転がり方、衝突、クッション反射の違いを観察できます。
外部ライブラリやWebサーバは不要です。htmlをブラウザで開くだけで利用できます。
デモ
ソース
1. 主な機能
1.1 ショット操作
- 白球からドラッグしてショット方向を指定
- ショットの強さを5~100%で変更
- 照準線と矢印による方向表示
- ボタンまたはキーボードからショット実行
- ボール停止中の白球移動
1.2 物理設定
- 摩擦の調整
- 反発係数の調整
- 完全弾性衝突への切り替え
- ボール同士の円形当たり判定
- クッションに対する斜め反射
- 反発係数に応じた衝突時のエネルギー減衰
1.3 表示機能
- ボールの速度ベクトル表示
- ボールの軌跡表示
- 衝突回数表示
- 白球速度表示
- 総運動エネルギー表示
- 運動中・停止中の状態表示
1.4 ステージプリセット
以下の設定を選択できます。
| プリセット | 摩擦 | 反発係数 | 特徴 |
|---|---|---|---|
| 標準テーブル | 0.45 | 0.96 | 通常のゲーム向け設定 |
| めっちゃ滑る | 0.015 | 0.99 | ボールが長時間滑り続ける |
| 全然転がらない | 2.40 | 0.82 | ショット後すぐに減速する |
| 超反射 | 0.12 | 1.00 | 摩擦が小さく、衝突時の速度損失がない |
| エネルギー吸収 | 0.35 | 0.45 | 衝突するたびに大きく減速する |
プリセット選択後も、摩擦と反発係数は個別に変更できます。
2. 起動方法
-
billiards_physics_lab.htmlを任意のフォルダに保存します。 - Google Chrome、Microsoft Edge、FirefoxなどのWebブラウザで開きます。
- 画面が表示されたら、そのまま操作できます。
インストール、ビルド、Webサーバの起動は不要です。
3. 操作方法
3.1 マウスまたはタッチ操作
白球からドラッグする
白球を押したまま狙う方向へドラッグし、離すとショットします。
ドラッグ中は照準方向が更新されます。
テーブル上をクリックする
白球以外の場所をクリックすると、その位置へ向けて照準を変更できます。
クリック後にポインターを離すと、その方向へショットします。
白球の起点を移動する
すべてのボールが停止している状態で、Shiftキーを押しながら白球をドラッグします。
白球はクッションの内側の範囲で移動できます。
3.2 キーボード操作
| キー | 動作 |
|---|---|
Space |
現在の照準方向へショット |
R |
ボールを初期配置へ戻す |
S |
すべてのボールを停止する |
Shift+白球ドラッグ |
白球の起点を移動する |
4. 画面項目
4.1 ショット
強さ
ショット時の白球の初速度を指定します。
設定可能範囲は5~100%です。
内部では、次の式で初速度を計算しています。
初速度 = 1250 × 強さ / 100
狙った方向へショット
現在表示されている照準方向へ白球を発射します。
ボールが動いている間は、新しいショットは実行されません。
全停止
すべてのボールのX方向速度とY方向速度を0にします。
初期配置には戻しません。
初期配置
白球と15個の的球を初期位置へ戻し、以下の情報も初期化します。
- 衝突回数
- 軌跡
- 照準方向
4.2 ステージ物理
摩擦
ボールが進むにつれて速度を減少させる値です。
設定可能範囲は0.00~3.00です。
- 値が小さいほど長く滑ります。
- 値が大きいほど早く停止します。
- 0.00にすると、衝突以外ではほぼ減速しません。
内部では、おおむね次の式で速度を減少させています。
減速度 = 摩擦 × 230 × 経過時間
このゲームの摩擦値は、実際の物理単位ではなく、遊びやすさを目的としたシミュレーション用の値です。
反発係数
ボール同士またはボールとクッションが衝突したときに、どの程度速度を維持するかを指定します。
設定可能範囲は0.20~1.00です。
| 値 | 挙動 |
|---|---|
| 1.00 | 衝突による運動エネルギー損失がない理想状態 |
| 1.00未満 | 衝突するたびに速度の一部を失う |
| 小さい値 | 衝突後に大きく減速する |
完全弾性衝突
有効にすると、反発係数を強制的に1.00として計算します。
この間、反発係数のスライダーは操作できません。
完全弾性衝突では、摩擦による減速を除き、衝突前後の運動エネルギーが理想的に保存されます。
4.3 表示
速度ベクトルを表示
移動中のボールに、現在の速度方向と大きさを黄色い線で表示します。
線が長いほど、そのボールの速度が大きいことを示します。
軌跡を表示
ボールが通過した位置を点として残します。
最大160フレーム分の履歴を保持します。
表示を無効にすると、保存されていた軌跡も削除されます。
衝突回数を表示
テーブル左上に、以下を合計した衝突回数を表示します。
- ボール同士の衝突
- ボールと左右クッションの衝突
- ボールと上下クッションの衝突
画面下部のステータス欄では、この設定にかかわらず衝突回数を確認できます。
5. ステータス表示
状態
-
停止中:すべてのボールの速度が停止判定値未満 -
運動中:いずれかのボールが移動中
白球速度
白球の現在速度を表示します。
X方向速度とY方向速度から、次の式で求めています。
速度 = √(X方向速度² + Y方向速度²)
衝突回数
ゲーム開始または初期配置後から発生した衝突の累計です。
総運動エネルギー
すべてのボールの運動エネルギーを合計した値です。
各ボールの質量は1として、次の式で計算しています。
運動エネルギー = 1 / 2 × 質量 × 速度²
実際のジュール値ではなく、設定変更前後の比較や、エネルギー減衰の観察に利用するための相対的な値です。
6. 物理モデル
6.1 ボールの表現
各ボールは、平面上の円として扱っています。
主なデータは次のとおりです。
- 中心座標
x,y - X方向速度
vx - Y方向速度
vy - 半径
- 質量
- 色
- 番号
すべてのボールは、同じ半径、同じ質量として計算します。
6.2 ボール同士の当たり判定
2つのボールの中心間距離が、半径の合計より小さくなった場合に衝突と判定します。
中心間距離 < ボールAの半径 + ボールBの半径
ボール同士が重なった場合は、それぞれを衝突法線方向へ半分ずつ移動させ、重なりを解消します。
その後、衝突方向に対する相対速度と反発係数から力積を求め、両方の速度を更新します。
6.3 クッション反射
ボールがテーブルの有効範囲を越えた場合、位置を内側へ戻し、該当する速度成分の符号を反転します。
左右のクッションではX方向速度、上下のクッションではY方向速度を反転します。
左右反射: vx = -vx × 反発係数
上下反射: vy = -vy × 反発係数
このため、斜めにクッションへ入射した場合も、入射角に応じた斜め反射になります。
6.4 計算の安定化
1画面更新分の物理計算を3回に分割して処理しています。
これにより、速度が高い場合にボール同士がすり抜ける現象を軽減しています。
また、1フレームの経過時間は最大0.025秒に制限しています。ブラウザが一時停止した場合などに、再開直後の計算が極端に大きくなることを防ぎます。
7. 簡略化している要素
本ゲームは、物理現象を理解しやすくするため、平面上の並進運動に絞っています。
現在は、次の要素を計算していません。
- ボールの回転
- 順回転、逆回転、横回転
- キューの撞点
- マッセやカーブ
- スリップ状態から転がり状態への移行
- 空気抵抗
- テーブルクロスの方向性
- ボールと布の静止摩擦
- ポケット
- 得点やゲームルール
- 音
そのため、実際のビリヤードを完全に再現するものではなく、摩擦、反射、円同士の衝突を試すための簡易物理実験環境です。
8. ファイル構成
billiards_physics_lab.html
billiards_physics_lab.htmlの内部に、以下をすべて記載しています。
HTML : 画面構造
CSS : レイアウトとデザイン
JavaScript : 描画、操作、物理計算
画像、JavaScriptライブラリ、CSSライブラリなどの外部ファイルは使用していません。
9. 対応環境
HTML5 CanvasとPointer Eventsに対応した、比較的新しいブラウザを対象としています。
主な対象ブラウザは次のとおりです。
- Google Chrome
- Microsoft Edge
- Mozilla Firefox
PCでのマウス操作を基本としていますが、Pointer Eventsを利用しているため、対応端末ではタッチ操作も可能です。
10. 改造しやすい箇所
初期配置
resetBalls()関数で、白球と的球の位置を定義しています。
ショット最大速度
shoot()関数内の次の値を変更します。
const speed = 1250 * power;
摩擦の効き方
physicsStep()関数内の次の係数を変更します。
const decel = friction * 230 * dt;
ボールの大きさ
world.ballRadiusを変更します。
ballRadius: 16
物理計算の分割数
アニメーションループ内のsubStepsを変更します。
const subSteps = 3;
値を大きくすると高速衝突時の安定性が向上しやすくなりますが、計算負荷も増加します。
11. 今後の拡張候補
- ポケットと落球判定
- 得点ルール
- 手球と的球の選択
- キューによる撞点指定
- ボールの回転
- スピンに応じたクッション反射
- 質量や大きさが異なるボール
- 障害物の配置
- ステージエディター
- 重力方向の設定
- スローモーション
- 一時停止と1フレーム送り
- 衝突前後の速度・運動量表示
- 設定値の保存と読み込み
- 効果音
物理計算と画面描画がJavaScript内で関数ごとに分かれているため、学習用の改造題材として利用できます。