[HOME](https://hackmd.io/2BHmUlxZRy-eNbUEF2Mc-A?view)
# インゲーム設計
## クラス
### ボツ案
```cpp=
class StageManager {
private:
NoteManager noteManager;
Player player;
MusicData musicData;
public:
void loadFromFile(filePath) {
// 譜面、メタデータファイルから情報取得
noteManager.loadNotesFromCSV(CSV文字列)
}
void update() {
noteManager.update();
player.update();
}
void draw() const {
noteManager.draw();
player.sraw();
}
}
class NoteManager {
private:
Array<Note*> notes;
public:
void loadNotesFromCSV(String rawCSV) {
// csv文字列からノーツ読み込み
}
void update() {
for (auto note : notes) {
note->update();
}
}
void draw() const {
for (auto note : notes) {
note->draw();
}
}
}
class Player {
public:
void animate(PlayerAnimation);
void update();
void drawAt(Vec2 pos);
}
class MusicData {
public:
double bpm;
int beatPerMeasure;
Duration firstBeatTimePos
}
```
## 設計(決定)
```mermaid
classDiagram
InGame "1" --> "1" Notes
Notes "1" --> "0..n" Note
Note <|-- それぞれのNote
class InGame {
-Array<Note*> notes
-Audio music
+update()
+draw()
-judge(now): Judgment
}
class Notes {
-Array<Note*> notes
+notesInsideScreen(now): Array
}
class Note {
+draw()
}
```
```cpp
class Notes {
Array <std::shared_ptr<Note>> notes;
Init() {
// 譜面読み込み
while() {
notes << std::make_shared<Node>(args...);
}
}
notesInsideScreen(now) {
return notes.filter([](Note *n){ return !n->isOutOfRange(now); });
}
}
class InGame {
Notes notes = {...};
Audio music;
InGame::update() {
inputType = ...
now = music.posSec();
player.update();
effectManager.update();
for (auto note : notes.notesInsideScreen(now)) {
note.update(); // animation
judge.judge(now, note, inputType);
}
}
InGame::draw() {
now = 今の時間
for (auto note : notes.notesInsideScreen(now)) {
note.draw();
}
}
const double margin = 0.1;
Judgment judge(now, note, inputType) {
// 画面に入ってきてすぐのノーツに反応してしまう
// ジャッジはプレイヤーの一定範囲内でのみ行う
if (!note->isActive())
return Judgment::None;
if (note->type != inputType)
return Judgment::None;
if (abs(now - note->time) < margin) {
return Judgment::Success;
} else {
return Judgment::failure;
}
}
}
class Note {
protected:
Note(Duration timePos, double intervalBeat)
: timePos(timePos), intervalBeat(intervalBeat) {}
virtual ~Note() {} // 仮想デストラクタ
const Duration timePos; // ノーツの配置位置(s)
const double intervalBeat; // ノーツが出現してからプレイヤーに衝突するまでの拍数
NoteState state; // ノーツの状態(回避に成功したかどうか)
AvoidType avoidType; // 回避の仕方
public:
virtual void update(Duration now, Player player) = 0;
virtual void draw(Duration now, Player player) const = 0;
virtual bool isActive() const = 0;
void setState(NoteState nextState) {
this->state = nextState;
}
bool isOutOfRange(double now) {
}
}
```
Note::update()で何をするか?
InGameシーンがすべてのノーツと曲をもち、画面内ノーツを対象に処理・判定を行う。
シーンがJudgeしてもいいよね?
### Animation
AnimationTexture.h
```cpp
class AnimationTexture {
private:
Texture texture; // 元となる画像
Point frameSize; // 1フレームのサイズ(ピクセル)
int numFrame; // フレーム数
public:
AnimationTexture(Texture texture, Point frameSize);
// 指定したフレーム番号のテクスチャを返す
Texture frame(int frame);
// switchSpanの期間ごとにフレームを切り替えたテクスチャを返す
// timePosの剰余を取ってアニメーションさせる
// (timePos / switchSpan) mod numFrame
Texture animateByTime(Duration timePos, Duration switchSpan);
}
```
AnimationTexture.cpp
```cpp
AnimationTexture::AnimationTexture(Texture texture, Point frameSize, int numFrame)
: texture(texture), frameSize(frameSize), numFrame(numFrame) {}
Texture AnimationTexture::draw(int frame) {
// 実装
}
Texture AnimationTexture::animateByTime(Duration timePos, Duration switchSpan) {
// 実装
}
```
### UV管理(仮)
`playerJump.png`
画像。
`playerJump.json`
UVをずらすために1フレームの横と縦の長さを指定する。
```json
{
"widthPerFrame": 10,
"heightPerFrame": 20
}
```
CSVでもいいかもー
`playerJump.csv`
```csv
10,20
```
### アセット管理
Asset.h
```cpp=
namespace Asset {
namespace Texture {
String playerRun{U"playerRun.png"};
String playerJump{U"playerJump.png"};
}
}
```
Asset.cpp
```cpp=
void RegisterAsset() {
}
```