# 機能設計書 65-カメラ制御

## 概要

本ドキュメントは、K-Shoot MANIA のプレイ画面におけるカメラ制御機能の設計を記述する。Zoom Top/Bottom/Side、Tilt、Spin、Half Spin、Center Split の各カメラパラメータを譜面データとレーザー入力に基づいてリアルタイムに制御し、3D空間でのレーン表示角度・位置を動的に変化させる。

### 本機能の処理概要

**業務上の目的・背景**：リズムゲームの演出効果として、譜面の盛り上がりやプレイヤーの入力に応じてレーンの表示角度や位置を動的に変化させることで、視覚的なダイナミクスを生み出す。カメラ制御はゲームの臨場感と演出品質を大きく左右する重要機能である。

**機能の利用シーン**：ゲームプレイ画面（SCENE_PLAY）の毎フレーム描画処理内で、drawFrame 関数の後半部分として実行される。譜面に記述されたカメラ制御命令（zoom_top, zoom_bottom, zoom_side, tilt, spin 等）と、レーザーの入力状態に基づいてカメラの姿勢を計算する。

**主要な処理内容**：
1. Tilt（傾き）の計算 - レーザー位置に基づく手動Tilt値と、数値指定によるTilt値の合成
2. Side Zoom の計算 - 左右方向の視点シフト（shake効果との合成）
3. Top Zoom の計算 - 上方向の視点角度変化（レーンの奥行き表現）
4. Bottom Zoom の計算 - 下方向の視点角度変化（判定ラインの拡大縮小）
5. Spin（回転）アニメーションの合成
6. Center Split の適用 - レーンの左右分割表示
7. 3Dオブジェクト（レーン・判定ライン）の角度・位置の設定
8. レーンメッシュの頂点座標計算（meshmap による変形）

**関連システム・外部連携**：ksmcore.dll の GameSystem によるカメラ値計算、HGIMG4 の3Dオブジェクト制御API。

**権限による制御**：LASER の MIRROR 設定（pturna）時に Tilt と Side Zoom の値を反転。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | play_draw_frame.hsp による Zoom/Tilt/Spin/Half Spin/Center Split カメラ制御 |

## 機能種別

3D描画制御 / アニメーション処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| game_system | int | Yes | GameSystem オブジェクトハンドル | ksmcore.dll で生成 |
| CAM_MANUAL_TILT | int | Yes | 手動Tilt値のカメラパラメータID | - |
| CAM_ZOOM_TOP | int | Yes | ZoomTop のカメラパラメータID | - |
| CAM_ZOOM_BOTTOM | int | Yes | ZoomBottom のカメラパラメータID | - |
| CAM_ZOOM_SIDE | int | Yes | ZoomSide のカメラパラメータID | - |
| CAM_CENTER_SPLIT | int | Yes | CenterSplit のカメラパラメータID | - |
| tiltrnow | float | Yes | 現在のTilt値（レーザー位置由来） | - |
| spinnow | int配列 | Yes | Spin パラメータ（タイプ/方向/長さ） | - |
| ror | float | Yes | Tilt の回転レート | - |
| romax | float | Yes | Tilt の最大角度 | - |
| csongver_int | int | Yes | 譜面バージョン番号 | 167以上で新仕様 |

### 入力データソース

ksmcore.dll の GetCurrentCamValue 関数、譜面パラメータ解析結果。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| dstat (最終回転角) | double | レーン全体の回転角度（ラジアン） |
| ztopnow | double | Top Zoom の現在値 |
| zbotnow | double | Bottom Zoom の現在値 |
| zsidenow | double | Side Zoom の現在値 |
| ztiltnow | double | 手動Tilt の現在値 |
| judgelrate | double | 判定アニメーションのスケール率 |
| judgelrate_cline | double | 判定ラインのスケール率 |

### 出力先

HGIMG4 の3Dオブジェクト（obj_lane, obj_lane_s, obj_judgel, obj_cline, obj_analogcur）への角度・位置・スケール設定。meshmap によるレーンメッシュの頂点変形。

