1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 12:07:45 +00:00

BrickGame: Show where a piece would end up when after a fast drop

To show it to the player, draw a faint outline of where the piece would
end up.
This commit is contained in:
Karol Baraniecki 2023-04-07 21:10:19 +02:00 committed by Jelle Raaijmakers
parent 652a19b232
commit f3f14a7ef1
2 changed files with 55 additions and 8 deletions

View file

@ -277,9 +277,13 @@ public:
[[nodiscard]] Block const& next_block() const { return m_next_block; } [[nodiscard]] Block const& next_block() const { return m_next_block; }
[[nodiscard]] bool operator[](Position pos) const [[nodiscard]] BrickGame::BoardSpace operator[](Position pos) const
{ {
return m_well[pos] || m_block[pos]; if (m_well[pos] || m_block[pos])
return BrickGame::BoardSpace::FullyOn;
if (m_shadow_hint_block[pos])
return BrickGame::BoardSpace::ShadowHint;
return BrickGame::BoardSpace::Off;
} }
[[nodiscard]] RenderRequest rotate_left() { return set_current_block(Block(m_block).rotate_left()); } [[nodiscard]] RenderRequest rotate_left() { return set_current_block(Block(m_block).rotate_left()); }
@ -297,9 +301,11 @@ public:
m_block.place_into(m_well); m_block.place_into(m_well);
check_and_remove_full_rows(); check_and_remove_full_rows();
add_new_block(); add_new_block();
update_shadow_hint_block();
return RenderRequest::RequestUpdate; return RenderRequest::RequestUpdate;
} }
m_block = block; m_block = block;
update_shadow_hint_block();
return RenderRequest::RequestUpdate; return RenderRequest::RequestUpdate;
} }
@ -314,9 +320,19 @@ public:
} }
m_block = block; m_block = block;
} }
update_shadow_hint_block();
return RenderRequest::RequestUpdate; return RenderRequest::RequestUpdate;
} }
void update_shadow_hint_block()
{
for (auto block = m_block;; block.move_down()) {
if (block.has_collision(m_well))
return;
m_shadow_hint_block = block;
}
}
void toggle_pause() void toggle_pause()
{ {
switch (m_state) { switch (m_state) {
@ -355,6 +371,7 @@ public:
m_well.reset(); m_well.reset();
m_block.random_shape(); m_block.random_shape();
m_next_block.random_shape(); m_next_block.random_shape();
update_shadow_hint_block();
m_last_update = Time::now_realtime(); m_last_update = Time::now_realtime();
m_state = GameState::Active; m_state = GameState::Active;
} }
@ -363,6 +380,7 @@ private:
Well m_well {}; Well m_well {};
Block m_block {}; Block m_block {};
Block m_next_block {}; Block m_next_block {};
Block m_shadow_hint_block {};
unsigned m_level {}; unsigned m_level {};
unsigned m_score {}; unsigned m_score {};
GameState m_state { GameState::GameOver }; GameState m_state { GameState::GameOver };
@ -394,6 +412,7 @@ private:
{ {
if (!block.has_collision(m_well)) { if (!block.has_collision(m_well)) {
m_block = block; m_block = block;
update_shadow_hint_block();
return RenderRequest::RequestUpdate; return RenderRequest::RequestUpdate;
} }
return RenderRequest::SkipRender; return RenderRequest::SkipRender;
@ -516,23 +535,41 @@ void BrickGame::keydown_event(GUI::KeyEvent& event)
update(); update();
} }
void BrickGame::paint_cell(GUI::Painter& painter, Gfx::IntRect rect, bool is_on) void BrickGame::paint_cell(GUI::Painter& painter, Gfx::IntRect rect, BrickGame::BoardSpace space)
{ {
Color inside_color;
Color outside_color;
switch (space) {
case BrickGame::BoardSpace::FullyOn:
inside_color = m_front_color;
outside_color = m_front_color;
break;
case BrickGame::BoardSpace::ShadowHint:
inside_color = m_shadow_color;
outside_color = m_hint_block_color;
break;
case BrickGame::BoardSpace::Off:
inside_color = m_shadow_color;
outside_color = m_shadow_color;
break;
}
painter.draw_rect(rect, m_back_color); painter.draw_rect(rect, m_back_color);
rect.inflate(-1, -1, -1, -1); rect.inflate(-1, -1, -1, -1);
painter.draw_rect(rect, is_on ? m_front_color : m_shadow_color); painter.draw_rect(rect, outside_color);
painter.set_pixel(rect.top_left(), m_back_color); painter.set_pixel(rect.top_left(), m_back_color);
painter.set_pixel(rect.bottom_left(), m_back_color); painter.set_pixel(rect.bottom_left(), m_back_color);
painter.set_pixel(rect.top_right(), m_back_color); painter.set_pixel(rect.top_right(), m_back_color);
painter.set_pixel(rect.bottom_right(), m_back_color); painter.set_pixel(rect.bottom_right(), m_back_color);
rect.inflate(-2, -2); rect.inflate(-2, -2);
painter.draw_rect(rect, is_on ? m_front_color : m_shadow_color); painter.draw_rect(rect, outside_color);
rect.inflate(-2, -2); rect.inflate(-2, -2);
painter.draw_rect(rect, m_back_color); painter.draw_rect(rect, m_back_color);
rect.inflate(-2, -2); rect.inflate(-2, -2);
painter.draw_rect(rect, m_back_color); painter.draw_rect(rect, m_back_color);
rect.inflate(-2, -2); rect.inflate(-2, -2);
painter.fill_rect(rect, is_on ? m_front_color : m_shadow_color); painter.fill_rect(rect, inside_color);
} }
void BrickGame::paint_sidebar_text(GUI::Painter& painter, int row, StringView text) void BrickGame::paint_sidebar_text(GUI::Painter& painter, int row, StringView text)
@ -613,7 +650,9 @@ void BrickGame::paint_game(GUI::Painter& painter, Gfx::IntRect const& rect)
auto const dot_rect = Gfx::IntRect { hint_rect.x(), hint_rect.y(), cell_size.width() - 1, cell_size.height() - 1 }; auto const dot_rect = Gfx::IntRect { hint_rect.x(), hint_rect.y(), cell_size.width() - 1, cell_size.height() - 1 };
for (size_t y = 0; y < Block::shape_size; ++y) for (size_t y = 0; y < Block::shape_size; ++y)
for (size_t x = 0; x < Block::shape_size; ++x) for (size_t x = 0; x < Block::shape_size; ++x)
paint_cell(painter, dot_rect.translated(int(x * cell_size.width()), int(y * cell_size.height())), m_brick_game->next_block().dot_at({ x, y })); paint_cell(painter,
dot_rect.translated(int(x * cell_size.width()), int(y * cell_size.height())),
m_brick_game->next_block().dot_at({ x, y }) ? BrickGame::BoardSpace::FullyOn : BrickGame::BoardSpace::Off);
if (m_brick_game->state() == Bricks::GameState::Paused) if (m_brick_game->state() == Bricks::GameState::Paused)
paint_paused_text(painter); paint_paused_text(painter);

View file

@ -15,6 +15,13 @@ class BrickGame : public GUI::Frame {
C_OBJECT(BrickGame); C_OBJECT(BrickGame);
public: public:
// How should a particular space on the board be presented to the user
enum class BoardSpace {
FullyOn,
ShadowHint,
Off
};
virtual ~BrickGame() override = default; virtual ~BrickGame() override = default;
void reset(); void reset();
@ -28,7 +35,7 @@ private:
void paint_sidebar_text(GUI::Painter&, int row, StringView); void paint_sidebar_text(GUI::Painter&, int row, StringView);
void paint_paused_text(GUI::Painter&); void paint_paused_text(GUI::Painter&);
void paint_cell(GUI::Painter&, Gfx::IntRect, bool); void paint_cell(GUI::Painter&, Gfx::IntRect, BoardSpace);
void paint_game(GUI::Painter&, Gfx::IntRect const&); void paint_game(GUI::Painter&, Gfx::IntRect const&);
void game_over(); void game_over();
@ -45,4 +52,5 @@ private:
Color m_back_color { Color::from_rgb(0x8fbc8f) }; Color m_back_color { Color::from_rgb(0x8fbc8f) };
Color m_front_color { Color::Black }; Color m_front_color { Color::Black };
Color m_shadow_color { Color::from_rgb(0x729672) }; Color m_shadow_color { Color::from_rgb(0x729672) };
Color m_hint_block_color { Color::from_rgb(0x485e48) };
}; };