diff options
author | Timothy Flynn <trflynn89@pm.me> | 2022-12-20 08:34:18 -0500 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-12-23 23:26:21 +0100 |
commit | cb66c02bc4638ee53cf0879cccc3d6e6db6b8c17 (patch) | |
tree | 123687766c50b9fef9652be22b7dc2a7be1a4115 | |
parent | ae90f490bd8c2e97c04dead108585c6d34e1d829 (diff) | |
download | serenity-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.txt | 6 | ||||
-rw-r--r-- | Userland/Games/Snake/Game.cpp | 83 | ||||
-rw-r--r-- | Userland/Games/Snake/Game.h | 3 | ||||
-rw-r--r-- | Userland/Games/Snake/Snake.gml | 9 | ||||
-rw-r--r-- | Userland/Games/Snake/main.cpp | 22 |
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&) { |