## 処理フロー

### 処理シーケンス

```
1. Manual Tilt の計算
   └─ GetCurrentCamValue(CAM_MANUAL_TILT) * romax
   └─ MIRROR時は値を反転（pturna）
   └─ 補間処理: 前フレーム値との線形補間（ztilttime で制御）
   └─ ±14度にクランプ後、180度でゼロになる非線形変換
2. 背景描画（bg>=1）
   └─ ゲージ状態に応じた背景モデル切替（mod_bg0/mod_bg1）
   └─ Tilt に応じた背景の回転
3. レイヤーアニメーション（bg>=2）
   └─ bgspeed に応じたアニメーションフレーム更新
   └─ Tilt/回転に応じたレイヤーの角度設定
4. Side Zoom の計算
   └─ GetCurrentCamValue(CAM_ZOOM_SIDE) / 1.5 / 2.0
   └─ MIRROR時は反転
   └─ 前フレーム値との線形補間（ztime で制御）
   └─ sha（横揺れ）変数に加算
5. Top Zoom の計算
   └─ GetCurrentCamValue(CAM_ZOOM_TOP)
   └─ バージョン互換処理（csongver_int<167 で旧計算式）
   └─ 前フレーム値との線形補間
6. Bottom Zoom の計算
   └─ GetCurrentCamValue(CAM_ZOOM_BOTTOM) / 1.5 / 120.0
   └─ 正の値は /2.5 で減衰
   └─ 前フレーム値との線形補間
7. judgelrate / judgelrate_cline の計算
   └─ zbotnow から非線形変換で判定エフェクトのスケール率を算出
8. 最終回転角の計算
   └─ Tilt + Spin + SpinRP + ManualTilt を合成してラジアンに変換
9. 3Dオブジェクトの更新
   └─ setang / setpos でレーン・判定ライン・レーザーカーソルの姿勢設定
   └─ meshmap でレーンメッシュの頂点座標を変形
10. カメラ初期設定（initCamera）
    └─ カメラ角度: -15度（-M_PI/12）
    └─ カメラ位置: Y=-45, Z=366
```

### フローチャート

