ProjectDirectory/
│
├── Main.cpp
├── StateMachine.hpp
├── CharacterStates.hpp
└── CharacterStateMachine.cpp
Last active
November 5, 2023 04:45
-
-
Save hattori8/edc6ed75ec83b563f06933da2991973c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CHARACTERSTATEMACHINE_HPP | |
#define CHARACTERSTATEMACHINE_HPP | |
#include "StateMachine.hpp" | |
#include "CharacterStates.hpp" | |
class CharacterStateMachine : public StateMachine<CharacterState> { | |
private: | |
Stopwatch stopwatch; | |
std::unordered_map<CharacterState, int32> stateTextSpeeds; | |
CharacterState previousState; | |
String currentStateText; | |
String characterName = U"ヒカリ"; | |
bool showCharacterName = false; | |
void resetStopwatch() { | |
stopwatch.restart(); | |
} | |
void drawTextByChar(const String& text, Vec2 pos, Color color, int32 speedInMilliseconds) { | |
const int32 count = (stopwatch.ms() / speedInMilliseconds); | |
draw(text.substr(0, count), pos, color); | |
} | |
// キャラクター名を表示するメソッド | |
void drawCharacterName() { | |
if (showCharacterName) { | |
draw(characterName, Vec2(120, 650), Palette::White); | |
} | |
} | |
public: | |
CharacterStateMachine(Font font) : StateMachine(font), previousState(static_cast<CharacterState>(0)) { | |
setupStates(); | |
} | |
void addStateWithSpeed(CharacterState state, const String& text, int32 speed, bool showName) { | |
stateTextSpeeds[state] = speed; | |
addState(state, [=, this]() mutable { | |
if (previousState != state) { | |
currentStateText = text; | |
showCharacterName = showName; | |
resetStopwatch(); | |
previousState = state; | |
} | |
drawTextByChar(currentStateText, Vec2(200, 700), Palette::White, stateTextSpeeds[state]); | |
}); | |
} | |
void update() { | |
drawCharacterName(); | |
StateMachine::update(); | |
} | |
void setupStates() { | |
// ステートの設定 | |
addStateWithSpeed(CharacterState::CallingForHelp1, U"こちらです、助けてください…!", 30, true); | |
addStateWithSpeed(CharacterState::CallingForHelp2, U"お願い…私を放っておかないで…", 100, false); | |
addStateWithSpeed(CharacterState::CallingForHelp3, U"誰か!助けてください!", 60, false); | |
addStateWithSpeed(CharacterState::DamageByPlayer, U"気にしないで、大丈夫ですから…", 30, true); | |
addStateWithSpeed(CharacterState::DamageByEnemy, U"まだ平気です、助けて…", 30, true); | |
addStateWithSpeed(CharacterState::PlayerDamaged1, U"大丈夫ですか?私、心配です…", 30, true); | |
addStateWithSpeed(CharacterState::PlayerDamaged2, U"本当にありがとう…", 30, true); | |
addStateWithSpeed(CharacterState::PlayerDamaged3, U"逃げてください!!それ以上はもう…!!", 30, true); | |
addStateWithSpeed(CharacterState::DeathByCollisionNarration, U"不運にもロボの機体が彼女の家を破壊した。", 20, false); | |
addStateWithSpeed(CharacterState::DeathByCollision, U"こんな終わり方、望んでなかった…", 70, true); | |
addStateWithSpeed(CharacterState::DeathByShotNarration, U"ロボの銃弾が彼女を撃ち抜いた。", 20, false); | |
addStateWithSpeed(CharacterState::DeathByShot, U"あなたのこと、ずっと覚えています…", 90, true); | |
addStateWithSpeed(CharacterState::DeathByEnemyNarration, U"敵の攻撃がとどめをさした。最後の言葉がこだまする。", 20, false); | |
addStateWithSpeed(CharacterState::DeathByEnemy, U"ごめんなさい、皆さん…", 140, true); | |
addStateWithSpeed(CharacterState::PlayerDeathNarration, U"惜しくも、ロボの体力は限界まで到達した。", 20, false); | |
addStateWithSpeed(CharacterState::PlayerDeath, U"こんなに早く…さよならなんて言いたくなかったです…", 90, true); | |
addStateWithSpeed(CharacterState::NearRescue, U"もう少し…持ちこたえて…", 30, true); | |
addStateWithSpeed(CharacterState::RescuedNarration, U"避難までの時間を稼ぐことで、彼女を救うことできた。", 20, false); | |
addStateWithSpeed(CharacterState::Rescued, U"助けてくれてありがとう。本当に感謝しています。", 80, true); | |
} | |
}; | |
#endif // CHARACTERSTATEMACHINE_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CHARACTERSTATES_HPP | |
#define CHARACTERSTATES_HPP | |
enum class CharacterState { | |
CallingForHelp1, | |
CallingForHelp2, | |
CallingForHelp3, | |
DamageByPlayer, | |
DamageByEnemy, | |
PlayerDamaged1, | |
PlayerDamaged2, | |
PlayerDamaged3, | |
DeathByCollisionNarration, | |
DeathByCollision, | |
DeathByShotNarration, | |
DeathByShot, | |
DeathByEnemyNarration, | |
DeathByEnemy, | |
PlayerDeathNarration, | |
PlayerDeath, | |
NearRescue, | |
RescuedNarration, | |
Rescued | |
}; | |
#endif // CHARACTERSTATES_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <Siv3D.hpp> | |
# include "CharacterStateMachine.cpp" | |
// ゲームの状態を表す enum | |
enum class GameState { | |
Title, | |
CharacterSelection, | |
Playing, | |
BadEndCollision, // プレイヤーがぶつかって死亡 | |
BadEndShot, // プレイヤーが撃ち抜いて死亡 | |
BadEndDefeat, // 敵に倒されて死亡 | |
GoodEnd // 救う | |
}; | |
// エンディングの状態を | |
enum class EndingState { | |
BadEndCollision, // プレイヤーがぶつかって死亡 | |
BadEndShot, // プレイヤーが撃ち抜いて死亡 | |
BadEndDefeat, // 敵に倒されて死亡 | |
GoodEnd // 救う | |
}; | |
// 敵の位置をランダムに作成する関数 | |
Vec2 GenerateEnemy() | |
{ | |
return RandomVec2({ 240, 1040 }, -20); | |
} | |
void Main() | |
{ | |
// ゲームの初期状態 | |
GameState gameState = GameState::Title; | |
// エンディングの初期状態 | |
EndingState endingState = EndingState::GoodEnd; | |
Scene::SetBackground(ColorF{ 0, 0, 0}); | |
// ウィンドウを 1280x900 にリサイズする | |
Window::Resize(1280, 900); | |
// フォント | |
const Font font{ FontMethod::MSDF, 36 }; | |
// テクスチャ | |
const Texture playerTexture{ U"🤖"_emoji }; | |
const Texture enemyTexture{ U"👾"_emoji }; | |
const Texture houseTexture{ U"🏠"_emoji }; | |
// 画像ファイルから Image を作成 | |
const Image image{ U"DALL·E 2023-11-04 23.35.47 - An anime-style illustration of a woman named Hikari in a grateful pose. She is clad in futuristic survival gear, sporting a vibrant blue and white jac.png" }; | |
// Image から Texture を作成 | |
const Texture texture{ image }; | |
// HP | |
constexpr int InitialPlayerHP = 50; | |
int playerHP = InitialPlayerHP; | |
constexpr int InitialHouseHP = 10; | |
int houseHP = InitialHouseHP; | |
// ポジション | |
Vec2 playerPos{ 640, 500 }; | |
Array<Vec2> enemies = { GenerateEnemy() }; | |
Vec2 housePos{ 640, 300 }; | |
// ショット | |
Array<Vec2> playerBullets; | |
Array<Vec2> enemyBullets; | |
// スピード | |
constexpr double PlayerSpeed = 550.0; | |
constexpr double PlayerBulletSpeed = 500.0; | |
constexpr double EnemySpeed = 100.0; | |
constexpr double EnemyBulletSpeed = 300.0; | |
// 敵の発生間隔の初期値(秒) | |
constexpr double InitialEnemySpawnInterval = 2.0; | |
// 敵の発生間隔(秒) | |
double enemySpawnTime = InitialEnemySpawnInterval; | |
// 敵の発生の蓄積時間(秒) | |
double enemyAccumulatedTime = 0.0; | |
// 敵ショットのクールタイム(秒) | |
constexpr double EnemyShotCoolTime = 0.9; | |
// 敵ショットのクールタイムタイマー(秒) | |
double enemyShotTimer = 0.0; | |
// 避難までの時間(秒) | |
constexpr double InitialEscapeTime = 30; | |
double escapeTime = InitialEscapeTime; | |
// ゲームプレイの初期化 | |
bool InitializedPlaying = false; | |
Effect effect; | |
// ステートマシン | |
CharacterStateMachine characterSM(font); | |
characterSM.setupStates(); | |
double timeSinceStateChange = 0; | |
while (System::Update()) | |
{ | |
// マウスカーソルを非表示に | |
Cursor::RequestStyle(CursorStyle::Hidden); | |
const double deltaTime = Scene::DeltaTime(); | |
// ステートマシンの更新 | |
characterSM.update(); | |
switch (gameState) | |
{ | |
// タイトル画面の処理 | |
case GameState::Title: | |
timeSinceStateChange += deltaTime; | |
characterSM.setState(CharacterState::CallingForHelp3); | |
if(timeSinceStateChange >= 4){ | |
characterSM.setState(CharacterState::CallingForHelp2); | |
} | |
// 'Enter' キーでキャラクター選択へ | |
if (KeyEnter.pressed()) { | |
timeSinceStateChange = 0; | |
gameState = GameState::CharacterSelection; | |
} | |
break; | |
// キャラクター選択画面の処理 | |
case GameState::CharacterSelection: | |
characterSM.setState(CharacterState::CallingForHelp1); | |
// 選択が完了したら 'H' キーでゲーム開始 | |
if (KeyH.pressed()) { | |
timeSinceStateChange = 0; | |
gameState = GameState::Playing; | |
} | |
break; | |
// バッドエンド | |
case GameState::BadEndCollision: | |
timeSinceStateChange += deltaTime; | |
characterSM.setState(CharacterState::DeathByCollisionNarration); | |
if(timeSinceStateChange >= 2){ | |
characterSM.setState(CharacterState::DeathByCollision); | |
} | |
// 'R' キーでタイトル画面へ | |
if (KeyR.pressed()) { | |
timeSinceStateChange = 0; | |
gameState = GameState::Title; | |
} | |
break; | |
case GameState::BadEndShot: | |
timeSinceStateChange += deltaTime; | |
characterSM.setState(CharacterState::DeathByShotNarration); | |
if(timeSinceStateChange >= 2){ | |
characterSM.setState(CharacterState::DeathByShot); | |
} | |
// 'R' キーでタイトル画面へ | |
if (KeyR.pressed()) { | |
timeSinceStateChange = 0; | |
gameState = GameState::Title; | |
} | |
break; | |
case GameState::BadEndDefeat: | |
timeSinceStateChange += deltaTime; | |
characterSM.setState(CharacterState::DeathByEnemyNarration); | |
if(timeSinceStateChange >= 2){ | |
characterSM.setState(CharacterState::DeathByEnemy); | |
} | |
// 'R' キーでタイトル画面へ | |
if (KeyR.pressed()) { | |
timeSinceStateChange = 0; | |
gameState = GameState::Title; | |
} | |
break; | |
// グッドエンド | |
case GameState::GoodEnd: | |
timeSinceStateChange += deltaTime; | |
characterSM.setState(CharacterState::RescuedNarration); | |
if(timeSinceStateChange >= 3){ | |
characterSM.setState(CharacterState::Rescued); | |
} | |
// 'R' キーでタイトル画面へ | |
if (KeyR.pressed()) { | |
timeSinceStateChange = 0; | |
gameState = GameState::Title; | |
} | |
break; | |
// ゲームプレイ中の処理 | |
case GameState::Playing: | |
// ゲームエンド判定 | |
bool gameend = false; | |
escapeTime -= deltaTime; | |
enemyAccumulatedTime += deltaTime; | |
enemyShotTimer += deltaTime; | |
// 敵を発生させる | |
while (enemySpawnTime <= enemyAccumulatedTime) | |
{ | |
enemyAccumulatedTime -= enemySpawnTime; | |
enemySpawnTime = Max(enemySpawnTime * 0.95, 0.3); | |
enemies << GenerateEnemy(); | |
} | |
// 自機の移動 | |
const Vec2 move = Vec2{ (KeyD.pressed() - KeyA.pressed()), (KeyS.pressed() - KeyW.pressed()) } | |
.setLength(deltaTime * PlayerSpeed * (KeyShift.pressed() ? 0.5 : 1.0)); | |
playerPos.moveBy(move).clamp(Scene::Rect()); | |
// 自機ショットの発射 | |
if (KeyF.down()) | |
{ | |
playerBullets << playerPos.movedBy(0, -50); | |
} | |
// 自機ショットを移動させる | |
for (auto& playerBullet : playerBullets) | |
{ | |
playerBullet.y += (deltaTime * -PlayerBulletSpeed); | |
} | |
// 画面外に出た自機ショットを削除する | |
playerBullets.remove_if([](const Vec2& b) { return (b.y < -40); }); | |
// 敵を移動させる | |
// 画面の中央座標を指定 | |
float screenCenterX = 640.0f; // 画面の中央のX座標 | |
float screenCenterY = 300.0f; // 画面の中央のY座標 | |
// 敵を画面の中央に向かって移動させる | |
for (auto& enemy : enemies) | |
{ | |
// 画面の中央に向かうベクトルを計算 | |
float dirX = screenCenterX - enemy.x; | |
float dirY = screenCenterY - enemy.y; | |
// ベクトルの長さを計算(距離) | |
float length = sqrt(dirX * dirX + dirY * dirY); | |
// 長さが0でないならば、ベクトルを正規化(方向のみを保持) | |
if (length > 0.01f) // ゼロ除算を避けるための微小値 | |
{ | |
dirX /= length; | |
dirY /= length; | |
} | |
// 敵を移動させる(正規化された方向ベクトルにスピードと時間を乗算) | |
enemy.x += dirX * (deltaTime * EnemySpeed); | |
enemy.y += dirY * (deltaTime * EnemySpeed); | |
// オプション: 画面中央に到達したら、さらに移動しないようにする | |
if (sqrt(pow(enemy.x - screenCenterX, 2) + pow(enemy.y - screenCenterY, 2)) < (deltaTime * EnemySpeed)) { | |
enemy.x = screenCenterX; | |
enemy.y = screenCenterY; | |
} | |
} | |
//////////////////////////////// | |
// | |
// 攻撃判定 | |
// | |
//////////////////////////////// | |
// 敵 vs 自機ショット | |
for (auto itEnemy = enemies.begin(); itEnemy != enemies.end();) | |
{ | |
const Circle enemyCircle{ *itEnemy, 40 }; | |
bool skip = false; | |
for (auto itBullet = playerBullets.begin(); itBullet != playerBullets.end();) | |
{ | |
if (enemyCircle.intersects(*itBullet)) | |
{ | |
// 爆発エフェクトを追加する | |
effect.add([pos = *itEnemy](double t) | |
{ | |
const double t2 = ((0.5 - t) * 2.0); | |
Circle{ pos, (10 + t * 280) }.drawFrame((20 * t2), AlphaF(t2 * 0.5)); | |
return (t < 0.5); | |
}); | |
itEnemy = enemies.erase(itEnemy); | |
playerBullets.erase(itBullet); | |
skip = true; | |
break; | |
} | |
++itBullet; | |
} | |
if (skip) | |
{ | |
continue; | |
} | |
++itEnemy; | |
} | |
// 敵 vs 自機の衝突判定 | |
for (auto itEnemy = enemies.begin(); itEnemy != enemies.end();) | |
{ | |
const Circle enemyCircle{ *itEnemy, 60 }; | |
if (enemyCircle.intersects(playerPos)) | |
{ | |
playerHP -= 5; | |
if(playerHP >= 40){ | |
characterSM.setState(CharacterState::PlayerDamaged1); | |
} | |
else if (playerHP >= 20){ | |
characterSM.setState(CharacterState::PlayerDamaged2); | |
} | |
else{ | |
characterSM.setState(CharacterState::PlayerDamaged3); | |
} | |
// 爆発エフェクトを追加する | |
effect.add([pos = *itEnemy](double t) | |
{ | |
const double t2 = ((0.5 - t) * 2.0); | |
Circle{ pos, (10 + t * 280) }.drawFrame((20 * t2), AlphaF(t2 * 0.5)); | |
return (t < 0.5); | |
}); | |
itEnemy = enemies.erase(itEnemy); | |
} | |
else | |
{ | |
++itEnemy; | |
} | |
} | |
// 敵 vs 家の衝突判定 | |
for (auto itEnemy = enemies.begin(); itEnemy != enemies.end();) | |
{ | |
const Circle enemyCircle{ *itEnemy, 40 }; | |
if (enemyCircle.intersects(housePos)) | |
{ | |
itEnemy = enemies.erase(itEnemy); | |
houseHP -= 5; | |
if(houseHP <= 0){ | |
gameend = true; | |
endingState = EndingState::BadEndDefeat; | |
} | |
else{ | |
characterSM.setState(CharacterState::DamageByEnemy); | |
// 爆発エフェクトを追加する | |
effect.add([pos = *itEnemy](double t) | |
{ | |
const double t2 = ((0.5 - t) * 2.0); | |
Circle{ pos, (10 + t * 280) }.drawFrame((20 * t2), AlphaF(t2 * 0.5)); | |
return (t < 0.5); | |
}); | |
} | |
} | |
else | |
{ | |
++itEnemy; | |
} | |
} | |
// プレイヤーのショット vs 家の衝突判定 | |
for (auto itBullet = playerBullets.begin(); itBullet != playerBullets.end();) | |
{ | |
const Circle bulletCircle{ *itBullet, 20 }; // 仮の弾のサイズ | |
if (bulletCircle.intersects(housePos)) | |
{ | |
itBullet = playerBullets.erase(itBullet); | |
houseHP -= 5; | |
if(houseHP <= 0){ | |
gameend = true; | |
endingState = EndingState::BadEndShot; | |
} | |
else{ | |
characterSM.setState(CharacterState::DamageByPlayer); | |
// 爆発エフェクトを追加する | |
effect.add([pos = *itBullet](double t) | |
{ | |
const double t2 = ((0.5 - t) * 2.0); | |
Circle{ pos, (10 + t * 280) }.drawFrame((20 * t2), AlphaF(t2 * 0.5)); | |
return (t < 0.5); | |
}); | |
} | |
} | |
else | |
{ | |
++itBullet; | |
} | |
} | |
// 自機 vs 家の衝突判定 | |
{ | |
const Circle playerCircle{ playerPos, 30 }; // 仮の自機のサイズ | |
if (playerCircle.intersects(housePos)) | |
{ | |
houseHP -= 10; | |
endingState = EndingState::BadEndCollision; | |
gameend = true; | |
} | |
} | |
if(escapeTime <= 0){ | |
gameend = true; | |
endingState = EndingState::GoodEnd; | |
} | |
if(escapeTime <= 3){ | |
characterSM.setState(CharacterState::NearRescue); | |
} | |
// ゲームエンドならリセットする | |
if (gameend) | |
{ | |
playerPos = Vec2{ 640, 500 }; | |
enemies.clear(); | |
playerBullets.clear(); | |
enemyBullets.clear(); | |
enemySpawnTime = InitialEnemySpawnInterval; | |
houseHP = InitialHouseHP; | |
playerHP = InitialPlayerHP; | |
escapeTime = InitialEscapeTime; | |
switch (endingState) { | |
case EndingState::BadEndCollision: | |
gameState = GameState::BadEndCollision; | |
break; | |
case EndingState::BadEndShot: | |
gameState = GameState::BadEndShot; | |
break; | |
case EndingState::BadEndDefeat: | |
gameState = GameState::BadEndDefeat; | |
break; | |
case EndingState::GoodEnd: | |
gameState = GameState::GoodEnd; | |
break; | |
default: | |
gameState = GameState::Title; | |
break; | |
} | |
} | |
break; | |
} | |
//////////////////////////////// | |
// | |
// 描画 | |
// | |
//////////////////////////////// | |
switch (gameState) | |
{ | |
case GameState::Title: | |
font(U"君を救うロボット").draw(80, Vec2{ 600, 300 }, Palette::White); | |
font(U"[Enter] ゲームスタート").draw(30, Vec2{ 600, 500 }, Palette::White); | |
font(U"[esc] ゲーム終了").draw(30, Vec2{ 600, 540 }, Palette::White); | |
break; | |
case GameState::CharacterSelection: | |
font(U"救う人").draw(80, Vec2{ 600, 300 }, Palette::White); | |
font(U"[H] ヒカリ (ロボットの家族)").draw(30, Vec2{ 600, 500 }, Palette::White); | |
// font(U"[?] FutureWork").draw(30, Vec2{ 600, 540 }, Palette::White); | |
break; | |
case GameState::BadEndCollision: | |
case GameState::BadEndShot: | |
case GameState::BadEndDefeat: | |
font(U"[R] 時をもどす").draw(30, Vec2{ 1000, 500 }, Palette::White); | |
break; | |
case GameState::GoodEnd: | |
if(timeSinceStateChange >= 7.5){ | |
texture.draw(); | |
font(U"fin").draw(60, Vec2{ 1100, 400 }, Palette::White); | |
} | |
if(timeSinceStateChange >= 12){ | |
font(U"[esc] ゲーム終了").draw(20, Vec2{ 1050, 820 }, Palette::White); | |
font(U"[R] 時をもどす").draw(20, Vec2{ 1050, 850 }, Palette::White); | |
} | |
break; | |
case GameState::Playing: | |
// 背景のアニメーションを描画する | |
for (int32 i = 0; i < 12; ++i) | |
{ | |
const double a = Periodic::Sine0_1(2s, Scene::Time() - (2.0 / 12 * i)); | |
Rect{ 240, (i * 50), 800, 50 }.draw(ColorF(1.0, a * 0.2)); | |
} | |
// 自機を描画する | |
playerTexture.resized(80).flipped().drawAt(playerPos); | |
// 自機ショットを描画する | |
for (const auto& playerBullet : playerBullets) | |
{ | |
Circle{ playerBullet, 8 }.draw(Palette::Orange); | |
} | |
// 敵を描画する | |
for (const auto& enemy : enemies) | |
{ | |
enemyTexture.resized(60).drawAt(enemy); | |
} | |
// 家を描画する | |
houseTexture.resized(50).drawAt(housePos); | |
// 爆発エフェクトを描画する | |
effect.update(); | |
// スコアを描画する | |
font(U"プレイヤーのHP").draw(24, Arg::bottomLeft(20, 50)); | |
font(U"{}"_fmt(playerHP)).draw(24, Arg::bottomLeft(20, 80)); | |
font(U"家のHP").draw(24, Arg::bottomLeft(20, 110)); | |
font(U"{}"_fmt(houseHP)).draw(24, Arg::bottomLeft(20, 140)); | |
font(U"避難までの時間").draw(24, Arg::bottomLeft(20, 170)); | |
font(U"{:.2f}"_fmt(escapeTime)).draw(24, Arg::bottomLeft(20, 200)); | |
// 操作方法を描画 | |
font(U"[WASD] 移動").draw(24, Arg::bottomRight(1240, 50)); | |
font(U"[F] 発射").draw(24, Arg::bottomRight(1240, 80)); | |
break; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef STATEMACHINE_HPP | |
#define STATEMACHINE_HPP | |
#include <Siv3D.hpp> | |
#include <functional> | |
#include <unordered_map> | |
template<typename T> | |
class StateMachine { | |
private: | |
T currentState; | |
Font font; | |
std::unordered_map<T, std::function<void()>> stateFunctions; | |
public: | |
StateMachine(Font font) : font(font) {} | |
// ステートを追加するメソッド | |
void addState(T state, std::function<void()> function) { | |
stateFunctions[state] = function; | |
} | |
// ステートをセットするメソッド | |
void setState(T newState) { | |
currentState = newState; | |
} | |
// 現在のステートの関数を実行する | |
void update() { | |
if (stateFunctions.find(currentState) != stateFunctions.end()) { | |
stateFunctions[currentState](); | |
} | |
} | |
// テキストを描画する汎用メソッド | |
void draw(const String& text, Vec2 position, ColorF color) const { | |
font(text).draw(Arg::leftCenter(position), color); | |
} | |
}; | |
#endif // STATEMACHINE_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment