IMX6U-Game/src/Apps/LightGame/src/engine/GameStateManager.cpp

174 lines
5.0 KiB
C++

#include "GameStateManager.h"
#include "DrawContext.h"
#include "BitmapFont.h"
#include "ButtonInput.h"
#include "IKeyboardState.h"
#include <cstdio>
namespace LightGame
{
GameStateManager::GameStateManager()
: state_(GameState::Title),
hud_(),
title_blink_ms_(0),
title_show_prompt_(true),
esc_was_down_(false)
{
}
void GameStateManager::update(GameState current_state, const Platform::IButtonInput* button, const Platform::IKeyboardState* keyboard, uint32_t dt_ms)
{
state_ = current_state;
const bool esc_down = keyboard && keyboard->is_key_down(Platform::KEY_ESC);
const bool esc_pressed = esc_down && !esc_was_down_;
esc_was_down_ = esc_down;
switch (state_)
{
case GameState::Title:
title_blink_ms_ += dt_ms;
if (title_blink_ms_ >= 500)
{
title_blink_ms_ -= 500;
title_show_prompt_ = !title_show_prompt_;
}
break;
case GameState::Playing:
if (esc_pressed || (button && button->was_pressed()))
{
state_ = GameState::Paused;
}
break;
case GameState::Paused:
if (esc_pressed || (button && button->was_pressed()))
{
state_ = GameState::Playing;
}
break;
case GameState::GameOver:
case GameState::LevelComplete:
break;
}
}
void GameStateManager::draw(Core::DrawContext& ctx, const RenderData::BitmapFont& font,
int32_t screen_w, int32_t screen_h)
{
switch (state_)
{
case GameState::Title:
draw_title(ctx, font, screen_w, screen_h);
break;
case GameState::Playing:
draw_hud(ctx, font, screen_w, screen_h);
break;
case GameState::Paused:
draw_hud(ctx, font, screen_w, screen_h);
draw_pause(ctx, font, screen_w, screen_h);
break;
case GameState::GameOver:
draw_game_over(ctx, font, screen_w, screen_h);
break;
case GameState::LevelComplete:
draw_level_complete(ctx, font, screen_w, screen_h);
break;
}
}
void GameStateManager::draw_title(Core::DrawContext& ctx, const RenderData::BitmapFont& font,
int32_t w, int32_t h)
{
ctx.fill_rect(0, 0, w, h, RenderData::Color(0, 0, 40, 255));
const char* title = "LIGHT QUEST";
const int32_t title_x = (w - 11 * 8) / 2;
const int32_t title_y = h / 3;
ctx.draw_text(font, title_x, title_y, RenderData::Color(255, 255, 100, 255), title);
if (title_show_prompt_)
{
const char* prompt = "PRESS TO START";
const int32_t prompt_x = (w - 14 * 8) / 2;
ctx.draw_text(font, prompt_x, title_y + 40, RenderData::Color::White(), prompt);
}
}
void GameStateManager::draw_hud(Core::DrawContext& ctx, const RenderData::BitmapFont& font,
int32_t w, int32_t)
{
draw_light_bar(ctx, 8, 8, 80, 8, hud_.light_level, hud_.light_max);
char buf[32];
snprintf(buf, sizeof(buf), "LV%d", hud_.current_level);
ctx.draw_text(font, w - 48, 8, RenderData::Color::White(), buf);
snprintf(buf, sizeof(buf), "x%d", hud_.collectibles);
ctx.draw_text(font, 8, 24, RenderData::Color(255, 255, 0, 255), buf);
for (int32_t i = 0; i < hud_.lives; ++i)
{
ctx.fill_rect(8 + i * 12, 40, 8, 8, RenderData::Color::Red());
}
}
void GameStateManager::draw_pause(Core::DrawContext& ctx, const RenderData::BitmapFont& font,
int32_t w, int32_t h)
{
ctx.fill_rect(w / 4, h / 3, w / 2, h / 3, RenderData::Color(0, 0, 0, 200));
const char* text = "PAUSED";
const int32_t tx = (w - 6 * 8) / 2;
const int32_t ty = h / 2 - 4;
ctx.draw_text(font, tx, ty, RenderData::Color::White(), text);
}
void GameStateManager::draw_game_over(Core::DrawContext& ctx, const RenderData::BitmapFont& font,
int32_t w, int32_t h)
{
ctx.fill_rect(0, 0, w, h, RenderData::Color(40, 0, 0, 255));
const char* text = "GAME OVER";
const int32_t tx = (w - 9 * 8) / 2;
const int32_t ty = h / 2 - 4;
ctx.draw_text(font, tx, ty, RenderData::Color::Red(), text);
const char* retry = "PRESS TO RETRY";
const int32_t rx = (w - 14 * 8) / 2;
ctx.draw_text(font, rx, ty + 24, RenderData::Color::White(), retry);
}
void GameStateManager::draw_level_complete(Core::DrawContext& ctx, const RenderData::BitmapFont& font,
int32_t w, int32_t h)
{
ctx.fill_rect(0, 0, w, h, RenderData::Color(0, 40, 0, 255));
const char* text = "LEVEL CLEAR!";
const int32_t tx = (w - 12 * 8) / 2;
const int32_t ty = h / 2 - 4;
ctx.draw_text(font, tx, ty, RenderData::Color(100, 255, 100, 255), text);
char buf[32];
snprintf(buf, sizeof(buf), "SCORE: %d", hud_.collectibles);
const int32_t sx = (w - 10 * 8) / 2;
ctx.draw_text(font, sx, ty + 24, RenderData::Color::White(), buf);
}
void GameStateManager::draw_light_bar(Core::DrawContext& ctx, int32_t x, int32_t y,
int32_t w, int32_t h, uint16_t level, uint16_t max_level)
{
ctx.fill_rect(x, y, w, h, RenderData::Color(60, 60, 60, 255));
const int32_t fill_w = (max_level > 0) ? (static_cast<int32_t>(level) * (w - 2)) / max_level : 0;
if (fill_w > 0)
{
const uint8_t r = static_cast<uint8_t>(255 * (max_level - level) / max_level);
const uint8_t g = static_cast<uint8_t>(255 * level / max_level);
ctx.fill_rect(x + 1, y + 1, fill_w, h - 2, RenderData::Color(r, g, 0, 255));
}
}
}