Skip to content

事前シミュレーション方式で表紙が必ず上を向く落下演出を実装する #2

@kako-jun

Description

@kako-jun

背景

物理エンジン(Rapier)で本を落として表紙が上を向くように重力や回転を制御する方式は、実現が困難で破棄した(session95)。

発想を転換し、物理の結果を制御するのではなく、結果に合わせてテクスチャを貼る方式にする。

方式

事前シミュレーション(非表示・ページロード時)

  1. 本を1冊ずつ、ランダムな初期回転で落下させる(当たり判定なし、地面のみ衝突)
  2. 静止後、上を向いた面を判定(6面の法線をクォータニオンで回転し、Y成分が最大の面)
  3. その面に表紙テクスチャを割り当てる
  4. 最終着地位置のXZから真上に逆算して、落下開始位置を決める
  5. 初期パラメータ(位置、回転、テクスチャ面の割り当て)を記録
  6. 10冊分について、最終位置のXZが重ならないことを確認(近すぎたらリトライ)

本番表示

  1. 記録済みパラメータで落下を再生
  2. 表紙テクスチャは最初から貼られているので、落下中も表紙が見える
  3. 当たり判定なし → 各本は独立した物理で、事前シミュレーションと同じ結果になる
  4. ユーザーには「表紙の見える本がバラバラと落ちてきて、きれいに散らばる」ように見える

なぜ成立するか

  • 当たり判定なし: 本同士が互いに影響しないので、1冊ずつの事前シミュレーション結果が本番でもそのまま再現される
  • Rapierは決定論的: 同じ初期条件 → 同じ結果
  • テクスチャ後貼り: どの面が上になるかは物理に任せ、上になった面に表紙を貼るだけ。物理を操作する必要がない
  • 重なり防止: 当たり判定なし+最終XZ座標の距離チェックで、本同士が重ならない最終配置を保証

実装タスク

  • 非表示の事前シミュレーション機構(ヘッドレスRapierワールド)
  • 静止判定(rb.isSleeping() または速度閾値)
  • 上面判定ロジック(クォータニオン→法線変換→Y最大面)
  • 最終XZ位置の重なりチェック+リトライ
  • 最終XZ位置から落下開始位置(真上)の逆算
  • テクスチャ面の動的割り当て(BookCover.tsx)
  • 本番表示時のcollision group設定(本同士は無視、地面のみ衝突)
  • 複数プリセット保持でリロード時にバリエーションを出す

既存コードへの影響

  • BookCover.tsx: テクスチャ面の動的割り当て追加、磁気反発コード削除
  • Scene.tsx: 事前シミュレーション→本番表示の2フェーズ構成に変更
  • Walls.tsx: 当たり判定なしなら不要になる可能性あり(要検討)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions