---
# System prepended metadata

title: ゲーム画面実装メモ
tags: [2024春みんげ～アクションチーム]

---

[HOME](https://hackmd.io/2BHmUlxZRy-eNbUEF2Mc-A?view)
# ゲーム画面実装メモ
ノーツの描画を時間の関数として実装するためのメモ
## 計算式

### ボツ案
<details>
**必要な情報**

- プレイヤーから右画面端までの時間的距離(s)
- ノーツの移動速度(pixel/s)
- ノーツの配置位置(s)
- 楽曲再生位置(s)
- bpm


**プレイヤーから右画面端までの時間的距離(s)**
= プレイヤーから右画面端までの距離(pixel) / ノーツの移動速度(pixel/s) 

**ノーツのプレイヤーからの相対時間(s)(ノーツがプレイヤーに重なるまでの時間)**
= ノーツの配置位置(s) - 楽曲再生位置(s)

**ノーツのプレイヤーからの相対x座標(pixel)**
= ノーツのプレイヤーからの相対時間(s) * ノーツの移動速度(pixel/s)
= (ノーツの配置位置(s) - 楽曲再生位置(s)) * ノーツの移動速度(pixel/s)
※ 参考まで、ノーツが必ずしもプレイヤーに向かって等速直線運動するわけではない？

**１拍の間隔(s/beat)** = 60 / bpm
**１拍の間隔(pixel)**
= １拍の間隔(s/beat) * ノーツの移動速度(pixel/s)
= (60 / bpm) * ノーツの移動速度(pixel/s)

**ノーツのプレイヤーからの相対拍位置(beat)**
= ノーツのプレイヤーからの相対時間(s) / 1拍の間隔(s/beat)
= (ノーツの配置位置(s) - 楽曲再生位置(s)) / (60 / bpm)
= (ノーツの配置位置(s) - 楽曲再生位置(s)) * bpm / 60
</details>

### 案
**必要な情報**

- ノーツが出現してからプレイヤーに衝突するまでの拍数(beat)
- ノーツの配置位置(s)
- 楽曲再生位置(s)
- bpm

**ノーツのプレイヤーからの相対時間(s)(ノーツがプレイヤーに重なるまでの時間)**
= ノーツの配置位置(s) - 楽曲再生位置(s)

**１拍の間隔(s/beat)** = 60 / bpm

**ノーツが出現してからプレイヤーに衝突するまでの時間(s)**
= ノーツが出現してからプレイヤーに衝突するまでの拍数(beat) * 1拍の間隔(s/beat)
= ノーツが出現してからプレイヤーに衝突するまでの拍数(beat) * 60 / bpm

**ノーツ出現からプレイヤー衝突までの進行率(%)**
= ノーツのプレイヤーからの相対時間(s) / ノーツが出現してからプレイヤーに衝突するまでの時間(s)
= (ノーツの配置位置(s) - 楽曲再生位置(s)) / (ノーツが出現してからプレイヤーに衝突するまでの拍数(beat) * 60 / bpm)

**ノーツがプレイヤーに衝突するまでの残りビート数(beat)**
= ノーツのプレイヤーからの相対時間(s) / 1拍の間隔(s/beat)

**ノーツ出現を基準とした経過ビート数(beat)**
= (楽曲再生位置(s) - (ノーツの配置位置(s) - ノーツが出現してからプレイヤーに衝突するまでの時間(s))) / １拍の間隔(s/beat)



### 計算式から考えるノーツ描画の実装方法
```cpp=
// 1拍の間隔(s)を計算する
Duration secPerBeat(double bpm) {
    return 60 / bpm;
}

class HogeNote {
private:
    const Duration posSec = 10s; // ノーツの配置位置(s)
    const double intervalBeat = 1.5; // ノーツが出現してからプレイヤーに衝突するまでの拍数
    ??? status; // ノーツの状態（回避に成功したかどうか）
    
    // ノーツが出現してからプレイヤーに衝突するまでの時間を計算する
    Duration intevalSec(double bpm) const {
        return intervalBeat * secPerBeat(bpm);
    }
    
    // プレイヤーがノーツに衝突するまでの時間(s)
    // 衝突する前は+ 後は-
    Duration culcDiffSec(Duration musicPosSec) const {
        return posSec - musicPosSec;
    }
    
    // プレイヤーがノーツに衝突するまでの残りビート数
    // 衝突する前は+ 後は-
    double culcDiffBeat(musicPosSec, bpm) const {
        return culcDiffSec(musicPosSec) / secPerBeat(bpm);
    }
    
    // ノーツ出現を基準とした経過ビート数を計算する
    // double culcElapsedBeat(Duration musicPosSec, double bpm) const {
    //     return (musicPosSec - (posSec - intervalSec(bpm))) / secPerBeat(bpm)
    // }

public:
    void draw(musicPosSec, bpm) const {
        const double diffBeat = culcDiffBeat(musicPosSec, bpm);
        
        if (diffBeat > 1) {
            // 出現してからの0.5拍で、フィールドへの出現のアニメーションを行う
        } else { // elapsedBeat <= 1
            // switch-caseを使う代わりに、変数で保持した画像を表示するとよい
            // 画像は成功・失敗時に差し替える
            switch (status) {
            case プレイヤーに衝突する前:
                // 1拍前からプレイヤーに衝突するまでの予備動作を描画する
                break;
            case プレイヤーが回避に成功した:
                // 回避に成功した場合の描画
                break;
            case プレイヤーが回避に失敗した:
                // 回避に失敗した場合の描画
                break;
            }
        }       
    }
    
    void update(musicPosSec, bpm) const {
        const double diffBeat = culcDiffBeat(musicPosSec, bpm);
        
        if (diffBeat <= 1) {
            // 1拍前になったら1回だけ前フリの効果音を鳴らす処理
        }
    }
    
}
```

## データフロー
### NoteManager => Note::draw()



## コード
### NoteManager
```cpp=
Array<Note*> notes;
void draw() const {
    for (auto note : notes) {
        note->draw(musicPosSec, bpm);
    }
}
```

### Note
インターフェース定義
```
interface Note {
    ノーツの配置時間(s)を取得する
    update
    void draw(musicPosSec, bpm) const;
    void update(musicPosSec, bpm);
}
```
```cpp=
void HogeNote::draw(musicPosSec, bpm) const {
    
}
```
