174 lines
5.0 KiB
C++
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));
|
|
}
|
|
}
|
|
}
|