diff --git a/Base/res/apps/FlappyBug.af b/Base/res/apps/FlappyBug.af new file mode 100644 index 0000000000..fbbc4267c1 --- /dev/null +++ b/Base/res/apps/FlappyBug.af @@ -0,0 +1,4 @@ +[App] +Name=Flappy Bug +Executable=/bin/FlappyBug +Category=Games diff --git a/Base/res/icons/16x16/app-flappybug.png b/Base/res/icons/16x16/app-flappybug.png new file mode 100644 index 0000000000..ebb81a51f0 Binary files /dev/null and b/Base/res/icons/16x16/app-flappybug.png differ diff --git a/Base/res/icons/32x32/app-flappybug.png b/Base/res/icons/32x32/app-flappybug.png new file mode 100644 index 0000000000..dae5073be6 Binary files /dev/null and b/Base/res/icons/32x32/app-flappybug.png differ diff --git a/Userland/Games/CMakeLists.txt b/Userland/Games/CMakeLists.txt index c1cd514220..07e860670f 100644 --- a/Userland/Games/CMakeLists.txt +++ b/Userland/Games/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(2048) add_subdirectory(Breakout) add_subdirectory(Chess) +add_subdirectory(FlappyBug) add_subdirectory(GameOfLife) add_subdirectory(Hearts) add_subdirectory(Minesweeper) diff --git a/Userland/Games/FlappyBug/CMakeLists.txt b/Userland/Games/FlappyBug/CMakeLists.txt new file mode 100644 index 0000000000..dd77a434da --- /dev/null +++ b/Userland/Games/FlappyBug/CMakeLists.txt @@ -0,0 +1,7 @@ +set(SOURCES + main.cpp + Game.cpp +) + +serenity_app(FlappyBug ICON app-flappybug) +target_link_libraries(FlappyBug LibGUI) diff --git a/Userland/Games/FlappyBug/Game.cpp b/Userland/Games/FlappyBug/Game.cpp new file mode 100644 index 0000000000..4e05ba85d5 --- /dev/null +++ b/Userland/Games/FlappyBug/Game.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021, Mim Hufford + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "Game.h" +#include + +namespace FlappyBug { + +Game::Game() +{ + set_override_cursor(Gfx::StandardCursor::Hidden); + start_timer(16); + reset(); +} + +void Game::reset() +{ + m_active = false; + m_difficulty = 1; + m_bug.reset(); + m_obstacle.reset(); +} + +void Game::timer_event(Core::TimerEvent&) +{ + tick(); +} + +void Game::paint_event(GUI::PaintEvent& event) +{ + GUI::Painter painter(*this); + painter.add_clip_rect(event.rect()); + + painter.fill_rect(rect(), Color::Black); + + painter.fill_rect(enclosing_int_rect(m_obstacle.top_rect()), Color::White); + painter.fill_rect(enclosing_int_rect(m_obstacle.bottom_rect()), Color::White); + painter.fill_ellipse(enclosing_int_rect(m_bug.rect()), Color::Red); + + painter.draw_text({ 10, 10, 100, 100 }, String::formatted("{}", m_difficulty), Gfx::TextAlignment::TopLeft, Color::Green); +} + +void Game::keydown_event(GUI::KeyEvent& event) +{ + switch (event.key()) { + case Key_Escape: + GUI::Application::the()->quit(); + break; + default: + m_active = true; + m_bug.flap(); + break; + } +} + +void Game::tick() +{ + if (m_active) { + m_difficulty += 0.0001f; + + m_bug.fall(); + m_bug.apply_velocity(); + m_obstacle.x -= 4 + m_difficulty; + + if (m_bug.y > game_height || m_bug.y < 0) { + reset(); + } + + if (m_bug.rect().intersects(m_obstacle.top_rect()) || m_bug.rect().intersects(m_obstacle.bottom_rect())) { + reset(); + } + + if (m_obstacle.x < 0) { + m_obstacle.reset(); + } + } + + update(); +} + +} diff --git a/Userland/Games/FlappyBug/Game.h b/Userland/Games/FlappyBug/Game.h new file mode 100644 index 0000000000..6df9b0b451 --- /dev/null +++ b/Userland/Games/FlappyBug/Game.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021, Mim Hufford + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace FlappyBug { + +class Game final : public GUI::Widget { + C_OBJECT(Game); + +public: + static const int game_width = 560; + static const int game_height = 480; + +private: + Game(); + + virtual void paint_event(GUI::PaintEvent&) override; + virtual void keydown_event(GUI::KeyEvent&) override; + virtual void timer_event(Core::TimerEvent&) override; + + void tick(); + void reset(); + + struct Bug { + const float x { 50 }; + const float radius { 10 }; + const float starting_y { 200 }; + float y {}; + float velocity {}; + + void reset() + { + y = starting_y; + } + + Gfx::FloatRect rect() const + { + return { x - radius, y - radius, radius * 2, radius * 2 }; + } + + void flap() + { + const float flap_strength = 15.0f; + velocity = -flap_strength; + } + + void fall() + { + const float gravity = 1.0f; + velocity += gravity; + } + + void apply_velocity() + { + y += velocity; + } + }; + + struct Obstacle { + const float width { 20 }; + float x; + float gap_top_y { 200 }; + float gap_height { 175 }; + + void reset() + { + x = game_width; + } + + Gfx::FloatRect top_rect() const + { + return { x - width, 0, width, gap_top_y }; + } + + Gfx::FloatRect bottom_rect() const + { + return { x - width, gap_top_y + gap_height, width, game_height - gap_top_y - gap_height }; + } + }; + + Bug m_bug; + Obstacle m_obstacle; + bool m_active; + float m_difficulty; +}; + +} diff --git a/Userland/Games/FlappyBug/main.cpp b/Userland/Games/FlappyBug/main.cpp new file mode 100644 index 0000000000..1112889366 --- /dev/null +++ b/Userland/Games/FlappyBug/main.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021, Mim Hufford + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "Game.h" +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (pledge("stdio rpath wpath cpath recvfd sendfd cpath unix", nullptr) < 0) { + perror("pledge"); + return 1; + } + + auto app = GUI::Application::construct(argc, argv); + + if (pledge("stdio rpath wpath cpath recvfd sendfd", nullptr) < 0) { + perror("pledge"); + return 1; + } + + if (unveil("/res", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + + auto window = GUI::Window::construct(); + window->resize(FlappyBug::Game::game_width, FlappyBug::Game::game_height); + auto app_icon = GUI::Icon::default_icon("app-flappybug"); + window->set_icon(app_icon.bitmap_for_size(16)); + window->set_title("Flappy Bug"); + window->set_double_buffering_enabled(false); + window->set_resizable(false); + window->set_main_widget(); + window->show(); + + auto menubar = GUI::Menubar::construct(); + + auto& game_menu = menubar->add_menu("&Game"); + game_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) { + GUI::Application::the()->quit(); + })); + + auto& help_menu = menubar->add_menu("&Help"); + help_menu.add_action(GUI::CommonActions::make_about_action("Flappy Bug", app_icon, window)); + + window->set_menubar(move(menubar)); + + return app->exec(); +}