# 画面設計書 32-ゲームサンプル

## 概要

本ドキュメントは、three.jsのExamplesセクションに含まれる「ゲームサンプル（Games Examples）」画面の設計書である。FPS（First Person Shooter）形式のゲームサンプルを提供し、three.jsを使用したゲーム開発の参考実装として機能する。

### 本画面の処理概要

このサンプルは、Octree（八分木）を使用した衝突検出と物理シミュレーションを実装したFPSスタイルのインタラクティブデモである。プレイヤーは3D空間内を移動し、ボールを投げて物理的なインタラクションを体験できる。

**業務上の目的・背景**：three.jsでゲーム開発を行う開発者向けに、一人称視点のカメラ制御、衝突検出、物理シミュレーションの実装パターンを提供することを目的としている。特にOctreeを使用した効率的な衝突検出は、大規模な3D空間でのパフォーマンス最適化に不可欠な技術であり、実務での応用価値が高い。

**画面へのアクセス方法**：Examples一覧画面（examples/index.html）から「Games」カテゴリを選択するか、直接URLにアクセス。画面クリックでポインターロックが有効になり、ゲームプレイが開始される。

**主要な操作・処理内容**：
1. マウス操作によるカメラ視点の回転（FPS形式）
2. WASDキーによるプレイヤーの移動（前進・後退・左右移動）
3. スペースキーによるジャンプ
4. マウスクリックによるボールの投擲
5. Octreeベースの衝突検出による壁や床との当たり判定
6. 物理シミュレーションによるボールの挙動計算
7. GLTFモデル（collision-world.glb）の読み込みと表示

**画面遷移**：Examples一覧画面からアクセスされ、単一ページで完結する。GitHubソースコードへの外部リンクがある。

**権限による表示制御**：特になし。公開サンプルとして認証不要でアクセス可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | Object3D | 主機能 | プレイヤー・ボール等のオブジェクト管理 |
| 75 | Mesh | 補助機能 | 物理メッシュオブジェクトの表示 |
| 127 | Matrix4 | 補助機能 | 変換行列の計算 |
| 13 | WebGLRenderer | 主機能 | 3Dシーンのレンダリング |
| 19 | PerspectiveCamera | 主機能 | 一人称視点カメラ |
| 7 | Timer | 補助機能 | ゲームループの時間管理 |

## 画面種別

ゲームサンプル画面（インタラクティブゲームデモ）

## URL/ルーティング

`examples/games_fps.html`

## 入出力項目

| 項目名 | 入出力 | データ型 | 説明 |
|--------|--------|----------|------|
| マウス移動 | 入力 | MouseEvent | カメラ視点の回転操作 |
| キーボード入力（WASD） | 入力 | KeyboardEvent | プレイヤーの移動方向 |
| キーボード入力（Space） | 入力 | KeyboardEvent | ジャンプ操作 |
| マウスクリック | 入力 | MouseEvent | ボール投擲操作 |
| GLTF モデルデータ | 入力 | ArrayBuffer | collision-world.glb |
| レンダリング結果 | 出力 | Canvas | 3Dゲーム画面の描画 |
| FPS表示 | 出力 | DOM | Stats.jsによるパフォーマンス表示 |

## 表示項目

| 表示項目 | 説明 |
|----------|------|
| 3Dゲームワールド | GLTFモデルで構成されたゲーム空間 |
| 投擲ボール | IcosahedronGeometryで生成された球体（最大100個） |
| 操作説明テキスト | "WASD to move", "SPACE to jump" 等 |
| Statsパネル | FPS・メモリ使用量の表示 |
| デバッグGUI | Octreeヘルパーの表示切り替え |

## イベント仕様

### 1-ポインターロック取得

**トリガー**: コンテナ要素のmousedown
**処理内容**:
1. `document.body.requestPointerLock()`を呼び出し
2. ポインターロック取得でマウス移動がカメラ回転に直結
3. `mouseTime`を記録（ボール投擲力計算用）

### 2-プレイヤー移動

**トリガー**: キーボード入力（keydown/keyup）
**処理内容**:
1. `keyStates`オブジェクトでキー状態を管理
2. WASDキーで前後左右の移動ベクトル計算
3. 地上/空中で移動速度を変更（地上:25、空中:8）
4. `playerVelocity`に移動量を加算

### 3-ジャンプ

**トリガー**: スペースキー押下（playerOnFloor時のみ）
**処理内容**:
1. `playerOnFloor`フラグを確認
2. `playerVelocity.y = 15`でジャンプ速度設定
3. 重力（GRAVITY = 30）により自然落下

### 4-ボール投擲

**トリガー**: mouseup（ポインターロック中）
**処理内容**:
1. カメラの向きから投擲方向を計算
2. 押下時間に応じた投擲力計算（15〜45）
3. プレイヤーの移動速度を考慮した初速設定
4. 球体オブジェクトプールから次のボールを使用

### 5-衝突検出（毎フレーム）

**トリガー**: animate()関数内
**処理内容**:
1. `worldOctree.capsuleIntersect()`でプレイヤー衝突判定
2. `worldOctree.sphereIntersect()`でボール衝突判定
3. 衝突法線に基づく反発処理
4. ボール同士の衝突判定と反発処理

## データベース更新仕様

該当なし（クライアントサイドのみで動作）

## メッセージ仕様