```mermaid
flowchart TD
    A[drawFrame 後半] --> B[Manual Tilt 計算]
    B --> C[背景回転設定]
    C --> D[レイヤーアニメーション]
    D --> E[Side Zoom 計算]
    E --> F[Top Zoom 計算]
    F --> G[Bottom Zoom 計算]
    G --> H[judgelrate 計算]
    H --> I[最終回転角合成]
    I --> J[3Dオブジェクト姿勢更新]
    J --> K[meshmap でメッシュ変形]
    K --> L[テクスチャ取得]
    L --> M[hgdraw で3D描画]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-65-1 | MIRROR 反転 | pturna=1 の場合、Manual Tilt と Side Zoom の値を反転 | LASER MIRROR 設定時 |
| BR-65-2 | バージョン互換 | csongver_int<167 の場合、旧バージョンの計算式を使用 | 旧バージョン譜面 |
| BR-65-3 | Tilt クランプ | Manual Tilt は ±14度にクランプされ、90度・180度でゼロに近づく非線形変換が適用 | 常時 |
| BR-65-4 | 補間処理 | 各カメラ値は前フレーム値との線形補間で滑らかに変化 | 常時 |
| BR-65-5 | 背景切替条件 | ゲージ70%以上（通常）or 30%以上（HARD/コース）で背景1、それ未満で背景0 | bg>=1 |

### 計算ロジック

**最終回転角（dstat）の合成**:
```
dstat = deg2rad(
  ror * tiltrnow/1000 * (1 - ztiltrate)  // レーザー由来Tilt
  + spinangle                              // Spin アニメーション
  + spinrp * (残り時間補間)               // SpinRP
  + ztiltnow * ztiltrate                   // 数値指定Tilt
)
```

**judgelrate の計算（バージョン167以上）**:
```
judgelrate = (
  pow(max(zbotnow + 基準値, 0) / 基準値, 非線形指数)
  + 0.4545 * pow(1.1, min((-基準値 + zbotnow) / 基準値, 1))
) / 1.5
```

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | テクスチャ反転 | Top Zoom が180度を超えてレーンが上下反転 | f=1 で座標とテクスチャを反転 |

### リトライ仕様

該当なし。

## トランザクション仕様

該当なし。

## パフォーマンス要件

毎フレーム実行される描画処理。meshmap による頂点変形は毎フレーム実行されるが、2x2メッシュのため計算量は小さい。

## セキュリティ考慮事項

該当なし。

## 備考

- fv1 = -0.6125（ラジアン）はカメラ座標と判定ラインが並んだ線の正面方向からの角度を表す固定値（782行目）
- Spin アニメーションには通常 Spin、Half Spin、SpinRP の3種類がある
- レーンの3D表示は addmesh で生成された1x1メッシュを meshmap で変形する方式

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | カメラパラメータ定数: CAM_MANUAL_TILT, CAM_ZOOM_TOP, CAM_ZOOM_BOTTOM, CAM_ZOOM_SIDE, CAM_CENTER_SPLIT |
| 1-2 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | mod_lane / mod_lane_s / mod_cline / mod_judgel: レーンと判定ラインの3Dモデル |

**読解のコツ**: HGIMG4 では `addmesh` でモデル作成、`regobj` でオブジェクト登録、`setang/setpos/setscale` で姿勢制御を行う。`meshmap` はメッシュの頂点座標を直接操作する関数。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | drawFrame 関数の **628行目以降** がカメラ制御処理 |

**主要処理フロー**:
1. **629-640行目**: Manual Tilt の計算（GetCurrentCamValue、補間、クランプ）
2. **643-672行目**: 背景描画とレイヤーアニメーション
3. **683-694行目**: Side Zoom の計算
4. **697-707行目**: Top Zoom の計算
5. **712-719行目**: Bottom Zoom の計算
6. **722-737行目**: judgelrate / judgelrate_cline の計算
7. **740行目**: 最終回転角の合成
8. **746-757行目**: 3Dオブジェクトの姿勢設定
9. **793-843行目**: meshmap によるレーンメッシュの変形

#### Step 3: カメラ初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | **243-251行目**: initCamera 関数。カメラ角度 -15度、Y=-45, Z=366 |

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

```
play_update (メインループ)
    |
    +-- drawFrame
            |
            +-- GetCurrentCamValue(game_system, CAM_*)  // ksmcore.dll
            +-- setang / setpos / setscale              // HGIMG4
            +-- meshmap                                  // HGIMG4
            +-- hgdraw                                   // HGIMG4 3D描画実行

play_init (初期化)
    |
    +-- initCamera
    +-- initLaneObject
    +-- initJudgmentLineObject
    +-- initJudgmentAnimObject
```

### データフロー図

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

GetCurrentCamValue
  CAM_MANUAL_TILT  ───>    ┌──────────────────────┐
  CAM_ZOOM_TOP     ───>    |  カメラ値計算         |       dstat (回転角)
  CAM_ZOOM_BOTTOM  ───>    |  ├─ Tilt 計算        |  ──>  obj_lane 姿勢
  CAM_ZOOM_SIDE    ───>    |  ├─ Zoom 計算        |       obj_cline 姿勢
  CAM_CENTER_SPLIT ───>    |  ├─ 補間処理         |       obj_judgel 姿勢
                            |  └─ 合成             |       meshmap 頂点変形
tiltrnow (レーザー) ───>    |                      |
spinnow (Spin)      ───>    └──────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | ソース | カメラ制御の主処理（628-857行目） |
| play_graphics.hsp | `src/scene/play/play_graphics.hsp` | ソース | カメラ・レーン・判定ラインの初期化（185-251行目） |
| ksmcore.as | `src/ksmcore.as` | ソース | GetCurrentCamValue のDLLバインディング |
| play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | ソース | tiltrnow, spinnow 等のカメラパラメータ更新 |
