summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-12-20 08:34:18 -0500
committerAndreas Kling <kling@serenityos.org>2022-12-23 23:26:21 +0100
commitcb66c02bc4638ee53cf0879cccc3d6e6db6b8c17 (patch)
tree123687766c50b9fef9652be22b7dc2a7be1a4115
parentae90f490bd8c2e97c04dead108585c6d34e1d829 (diff)
downloadserenity-cb66c02bc4638ee53cf0879cccc3d6e6db6b8c17.zip
Snake: Convert the game window to GML
Unfortunately, GML widget registration requires a non-fallible construct method to create the widget. So this does a bit of manual error checking when loading the food bitmaps.
-rw-r--r--Userland/Games/Snake/CMakeLists.txt6
-rw-r--r--Userland/Games/Snake/Game.cpp83
-rw-r--r--Userland/Games/Snake/Game.h3
-rw-r--r--Userland/Games/Snake/Snake.gml9
-rw-r--r--Userland/Games/Snake/main.cpp22
5 files changed, 79 insertions, 44 deletions
diff --git a/Userland/Games/Snake/CMakeLists.txt b/Userland/Games/Snake/CMakeLists.txt
index d6ab5f3954..c862075738 100644
--- a/Userland/Games/Snake/CMakeLists.txt
+++ b/Userland/Games/Snake/CMakeLists.txt
@@ -4,10 +4,16 @@ serenity_component(
TARGETS Snake
)
+compile_gml(Snake.gml SnakeGML.h snake_gml)
+
set(SOURCES
Game.cpp
main.cpp
)
+set(GENERATED_SOURCES
+ SnakeGML.h
+)
+
serenity_app(Snake ICON app-snake)
target_link_libraries(Snake PRIVATE LibCore LibGfx LibGUI LibConfig LibMain LibDesktop)
diff --git a/Userland/Games/Snake/Game.cpp b/Userland/Games/Snake/Game.cpp
index 8f49464b29..3afdaa34bb 100644
--- a/Userland/Games/Snake/Game.cpp
+++ b/Userland/Games/Snake/Game.cpp
@@ -15,45 +15,62 @@
#include <LibGfx/Font/Font.h>
#include <LibGfx/Font/FontDatabase.h>
+REGISTER_WIDGET(Snake, Game);
+
namespace Snake {
-ErrorOr<NonnullRefPtr<Game>> Game::create()
+static NonnullRefPtrVector<Gfx::Bitmap> load_food_bitmaps()
{
+ static constexpr auto food_bitmaps_files = Array {
+ "/res/emoji/U+1F41F.png"sv,
+ "/res/emoji/U+1F95A.png"sv,
+ "/res/emoji/U+1F99C.png"sv,
+ "/res/emoji/U+1F986.png"sv,
+ "/res/emoji/U+1FAB2.png"sv,
+ "/res/emoji/U+1F426.png"sv,
+ "/res/emoji/U+1F424.png"sv,
+ "/res/emoji/U+1F40D.png"sv,
+ "/res/emoji/U+1F989.png"sv,
+ "/res/emoji/U+1F54A.png"sv,
+ "/res/emoji/U+1F408.png"sv,
+ "/res/emoji/U+1F420.png"sv,
+ "/res/emoji/U+1F415.png"sv,
+ "/res/emoji/U+1F429.png"sv,
+ "/res/emoji/U+1F98C.png"sv,
+ "/res/emoji/U+1F416.png"sv,
+ "/res/emoji/U+1F401.png"sv,
+ "/res/emoji/U+1F400.png"sv,
+ "/res/emoji/U+1F407.png"sv,
+ "/res/emoji/U+1F43F.png"sv,
+ "/res/emoji/U+1F9A5.png"sv,
+ "/res/emoji/U+1F423.png"sv,
+ "/res/emoji/U+1F425.png"sv,
+ "/res/emoji/U+1F98E.png"sv,
+ "/res/emoji/U+1F997.png"sv,
+ "/res/emoji/U+1FAB3.png"sv,
+ "/res/emoji/U+1F413.png"sv,
+ "/res/emoji/U+1FAB0.png"sv,
+ "/res/emoji/U+1FAB1.png"sv,
+ };
+
NonnullRefPtrVector<Gfx::Bitmap> food_bitmaps;
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F41F.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F95A.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F99C.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F986.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1FAB2.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F426.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F424.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F40D.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F989.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F54A.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F408.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F420.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F415.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F429.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F98C.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F416.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F401.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F400.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F407.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F43F.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F9A5.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F423.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F425.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F98E.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F997.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1FAB3.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1F413.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1FAB0.png"sv)));
- food_bitmaps.append(*TRY(Gfx::Bitmap::try_load_from_file("/res/emoji/U+1FAB1.png"sv)));
- return adopt_nonnull_ref_or_enomem(new (nothrow) Game(move(food_bitmaps)));
+ food_bitmaps.ensure_capacity(food_bitmaps_files.size());
+
+ for (auto file : food_bitmaps_files) {
+ auto bitmap = Gfx::Bitmap::try_load_from_file(file);
+ if (bitmap.is_error()) {
+ dbgln("\033[31;1mCould not load bitmap file\033[0m '{}': {}", file, bitmap.error());
+ VERIFY_NOT_REACHED();
+ }
+
+ food_bitmaps.unchecked_append(bitmap.release_value());
+ }
+
+ return food_bitmaps;
}
-Game::Game(NonnullRefPtrVector<Gfx::Bitmap> food_bitmaps)
- : m_food_bitmaps(move(food_bitmaps))
+Game::Game()
+ : m_food_bitmaps(load_food_bitmaps())
{
set_font(Gfx::FontDatabase::default_fixed_width_font().bold_variant());
reset();
diff --git a/Userland/Games/Snake/Game.h b/Userland/Games/Snake/Game.h
index accc97b2c4..41b30933fd 100644
--- a/Userland/Games/Snake/Game.h
+++ b/Userland/Games/Snake/Game.h
@@ -17,7 +17,6 @@ class Game : public GUI::Frame {
C_OBJECT(Game);
public:
- static ErrorOr<NonnullRefPtr<Game>> create();
virtual ~Game() override = default;
void start();
@@ -27,7 +26,7 @@ public:
void set_snake_base_color(Color color);
private:
- explicit Game(NonnullRefPtrVector<Gfx::Bitmap> food_bitmaps);
+ Game();
virtual void paint_event(GUI::PaintEvent&) override;
virtual void keydown_event(GUI::KeyEvent&) override;
diff --git a/Userland/Games/Snake/Snake.gml b/Userland/Games/Snake/Snake.gml
new file mode 100644
index 0000000000..865c6d8b1f
--- /dev/null
+++ b/Userland/Games/Snake/Snake.gml
@@ -0,0 +1,9 @@
+@GUI::Widget {
+ layout: @GUI::VerticalBoxLayout {}
+ fill_with_background_color: true
+
+ @Snake::Game {
+ name: "game"
+ fill_with_background_color: true
+ }
+}
diff --git a/Userland/Games/Snake/main.cpp b/Userland/Games/Snake/main.cpp
index a2501a3784..93644bc5df 100644
--- a/Userland/Games/Snake/main.cpp
+++ b/Userland/Games/Snake/main.cpp
@@ -6,6 +6,7 @@
#include "Game.h"
#include <AK/URL.h>
+#include <Games/Snake/SnakeGML.h>
#include <LibConfig/Client.h>
#include <LibCore/System.h>
#include <LibDesktop/Launcher.h>
@@ -46,35 +47,38 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
window->set_title("Snake");
window->resize(324, 344);
- auto game = TRY(Snake::Game::create());
- window->set_main_widget(game);
+ auto widget = TRY(window->try_set_main_widget<GUI::Widget>());
+ widget->load_from_gml(snake_gml);
+
+ auto& game = *widget->find_descendant_of_type_named<Snake::Game>("game");
+ game.set_focus(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&) {
- game->reset();
+ game.reset();
})));
static DeprecatedString const pause_text = "&Pause Game"sv;
auto const pause_icon = TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/pause.png"sv));
static DeprecatedString const continue_text = "&Continue Game"sv;
auto const continue_icon = TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/play.png"sv));
TRY(game_menu->try_add_action(GUI::Action::create(pause_text, { Mod_None, Key_Space }, pause_icon, [&](auto& action) {
- if (game->has_timer()) {
- game->pause();
+ if (game.has_timer()) {
+ game.pause();
action.set_text(continue_text);
action.set_icon(continue_icon);
} else {
- game->start();
+ game.start();
action.set_text(pause_text);
action.set_icon(pause_icon);
}
})));
TRY(game_menu->try_add_action(GUI::Action::create("&Change snake color", TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/color-chooser.png"sv)), [&](auto&) {
- game->pause();
+ game.pause();
auto dialog = GUI::ColorPicker::construct(Gfx::Color::White, window);
if (dialog->exec() == GUI::Dialog::ExecResult::OK)
- game->set_snake_base_color(dialog->color());
- game->start();
+ game.set_snake_base_color(dialog->color());
+ game.start();
})));
TRY(game_menu->try_add_separator());
TRY(game_menu->try_add_action(GUI::CommonActions::make_quit_action([](auto&) {