| メッセージ種別 | メッセージ内容 | 表示条件 |
|---------------|---------------|----------|
| 情報 | "Octree threejs demo - basic collisions with static triangle mesh" | ページロード時 |
| 情報 | "MOUSE to look around and to throw balls" | ページロード時 |
| 情報 | "WASD to move and SPACE to jump" | ページロード時 |

## 例外処理

| 例外状況 | 処理内容 |
|----------|----------|
| GLTFモデル読み込み失敗 | コンソールエラー出力、ゲーム空間が表示されない |
| WebGL非対応ブラウザ | エラーメッセージ表示 |
| ポインターロック非対応/拒否 | ゲーム操作が制限される |
| プレイヤーが画面外に落下 | Y座標が-25以下で初期位置にテレポート |

## 備考

- 物理演算はフレームレート非依存で実装（STEPS_PER_FRAME = 5でサブステップ処理）
- Octreeはthree.jsのaddonsとして提供（examples/jsm/math/Octree.js）
- Capsuleクラスでプレイヤーの衝突形状を定義（カプセル形状）
- VSMShadowMapを使用したソフトシャドウ
- ACESFilmicToneMappingでHDRトーンマッピング

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、衝突検出に使用されるデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Octree.js | `examples/jsm/math/Octree.js` | 八分木の構造、空間分割アルゴリズム |
| 1-2 | Capsule.js | `examples/jsm/math/Capsule.js` | カプセル形状の定義、衝突判定用 |

**読解のコツ**: Octreeは3D空間を再帰的に8分割し、衝突判定の対象を絞り込むことで計算量を削減する。fromGraphNode()でシーングラフから自動構築。

#### Step 2: エントリーポイントを理解する

処理の起点となるHTMLファイルとその初期化処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | games_fps.html | `examples/games_fps.html` | ゲームのエントリーポイント、初期化フロー |

**主要処理フロー**:
1. **41-46行目**: Timer、Scene、Fog、Camera初期化
2. **51-79行目**: レンダラー設定（シャドウ、トーンマッピング）
3. **86-113行目**: 球体プール初期化（NUM_SPHERES = 100）
4. **115-117行目**: Octree、PlayerCollider初期化
5. **415-452行目**: GLTFモデル読み込み、Octree構築
6. **469-494行目**: メインゲームループ（animate関数）

#### Step 3: 物理シミュレーション層を理解する

プレイヤーとボールの物理演算処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | games_fps.html（続き） | `examples/games_fps.html` | updatePlayer(), updateSpheres()関数 |

**主要処理フロー**:
- **198-222行目**: playerCollisions() - プレイヤー衝突判定
- **224-246行目**: updatePlayer() - 重力適用、ダンピング、位置更新
- **317-351行目**: updateSpheres() - ボール物理シミュレーション
- **281-315行目**: spheresCollisions() - ボール同士の衝突処理

### プログラム呼び出し階層図

```
games_fps.html
    │
    ├─ GLTFLoader.load('collision-world.glb')
    │      └─ worldOctree.fromGraphNode(gltf.scene)
    │
    ├─ animate()（メインループ）
    │      │
    │      ├─ timer.update()
    │      │
    │      └─ for (STEPS_PER_FRAME) {
    │             ├─ controls(deltaTime)
    │             │      └─ playerVelocity更新
    │             │
    │             ├─ updatePlayer(deltaTime)
    │             │      ├─ 重力適用
    │             │      ├─ playerCollider.translate()
    │             │      └─ playerCollisions()
    │             │             └─ worldOctree.capsuleIntersect()
    │             │
    │             ├─ updateSpheres(deltaTime)
    │             │      ├─ worldOctree.sphereIntersect()
    │             │      └─ playerSphereCollision()
    │             │
    │             └─ teleportPlayerIfOob()
    │          }
    │
    └─ renderer.render(scene, camera)
```

### データフロー図

```
[入力]                     [処理]                         [出力]

キーボード(WASD) ────▶ controls() ───────────────────▶ playerVelocity
                             │
                             └─ getForwardVector() / getSideVector()

マウス移動 ──────────▶ camera.rotation更新 ──────────▶ 視点方向

mouseup ─────────────▶ throwBall() ──────────────────▶ sphere.velocity
                             │
                             ├─ 投擲力計算（押下時間）
                             └─ プレイヤー速度加算

[毎フレーム]
playerCollider ──────▶ worldOctree.capsuleIntersect() ──▶ 衝突応答
                             │
                             └─ playerOnFloor判定

sphere.collider ─────▶ worldOctree.sphereIntersect() ───▶ 反発処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| games_fps.html | `examples/games_fps.html` | ソース | FPSゲームサンプルのメイン |
| Octree.js | `examples/jsm/math/Octree.js` | ソース | 八分木データ構造、空間分割 |
| OctreeHelper.js | `examples/jsm/helpers/OctreeHelper.js` | ソース | Octreeのデバッグ表示 |
| Capsule.js | `examples/jsm/math/Capsule.js` | ソース | カプセル形状定義 |
| GLTFLoader.js | `examples/jsm/loaders/GLTFLoader.js` | ソース | GLTFモデル読み込み |
| collision-world.glb | `examples/models/gltf/collision-world.glb` | アセット | ゲームワールドモデル |
| stats.module.js | `examples/jsm/libs/stats.module.js` | ライブラリ | FPS表示 |
| lil-gui.module.min.js | `examples/jsm/libs/lil-gui.module.min.js` | ライブラリ | デバッグGUI |
| main.css | `examples/main.css` | スタイル | サンプル共通スタイル |
