summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-12-20 08:55:56 -0500
committerAndreas Kling <kling@serenityos.org>2022-12-23 23:26:21 +0100
commit661c02b91484fbdeba0efe32d2f03afa9c3cb954 (patch)
tree8c505a690c92b74825d1181607abb8b5bf468f32
parentcb66c02bc4638ee53cf0879cccc3d6e6db6b8c17 (diff)
downloadserenity-661c02b91484fbdeba0efe32d2f03afa9c3cb954.zip
Snake: Use a statusbar to display the current and high score
The food bitmaps would sometimes be placed underneath the score text, which was a bit hard to see. Use a statusbar like we do in other games like Solitaire. Note the default height change of the Snake window is to make the inner game widget fit exactly 20x20 cells.
-rw-r--r--Userland/Games/Snake/Game.cpp36
-rw-r--r--Userland/Games/Snake/Game.h7
-rw-r--r--Userland/Games/Snake/Snake.gml5
-rw-r--r--Userland/Games/Snake/main.cpp21
4 files changed, 36 insertions, 33 deletions
diff --git a/Userland/Games/Snake/Game.cpp b/Userland/Games/Snake/Game.cpp
index 3afdaa34bb..d3350339e3 100644
--- a/Userland/Games/Snake/Game.cpp
+++ b/Userland/Games/Snake/Game.cpp
@@ -74,8 +74,7 @@ Game::Game()
{
set_font(Gfx::FontDatabase::default_fixed_width_font().bold_variant());
reset();
- m_high_score = Config::read_i32("Snake"sv, "Snake"sv, "HighScore"sv, 0);
- m_high_score_text = DeprecatedString::formatted("Best: {}", m_high_score);
+
m_snake_base_color = Color::from_argb(Config::read_u32("Snake"sv, "Snake"sv, "BaseColor"sv, m_snake_base_color.value()));
}
@@ -96,9 +95,12 @@ void Game::reset()
m_tail.clear_with_capacity();
m_length = 2;
m_score = 0;
- m_score_text = "Score: 0";
m_is_new_high_score = false;
m_velocity_queue.clear();
+
+ if (on_score_update)
+ on_score_update(m_score);
+
pause();
start();
spawn_fruit();
@@ -137,18 +139,6 @@ void Game::spawn_fruit()
m_fruit_type = get_random_uniform(m_food_bitmaps.size());
}
-Gfx::IntRect Game::score_rect() const
-{
- int score_width = font().width(m_score_text);
- return { frame_inner_rect().width() - score_width - 2, frame_inner_rect().height() - font().glyph_height() - 2, score_width, font().glyph_height() };
-}
-
-Gfx::IntRect Game::high_score_rect() const
-{
- int high_score_width = font().width(m_high_score_text);
- return { frame_thickness() + 2, frame_inner_rect().height() - font().glyph_height() - 2, high_score_width, font().glyph_height() };
-}
-
void Game::timer_event(Core::TimerEvent&)
{
Vector<Coordinate> dirty_cells;
@@ -191,15 +181,10 @@ void Game::timer_event(Core::TimerEvent&)
if (m_head == m_fruit) {
++m_length;
++m_score;
- m_score_text = DeprecatedString::formatted("Score: {}", m_score);
- if (m_score > m_high_score) {
- m_is_new_high_score = true;
- m_high_score = m_score;
- m_high_score_text = DeprecatedString::formatted("Best: {}", m_high_score);
- update(high_score_rect());
- Config::write_i32("Snake"sv, "Snake"sv, "HighScore"sv, m_high_score);
- }
- update(score_rect());
+
+ if (on_score_update)
+ m_is_new_high_score = on_score_update(m_score);
+
dirty_cells.append(m_fruit);
spawn_fruit();
dirty_cells.append(m_fruit);
@@ -279,9 +264,6 @@ void Game::paint_event(GUI::PaintEvent& event)
}
painter.draw_scaled_bitmap(cell_rect(m_fruit), m_food_bitmaps[m_fruit_type], m_food_bitmaps[m_fruit_type].rect());
-
- painter.draw_text(high_score_rect(), m_high_score_text, Gfx::TextAlignment::TopLeft, Color::from_rgb(0xfafae0));
- painter.draw_text(score_rect(), m_score_text, Gfx::TextAlignment::TopLeft, Color::White);
}
void Game::game_over()
diff --git a/Userland/Games/Snake/Game.h b/Userland/Games/Snake/Game.h
index 41b30933fd..0c512813b3 100644
--- a/Userland/Games/Snake/Game.h
+++ b/Userland/Games/Snake/Game.h
@@ -25,6 +25,8 @@ public:
void set_snake_base_color(Color color);
+ Function<bool(u32)> on_score_update;
+
private:
Game();
@@ -53,8 +55,6 @@ private:
void queue_velocity(int v, int h);
Velocity const& last_velocity() const;
Gfx::IntRect cell_rect(Coordinate const&) const;
- Gfx::IntRect score_rect() const;
- Gfx::IntRect high_score_rect() const;
int m_rows { 20 };
int m_columns { 20 };
@@ -72,9 +72,6 @@ private:
size_t m_length { 0 };
unsigned m_score { 0 };
- DeprecatedString m_score_text;
- unsigned m_high_score { 0 };
- DeprecatedString m_high_score_text;
bool m_is_new_high_score { false };
NonnullRefPtrVector<Gfx::Bitmap> m_food_bitmaps;
diff --git a/Userland/Games/Snake/Snake.gml b/Userland/Games/Snake/Snake.gml
index 865c6d8b1f..bbf142cae7 100644
--- a/Userland/Games/Snake/Snake.gml
+++ b/Userland/Games/Snake/Snake.gml
@@ -6,4 +6,9 @@
name: "game"
fill_with_background_color: true
}
+
+ @GUI::Statusbar {
+ name: "statusbar"
+ segment_count: 2
+ }
}
diff --git a/Userland/Games/Snake/main.cpp b/Userland/Games/Snake/main.cpp
index 93644bc5df..c363643e02 100644
--- a/Userland/Games/Snake/main.cpp
+++ b/Userland/Games/Snake/main.cpp
@@ -18,6 +18,7 @@
#include <LibGUI/Icon.h>
#include <LibGUI/Menu.h>
#include <LibGUI/Menubar.h>
+#include <LibGUI/Statusbar.h>
#include <LibGUI/Window.h>
#include <LibMain/Main.h>
#include <stdio.h>
@@ -45,7 +46,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
window->set_double_buffering_enabled(false);
window->set_title("Snake");
- window->resize(324, 344);
+ window->resize(324, 345);
auto widget = TRY(window->try_set_main_widget<GUI::Widget>());
widget->load_from_gml(snake_gml);
@@ -53,6 +54,24 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
auto& game = *widget->find_descendant_of_type_named<Snake::Game>("game");
game.set_focus(true);
+ auto high_score = Config::read_u32("Snake"sv, "Snake"sv, "HighScore"sv, 0);
+
+ auto& statusbar = *widget->find_descendant_of_type_named<GUI::Statusbar>("statusbar"sv);
+ statusbar.set_text(0, "Score: 0"sv);
+ statusbar.set_text(1, DeprecatedString::formatted("High Score: {}", high_score));
+
+ game.on_score_update = [&](auto score) {
+ statusbar.set_text(0, DeprecatedString::formatted("Score: {}", score));
+ if (score <= high_score)
+ return false;
+
+ statusbar.set_text(1, DeprecatedString::formatted("High Score: {}", score));
+ Config::write_u32("Snake"sv, "Snake"sv, "HighScore"sv, score);
+
+ high_score = score;
+ return true;
+ };
+
auto game_menu = TRY(window->try_add_menu("&Game"));
TRY(game_menu->try_add_action(GUI::Action::create("&New Game", { Mod_None, Key_F2 }, TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/reload.png"sv)), [&](auto&) {