# 機能設計書 66-背景描画

## 概要

本ドキュメントは、K-Shoot MANIA のプレイ画面における背景描画機能の設計を記述する。desert/sky/ocean/space/flame/snow/cloudy/cyber 等30種以上の背景パターンと、レイヤーアニメーションをプレイ中にリアルタイムで描画する。

### 本機能の処理概要

**業務上の目的・背景**：リズムゲームの演出において、背景は楽曲の雰囲気やプレイの盛り上がりを視覚的に表現する重要な要素である。ゲージの状態に応じて背景が切り替わることで、プレイヤーにクリア状況を直感的に伝える役割も果たす。

**機能の利用シーン**：ゲームプレイ画面（SCENE_PLAY）において、bg 変数が1以上の場合に背景描画が有効になる。bg=1で静止背景、bg=2以上でレイヤーアニメーション付き背景が表示される。譜面ファイルの bg パラメータで背景名が指定される。

**主要な処理内容**：
1. 背景画像のロード（loadBGGraphics）：背景名に基づきJPEG画像をロードし、キャッシュを生成
2. レイヤーアニメーションのロード（loadLayerGraphics）：GIFアニメーション画像をフレーム分割してスプライト化
3. 背景の描画：ゲージ状態に応じたmod_bg0/mod_bg1の切替
4. レイヤーアニメーションの描画：bgspeed に応じたフレームレート制御
5. 背景・レイヤーの回転制御：Tilt値に連動した回転
6. カスタム背景対応：譜面ディレクトリ内の画像ファイルを直接参照

**関連システム・外部連携**：HGIMG4の3Dスプライト描画。artlet2d によるJPEG画像のリサイズとキャッシュ生成。

**権限による制御**：描画品質設定（lowquality / bg 変数）により背景描画の有無が制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | play_draw_frame.hsp / play_graphics.hsp による背景パターン描画 |

## 機能種別

描画処理 / リソース管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| bgname | string | Yes | 背景名（desert, sky, ocean 等） | imgs/bg/ ディレクトリに存在する名前 |
| bgname_l | string | Yes | レイヤーアニメーション名 | imgs/bg/ ディレクトリに .gif として存在 |
| bg | int | Yes | 背景描画モード（0=なし, 1=静止, 2+=アニメーション付き） | 0以上 |
| bgspeed | int | Yes | レイヤーアニメーション速度 | 0=BPM連動, 正=ms周期, 負=逆再生 |
| bgrotation | int | Yes | レイヤーの回転タイプ（0-3） | 0=なし, 1=Tilt, 2=BPM, 3=両方 |
| gauge | int | Yes | 現在のゲージ値 | - |
| gaugemax | int | Yes | ゲージの最大値 | - |
| effratetype | int | Yes | ゲージタイプ（<=0:通常, >0:HARD） | - |

### 入力データソース

譜面ファイル（.ksh）の bg パラメータ、layer パラメータ。リソース画像（imgs/bg/）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| obj_bg | int | 背景3Dオブジェクトハンドル |
| obj_layer | int | レイヤー3Dオブジェクトハンドル |
| mod_bg0 / mod_bg1 | int | ゲージ低/高状態の背景モデル |
| mod_layer | int配列 | レイヤーアニメーションのモデル配列 |

### 出力先

HGIMG4 の3Dスプライトとして画面背景に描画。

## 処理フロー

### 処理シーケンス

```
1. 背景画像のロード (loadBGGraphics)
   1-1. bgname + "0.jpg" / "1.jpg" の存在確認
   1-2. 存在しない場合、セミコロン区切りのカスタムパス解析を試行
   1-3. それでも見つからない場合、"desert" にフォールバック
   1-4. cache/bg/ ディレクトリにリサイズ済みキャッシュが存在しなければ生成
   1-5. texload でテクスチャ読み込み → addspr でスプライトモデル作成
   1-6. regobj でオブジェクト登録
2. レイヤーアニメーションのロード (loadLayerGraphics)
   2-1. bgname_l + ".gif" の存在確認
   2-2. 存在しない場合、カスタムパスを試行、なければ "arrow" にフォールバック
   2-3. GIF 画像を buffer にロード
   2-4. 画像幅を 600 で割ってフレーム数(layermax) を算出
   2-5. フレーム分割 → gzoom でリサイズ → addspr でスプライト化
   2-6. ev_layeruv イベントを生成（UVアニメーション用）
3. フレーム更新 (drawFrame 内)
   3-1. ゲージ状態に応じて mod_bg0/mod_bg1 を切替 (setobjmodel)
   3-2. bgspeed に応じてレイヤーのアニメーションフレームを更新
   3-3. 背景とレイヤーにTilt回転角を適用 (setang)
```

### フローチャート

```mermaid
flowchart TD
    A[play_init] --> B[loadBGGraphics]
    B --> C{bgname画像存在?}
    C -->|Yes| D[キャッシュ確認・生成]
    C -->|No| E{カスタムパス?}
    E -->|Yes| F[カスタム画像ロード]
    E -->|No| G[desertにフォールバック]
    D --> H[texload → addspr → regobj]
    F --> H
    G --> D
    H --> I[loadLayerGraphics]
    I --> J{bg>=2?}
    J -->|Yes| K[GIF読み込み → フレーム分割]
    J -->|No| L[スキップ]
    K --> M[play_update: drawFrame]
    L --> M
    M --> N{ゲージ状態変化?}
    N -->|Yes| O[背景モデル切替]
    N -->|No| P[レイヤーフレーム更新]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-66-1 | デフォルト背景 | 指定背景が見つからない場合は "desert" にフォールバック | 背景画像不在時 |
| BR-66-2 | デフォルトレイヤー | 指定レイヤーが見つからない場合は "arrow" にフォールバック | レイヤー画像不在時 |
| BR-66-3 | キャッシュ生成 | cache/bg/ にリサイズ済みJPEGがなければ自動生成 | 初回ロード時 |
| BR-66-4 | ゲージ連動切替 | 通常ゲージ70%以上、HARDゲージ30%以上で背景1に切替 | ゲージ変動時 |
| BR-66-5 | カスタム背景 | セミコロン区切りで2つの画像パスを指定可能 | カスタム譜面 |
| BR-66-6 | レイヤー回転 | bgrotation: 0=なし, 1=Tilt連動, 2=BPM連動, 3=両方 | bg>=2 |

### 計算ロジック

**キャッシュ画像サイズ**: `getsize(900) x getsize(800)` (解像度依存)

**レイヤーフレーム算出**:
- bgspeed=0: `layernow = (cnow-cnowstart) / 350 % layermax`（BPM連動）
- bgspeed>0: `layernow = ((t+3400+1000*(cmovfile!="")) % bgspeed) * layermax / bgspeed`
- bgspeed<0: `layernow = layermax - 1 - 上記`（逆再生）

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 背景画像不在 | bgname の画像が存在しない | "desert" にフォールバック |
| - | レイヤー画像不在 | bgname_l の画像が存在しない | "arrow" にフォールバック |
| - | cache/bg ディレクトリ不在 | 初回起動時 | mkdir で自動作成 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

背景画像のロードは play_init 時に1回のみ。毎フレームの描画処理はスプライト切替（setobjmodel）とUVアニメーション（setevent）のみで軽量。

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

該当なし。

## 備考

- 背景画像は720x640ピクセルの元画像を解像度に応じてリサイズしてキャッシュする
- レイヤーのGIF画像は横に600ピクセルずつフレームが並んだスプライトシート形式
- カスタム背景はセミコロン区切りで2つのパスを指定（ゲージ低/高状態用）
- 背景の描画モード(bg)は描画品質設定によって制御される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | mod_bg0, mod_bg1: ゲージ低/高状態の背景3Dモデル |
| 1-2 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | mod_layer: レイヤーアニメーションのモデル配列（3フレームずつ） |
| 1-3 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | ev_layeruv: UVアニメーションイベント配列[2][3] |

#### Step 2: 背景ロード処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | **50-124行目**: loadBGGraphics 関数。背景画像のロードとキャッシュ生成 |

**主要処理フロー**:
1. **53-56行目**: bgname+"0.jpg"/"1.jpg" の存在確認
2. **57-74行目**: カスタムパス（セミコロン区切り）の解析
3. **77-79行目**: cache/bg ディレクトリの自動作成
4. **81-103行目**: キャッシュ生成（alStretchScreenToImage → alSaveFile）
5. **122行目**: regobj でオブジェクト登録

#### Step 3: レイヤーロード処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_graphics.hsp | `src/scene/play/play_graphics.hsp` | **126-169行目**: loadLayerGraphics 関数 |

**主要処理フロー**:
1. **128-137行目**: GIF画像の存在確認とフォールバック
2. **144行目**: `layermax = ginfo_winx / 600` でフレーム数算出
3. **146-153行目**: フレーム分割とスプライト化
4. **160-167行目**: UVアニメーションイベントの生成

#### Step 4: フレーム更新処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | **643-672行目**: drawFrame 内の背景・レイヤー更新処理 |

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

```
play_init (初期化)
    |
    +-- loadBGGraphics
    |       +-- exist (画像存在確認)
    |       +-- picload / alStretchScreenToImage / alSaveFile (キャッシュ生成)
    |       +-- texload / addspr / regobj (3Dモデル化)
    |
    +-- loadLayerGraphics
            +-- picload (GIFロード)
            +-- gzoom / addspr (フレーム分割・スプライト化)
            +-- newevent / event_uv (UVアニメーション)

play_update (メインループ)
    |
    +-- drawFrame
            +-- setobjmodel (背景モデル切替)
            +-- setevent (レイヤーUV更新)
            +-- setang (回転制御)
```

### データフロー図

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

bgname (譜面)       ───>    loadBGGraphics
bgname_l (譜面)     ───>    loadLayerGraphics
                              |
imgs/bg/*.jpg       ───>    ┌──────────────────────┐
imgs/bg/*.gif       ───>    |  画像ロード           |       mod_bg0 / mod_bg1
                             |  キャッシュ生成       |  ──>  mod_layer
                             |  フレーム分割         |       obj_bg / obj_layer
                             └──────────────────────┘

gauge / effratetype ───>    drawFrame
tiltrnow            ───>    ┌──────────────────────┐
bgspeed             ───>    |  背景モデル切替       |  ──>  3D描画出力
cnow / t            ───>    |  レイヤーフレーム更新  |
                             |  回転角設定           |
                             └──────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_graphics.hsp | `src/scene/play/play_graphics.hsp` | ソース | loadBGGraphics (50-124行目), loadLayerGraphics (126-169行目) |
| play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | ソース | 背景・レイヤーのフレーム更新 (643-672行目) |
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | 譜面からの bgname/bgname_l/bgspeed/bgrotation の読み込み |
| imgs/bg/ | `imgs/bg/` | リソース | 背景画像ファイル群（.jpg / .gif） |
| cache/bg/ | `cache/bg/` | キャッシュ | リサイズ済み背景画像のキャッシュ |
