diff options
author | Andreas Kling <kling@serenityos.org> | 2022-06-14 14:17:47 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-06-15 17:15:04 +0200 |
commit | 45de16f19577f8a22672e5a474b4b328993f241d (patch) | |
tree | 3d2a4bcdcad1f334063ed74b07402cf1a99e144d /Userland/Games | |
parent | 4e4a930b13f0f874f0ad7c368f1adb7fa5cb1e0b (diff) | |
download | serenity-45de16f19577f8a22672e5a474b4b328993f241d.zip |
Userland+Base: Remove Breakout and Pong games
These games were not very playable and definitely not fun.
Diffstat (limited to 'Userland/Games')
-rw-r--r-- | Userland/Games/Breakout/CMakeLists.txt | 14 | ||||
-rw-r--r-- | Userland/Games/Breakout/Game.cpp | 335 | ||||
-rw-r--r-- | Userland/Games/Breakout/Game.h | 105 | ||||
-rw-r--r-- | Userland/Games/Breakout/LevelSelectDialog.cpp | 58 | ||||
-rw-r--r-- | Userland/Games/Breakout/LevelSelectDialog.h | 25 | ||||
-rw-r--r-- | Userland/Games/Breakout/main.cpp | 64 | ||||
-rw-r--r-- | Userland/Games/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Userland/Games/Pong/CMakeLists.txt | 13 | ||||
-rw-r--r-- | Userland/Games/Pong/Game.cpp | 325 | ||||
-rw-r--r-- | Userland/Games/Pong/Game.h | 121 | ||||
-rw-r--r-- | Userland/Games/Pong/main.cpp | 64 |
11 files changed, 0 insertions, 1126 deletions
diff --git a/Userland/Games/Breakout/CMakeLists.txt b/Userland/Games/Breakout/CMakeLists.txt deleted file mode 100644 index 8fb1a5ed6e..0000000000 --- a/Userland/Games/Breakout/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -serenity_component( - Breakout - RECOMMENDED - TARGETS Breakout -) - -set(SOURCES - main.cpp - Game.cpp - LevelSelectDialog.cpp -) - -serenity_app(Breakout ICON app-breakout) -target_link_libraries(Breakout LibGUI LibMain LibDesktop) diff --git a/Userland/Games/Breakout/Game.cpp b/Userland/Games/Breakout/Game.cpp deleted file mode 100644 index 4d0e63f231..0000000000 --- a/Userland/Games/Breakout/Game.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Game.h" -#include "LevelSelectDialog.h" -#include <AK/Random.h> -#include <LibGUI/Application.h> -#include <LibGUI/MessageBox.h> -#include <LibGUI/Painter.h> -#include <LibGfx/AntiAliasingPainter.h> -#include <LibGfx/StandardCursor.h> -#include <unistd.h> - -namespace Breakout { - -Game::Game() -{ - set_override_cursor(Gfx::StandardCursor::Hidden); - auto level_dialog = LevelSelectDialog::show(m_board, window()); - if (level_dialog != GUI::Dialog::ExecResult::OK) - m_board = -1; - set_paused(false); - start_timer(16); - reset(); -} - -void Game::reset_paddle() -{ - update(enclosing_int_rect(m_paddle.rect)); - m_paddle.moving_left = false; - m_paddle.moving_right = false; - m_paddle.rect = { game_width / 2 - 40, game_height - 20, 80, 16 }; - update(enclosing_int_rect(m_paddle.rect)); -} - -void Game::reset() -{ - update(lives_left_rect()); - m_lives = 3; - update(lives_left_rect()); - - m_pause_count = 0; - m_cheater = false; - reset_ball(); - reset_paddle(); - generate_bricks(); -} - -void Game::generate_bricks() -{ - m_bricks = {}; - - Gfx::Color colors[] = { - Gfx::Color::Red, - Gfx::Color::Green, - Gfx::Color::Blue, - Gfx::Color::Yellow, - Gfx::Color::Magenta, - Gfx::Color::Cyan, - Gfx::Color::LightGray, - }; - - Vector<Brick> boards[] = { - // :^) - Vector({ - Brick(0, 0, colors[3], 40, 12, 100), - Brick(0, 4, colors[3], 40, 12, 100), - Brick(1, 2, colors[3], 40, 12, 100), - Brick(1, 5, colors[3], 40, 12, 100), - Brick(2, 1, colors[3], 40, 12, 100), - Brick(2, 3, colors[3], 40, 12, 100), - Brick(2, 6, colors[3], 40, 12, 100), - Brick(3, 6, colors[3], 40, 12, 100), - Brick(4, 0, colors[3], 40, 12, 100), - Brick(4, 6, colors[3], 40, 12, 100), - Brick(5, 6, colors[3], 40, 12, 100), - Brick(6, 5, colors[3], 40, 12, 100), - Brick(7, 4, colors[3], 40, 12, 100), - }) - }; - - if (m_board != -1) { - m_bricks = boards[m_board]; - - for (auto& brick : m_bricks) - update(enclosing_int_rect(brick.rect)); - } else { - // Rainbow - for (int row = 0; row < 7; ++row) { - for (int column = 0; column < 10; ++column) { - Brick brick(row, column, colors[row]); - m_bricks.append(brick); - update(enclosing_int_rect(brick.rect)); - } - } - } -} - -void Game::set_paused(bool paused) -{ - m_paused = paused; - - if (m_paused) { - set_override_cursor(Gfx::StandardCursor::None); - m_pause_count++; - } else { - set_override_cursor(Gfx::StandardCursor::Hidden); - } - - update(pause_rect()); -} - -void Game::timer_event(Core::TimerEvent&) -{ - if (m_paused) - return; - tick(); -} - -void Game::paint_event(GUI::PaintEvent& event) -{ - GUI::Painter painter(*this); - painter.add_clip_rect(event.rect()); - Gfx::AntiAliasingPainter aa_painter { painter }; - - painter.fill_rect(rect(), Color::Black); - - aa_painter.fill_ellipse(enclosing_int_rect(m_ball.rect()), Color::Red); - - painter.fill_rect(enclosing_int_rect(m_paddle.rect), Color::White); - - for (auto& brick : m_bricks) { - if (!brick.dead) - painter.fill_rect(enclosing_int_rect(brick.rect), brick.color); - } - - painter.draw_text(lives_left_rect(), String::formatted("Lives: {}", m_lives), Gfx::TextAlignment::Center, Color::White); - - if (m_paused) { - char const* msg = m_cheater ? "C H E A T E R" : "P A U S E D"; - painter.draw_text(pause_rect(), msg, Gfx::TextAlignment::Center, Color::White); - } -} - -void Game::keyup_event(GUI::KeyEvent& event) -{ - if (m_paused) - return; - switch (event.key()) { - case Key_A: - [[fallthrough]]; - case Key_Left: - m_paddle.moving_left = false; - break; - case Key_D: - [[fallthrough]]; - case Key_Right: - m_paddle.moving_right = false; - break; - default: - break; - } -} - -void Game::keydown_event(GUI::KeyEvent& event) -{ - if (m_paused) - return; - switch (event.key()) { - case Key_Escape: - GUI::Application::the()->quit(); - break; - case Key_A: - [[fallthrough]]; - case Key_Left: - m_paddle.moving_left = true; - break; - case Key_D: - [[fallthrough]]; - case Key_Right: - m_paddle.moving_right = true; - break; - default: - break; - } -} - -void Game::mousemove_event(GUI::MouseEvent& event) -{ - if (m_paused) - return; - update(enclosing_int_rect(m_paddle.rect)); - float new_paddle_x = event.x() - m_paddle.rect.width() / 2; - new_paddle_x = max(0.0f, new_paddle_x); - new_paddle_x = min(game_width - m_paddle.rect.width(), new_paddle_x); - m_paddle.rect.set_x(new_paddle_x); - update(enclosing_int_rect(m_paddle.rect)); -} - -void Game::reset_ball() -{ - int position_x_min = (game_width / 2) - 50; - int position_x_max = (game_width / 2) + 50; - int position_x = get_random<u32>() % (position_x_max - position_x_min + 1) + position_x_min; - int position_y = 200; - int velocity_x = get_random<u32>() % 3 + 1; - int velocity_y = 3 + (3 - velocity_x); - if (get_random<u32>() % 2) - velocity_x = velocity_x * -1; - - update(enclosing_int_rect(m_ball.rect())); - m_ball = {}; - m_ball.position = { position_x, position_y }; - m_ball.velocity = { velocity_x, velocity_y }; - update(enclosing_int_rect(m_ball.rect())); -} - -void Game::hurt() -{ - stop_timer(); - update(lives_left_rect()); - m_lives--; - update(lives_left_rect()); - if (m_lives <= 0) { - GUI::MessageBox::show(window(), "You lose!", "Breakout", GUI::MessageBox::Type::Information, GUI::MessageBox::InputType::OK); - reset(); - } - sleep(1); - reset_ball(); - reset_paddle(); - start_timer(16); -} - -void Game::win() -{ - stop_timer(); - update(); - if (m_cheater) { - GUI::MessageBox::show(window(), "You cheated not only the game, but yourself.", "Breakout", GUI::MessageBox::Type::Information, GUI::MessageBox::InputType::OK); - } else { - GUI::MessageBox::show(window(), "You win!", "Breakout", GUI::MessageBox::Type::Information, GUI::MessageBox::InputType::OK); - } - reset(); - start_timer(16); -} - -void Game::tick() -{ - auto new_ball = m_ball; - new_ball.position += new_ball.velocity; - - update(enclosing_int_rect(m_ball.rect())); - - if (new_ball.x() < new_ball.radius || new_ball.x() > game_width - new_ball.radius) { - new_ball.position.set_x(m_ball.x()); - new_ball.velocity.set_x(new_ball.velocity.x() * -1); - } - - if (new_ball.y() < new_ball.radius) { - new_ball.position.set_y(m_ball.y()); - new_ball.velocity.set_y(new_ball.velocity.y() * -1); - } - - if (new_ball.y() > game_height - new_ball.radius) { - hurt(); - return; - } - - update(enclosing_int_rect(new_ball.rect())); - - if (new_ball.rect().intersects(m_paddle.rect)) { - if (m_ball.y() < new_ball.y()) { - new_ball.position.set_y(m_ball.y()); - } - new_ball.velocity.set_y(fabs(new_ball.velocity.y()) * -1); - - float distance_to_middle_of_paddle = new_ball.x() - m_paddle.rect.center().x(); - float relative_impact_point = distance_to_middle_of_paddle / m_paddle.rect.width(); - new_ball.velocity.set_x(relative_impact_point * 7); - } - - for (auto& brick : m_bricks) { - if (brick.dead) - continue; - if (new_ball.rect().intersects(brick.rect)) { - brick.dead = true; - - auto overlap = new_ball.rect().intersected(brick.rect); - if (overlap.width() < overlap.height()) { - new_ball.position.set_x(m_ball.x()); - new_ball.velocity.set_x(new_ball.velocity.x() * -1); - } else { - new_ball.position.set_y(m_ball.y()); - new_ball.velocity.set_y(new_ball.velocity.y() * -1); - } - update(enclosing_int_rect(brick.rect)); - break; - } - } - - bool has_live_bricks = false; - for (auto& brick : m_bricks) { - if (!brick.dead) { - has_live_bricks = true; - break; - } - } - - if (!has_live_bricks) { - win(); - return; - } - - if (m_paddle.moving_left) { - update(enclosing_int_rect(m_paddle.rect)); - m_paddle.rect.set_x(max(0.0f, m_paddle.rect.x() - m_paddle.speed)); - update(enclosing_int_rect(m_paddle.rect)); - } - if (m_paddle.moving_right) { - update(enclosing_int_rect(m_paddle.rect)); - m_paddle.rect.set_x(min(game_width - m_paddle.rect.width(), m_paddle.rect.x() + m_paddle.speed)); - update(enclosing_int_rect(m_paddle.rect)); - } - - m_ball = new_ball; - - if (m_pause_count > 50) - m_cheater = true; -} - -} diff --git a/Userland/Games/Breakout/Game.h b/Userland/Games/Breakout/Game.h deleted file mode 100644 index 7ac05076be..0000000000 --- a/Userland/Games/Breakout/Game.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <LibGUI/Widget.h> -#include <LibGfx/Font/Font.h> - -namespace Breakout { - -class Game final : public GUI::Widget { - C_OBJECT(Game); - -public: - static constexpr int game_width = 480; - static constexpr int game_height = 500; - - virtual ~Game() override = default; - - void set_paused(bool paused); - -private: - Game(); - - virtual void paint_event(GUI::PaintEvent&) override; - virtual void keyup_event(GUI::KeyEvent&) override; - virtual void keydown_event(GUI::KeyEvent&) override; - virtual void mousemove_event(GUI::MouseEvent&) override; - virtual void timer_event(Core::TimerEvent&) override; - - void reset(); - void reset_ball(); - void reset_paddle(); - void generate_bricks(); - void tick(); - void hurt(); - void win(); - - struct Ball { - Gfx::FloatPoint position; - Gfx::FloatPoint velocity; - float radius { 8 }; - - float x() const { return position.x(); } - float y() const { return position.y(); } - - Gfx::FloatRect rect() const - { - return { x() - radius, y() - radius, radius * 2, radius * 2 }; - } - }; - - struct Paddle { - Gfx::FloatRect rect; - float speed { 5 }; - bool moving_left { false }; - bool moving_right { false }; - }; - - struct Brick { - Gfx::FloatRect rect; - Gfx::Color color; - bool dead { false }; - - Brick(int row, int column, Gfx::Color c, int brick_width = 40, int brick_height = 12, int field_left_offset = 30, int field_top_offset = 30, int brick_spacing = 3) - { - rect = { - field_left_offset + (column * brick_width) + (column * brick_spacing), - field_top_offset + (row * brick_height) + (row * brick_spacing), - brick_width, - brick_height - }; - color = c; - } - }; - - Gfx::IntRect lives_left_rect() const - { - int msg_width = font().width(String::formatted("Lives: {}", m_lives)); - return { (game_width - msg_width - 2), 2, msg_width, font().glyph_height() }; - } - - Gfx::IntRect pause_rect() const - { - char const* msg = m_cheater ? "C H E A T E R" : "P A U S E D"; - int msg_width = font().width(msg); - int msg_height = font().glyph_height(); - return { (game_width / 2) - (msg_width / 2), (game_height / 2) - (msg_height / 2), msg_width, msg_height }; - } - - bool m_paused; - int m_lives; - int m_board; - long m_pause_count; - bool m_cheater; - Ball m_ball; - Paddle m_paddle; - Vector<Brick> m_bricks; -}; - -} diff --git a/Userland/Games/Breakout/LevelSelectDialog.cpp b/Userland/Games/Breakout/LevelSelectDialog.cpp deleted file mode 100644 index fb45e21adc..0000000000 --- a/Userland/Games/Breakout/LevelSelectDialog.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2020-2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "LevelSelectDialog.h" -#include <LibGUI/BoxLayout.h> -#include <LibGUI/Button.h> -#include <LibGUI/Label.h> -#include <LibGUI/ListView.h> - -namespace Breakout { - -LevelSelectDialog::LevelSelectDialog(Window* parent_window) - : Dialog(parent_window) -{ - set_rect(0, 0, 300, 250); - set_title("Level Select"); - build(); -} - -GUI::Dialog::ExecResult LevelSelectDialog::show(int& board_number, Window* parent_window) -{ - auto box = LevelSelectDialog::construct(parent_window); - box->set_resizable(false); - if (parent_window) - box->set_icon(parent_window->icon()); - auto result = box->exec(); - board_number = box->level(); - return result; -} - -void LevelSelectDialog::build() -{ - auto& main_widget = set_main_widget<GUI::Widget>(); - main_widget.set_fill_with_background_color(true); - - auto& layout = main_widget.set_layout<GUI::VerticalBoxLayout>(); - layout.set_margins(4); - - main_widget.add<GUI::Label>("Choose a level").set_text_alignment(Gfx::TextAlignment::Center); - - auto& level_list = main_widget.add<GUI::Widget>(); - auto& scroll_layout = level_list.set_layout<GUI::VerticalBoxLayout>(); - scroll_layout.set_spacing(4); - - level_list.add<GUI::Button>("Rainbow").on_click = [this](auto) { - m_level = -1; - done(ExecResult::OK); - }; - - level_list.add<GUI::Button>(":^)").on_click = [this](auto) { - m_level = 0; - done(ExecResult::OK); - }; -} -} diff --git a/Userland/Games/Breakout/LevelSelectDialog.h b/Userland/Games/Breakout/LevelSelectDialog.h deleted file mode 100644 index 89ccb40048..0000000000 --- a/Userland/Games/Breakout/LevelSelectDialog.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020-2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <LibGUI/Dialog.h> - -namespace Breakout { -class LevelSelectDialog : public GUI::Dialog { - C_OBJECT(LevelSelectDialog) -public: - virtual ~LevelSelectDialog() override = default; - static ExecResult show(int& board_number, Window* parent_window); - int level() const { return m_level; } - -private: - explicit LevelSelectDialog(Window* parent_window); - void build(); - - int m_level; -}; -} diff --git a/Userland/Games/Breakout/main.cpp b/Userland/Games/Breakout/main.cpp deleted file mode 100644 index 53a30852d9..0000000000 --- a/Userland/Games/Breakout/main.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Game.h" -#include <AK/URL.h> -#include <LibCore/System.h> -#include <LibDesktop/Launcher.h> -#include <LibGUI/Application.h> -#include <LibGUI/Icon.h> -#include <LibGUI/Menu.h> -#include <LibGUI/Menubar.h> -#include <LibGUI/Window.h> -#include <LibGfx/Bitmap.h> -#include <LibMain/Main.h> - -ErrorOr<int> serenity_main(Main::Arguments arguments) -{ - TRY(Core::System::pledge("stdio recvfd sendfd rpath unix")); - - auto app = TRY(GUI::Application::try_create(arguments)); - - TRY(Desktop::Launcher::add_allowed_handler_with_only_specific_urls("/bin/Help", { URL::create_with_file_protocol("/usr/share/man/man6/Breakout.md") })); - TRY(Desktop::Launcher::seal_allowlist()); - - TRY(Core::System::pledge("stdio recvfd sendfd rpath")); - - TRY(Core::System::unveil("/res", "r")); - TRY(Core::System::unveil("/tmp/portal/launch", "rw")); - TRY(Core::System::unveil(nullptr, nullptr)); - - auto window = TRY(GUI::Window::try_create()); - window->resize(Breakout::Game::game_width, Breakout::Game::game_height); - window->set_resizable(false); - window->set_double_buffering_enabled(false); - window->set_title("Breakout"); - - auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-breakout")); - window->set_icon(app_icon.bitmap_for_size(16)); - - auto game = TRY(window->try_set_main_widget<Breakout::Game>()); - - auto game_menu = TRY(window->try_add_menu("&Game")); - TRY(game_menu->try_add_action(GUI::Action::create_checkable("&Pause", { {}, Key_P }, [&](auto& action) { - game->set_paused(action.is_checked()); - }))); - - TRY(game_menu->try_add_separator()); - TRY(game_menu->try_add_action(GUI::CommonActions::make_quit_action([](auto&) { - GUI::Application::the()->quit(); - }))); - - auto help_menu = TRY(window->try_add_menu("&Help")); - TRY(help_menu->try_add_action(GUI::CommonActions::make_help_action([](auto&) { - Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man6/Breakout.md"), "/bin/Help"); - }))); - TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Breakout", app_icon, window))); - - window->show(); - - return app->exec(); -} diff --git a/Userland/Games/CMakeLists.txt b/Userland/Games/CMakeLists.txt index a75ac6c7ff..7732fd5f80 100644 --- a/Userland/Games/CMakeLists.txt +++ b/Userland/Games/CMakeLists.txt @@ -1,12 +1,10 @@ add_subdirectory(2048) -add_subdirectory(Breakout) add_subdirectory(Chess) add_subdirectory(FlappyBug) add_subdirectory(GameOfLife) add_subdirectory(Hearts) add_subdirectory(MasterWord) add_subdirectory(Minesweeper) -add_subdirectory(Pong) add_subdirectory(Snake) add_subdirectory(Solitaire) add_subdirectory(Spider) diff --git a/Userland/Games/Pong/CMakeLists.txt b/Userland/Games/Pong/CMakeLists.txt deleted file mode 100644 index 1787e60133..0000000000 --- a/Userland/Games/Pong/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -serenity_component( - Pong - RECOMMENDED - TARGETS Pong -) - -set(SOURCES - main.cpp - Game.cpp -) - -serenity_app(Pong ICON app-pong) -target_link_libraries(Pong LibGUI LibMain LibDesktop) diff --git a/Userland/Games/Pong/Game.cpp b/Userland/Games/Pong/Game.cpp deleted file mode 100644 index eee3697b99..0000000000 --- a/Userland/Games/Pong/Game.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2020-2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Game.h" -#include <AK/Random.h> -#include <LibGfx/AntiAliasingPainter.h> - -namespace Pong { - -Game::Game() -{ - start_timer(16); - reset(); -} - -void Game::reset_keys() -{ - m_up_key_held = false; - m_down_key_held = false; -} - -void Game::reset_paddles() -{ - if (m_cursor_paddle_target_y.has_value()) - update(cursor_paddle_target_rect()); - m_cursor_paddle_target_y.clear(); - - update(enclosing_int_rect(m_player1_paddle.rect)); - m_player1_paddle.moving_up = m_up_key_held; - m_player1_paddle.moving_down = m_down_key_held; - m_player1_paddle.rect = { game_width - 12, game_height / 2 - 40, m_player1_paddle.width, m_player1_paddle.height }; - update(enclosing_int_rect(m_player1_paddle.rect)); - - update(enclosing_int_rect(m_player2_paddle.rect)); - m_player2_paddle.moving_up = false; - m_player2_paddle.moving_down = false; - m_player2_paddle.rect = { 4, game_height / 2 - 40, m_player2_paddle.width, m_player2_paddle.height }; - update(enclosing_int_rect(m_player2_paddle.rect)); -} - -void Game::reset() -{ - if (m_game_over) { - m_game_over = false; - start_timer(16); - } - - // Make sure the current ball disappears. - update(enclosing_int_rect(m_ball.rect())); - - reset_scores(); - reset_ball(1); - reset_keys(); - reset_paddles(); -} - -void Game::timer_event(Core::TimerEvent&) -{ - tick(); -} - -void Game::paint_event(GUI::PaintEvent& event) -{ - GUI::Painter painter(*this); - painter.add_clip_rect(event.rect()); - - Gfx::AntiAliasingPainter aa_painter { painter }; - - painter.fill_rect(rect(), Color::Black); - painter.fill_rect(enclosing_int_rect(m_net.rect()), m_net.color); - - aa_painter.fill_ellipse(enclosing_int_rect(m_ball.rect()), Color::Red); - - painter.fill_rect(enclosing_int_rect(m_player1_paddle.rect), m_player1_paddle.color); - painter.fill_rect(enclosing_int_rect(m_player2_paddle.rect), m_player2_paddle.color); - - if (m_cursor_paddle_target_y.has_value()) - aa_painter.fill_ellipse(cursor_paddle_target_rect(), Color::Blue); - - painter.draw_text(player_1_score_rect(), String::formatted("{}", m_player_1_score), Gfx::TextAlignment::TopLeft, Color::White); - painter.draw_text(player_2_score_rect(), String::formatted("{}", m_player_2_score), Gfx::TextAlignment::TopLeft, Color::White); -} - -void Game::keyup_event(GUI::KeyEvent& event) -{ - switch (event.key()) { - case Key_W: - case Key_Up: - m_up_key_held = false; - m_player1_paddle.moving_up = false; - break; - case Key_S: - case Key_Down: - m_down_key_held = false; - m_player1_paddle.moving_down = false; - break; - default: - break; - } -} - -void Game::keydown_event(GUI::KeyEvent& event) -{ - switch (event.key()) { - case Key_Escape: - GUI::Application::the()->quit(); - break; - case Key_W: - case Key_Up: - m_up_key_held = true; - m_player1_paddle.moving_up = true; - m_player1_paddle.moving_down = false; - m_cursor_paddle_target_y.clear(); - break; - case Key_S: - case Key_Down: - m_down_key_held = true; - m_player1_paddle.moving_up = false; - m_player1_paddle.moving_down = true; - m_cursor_paddle_target_y.clear(); - break; - default: - break; - } -} - -void Game::track_mouse_move(Gfx::IntPoint const& point) -{ - if (m_up_key_held || m_down_key_held) { - // We're using the keyboard to move the paddle, the cursor is doing something else - return; - } - - if (m_cursor_paddle_target_y.has_value()) - update(cursor_paddle_target_rect()); - - auto relative_point = point - window()->position(); - m_cursor_paddle_target_y = clamp(relative_point.y() - m_player1_paddle.rect.height() / 2, 0.f, game_height - m_player1_paddle.rect.height()); - if (m_player1_paddle.rect.y() > *m_cursor_paddle_target_y) { - m_player1_paddle.moving_up = true; - m_player1_paddle.moving_down = false; - } else if (m_player1_paddle.rect.y() < *m_cursor_paddle_target_y) { - m_player1_paddle.moving_up = false; - m_player1_paddle.moving_down = true; - } - update(cursor_paddle_target_rect()); -} - -void Game::reset_scores() -{ - // Clearing the scores first would lead to overly narrow rects for multi-digit scores. - update(player_1_score_rect()); - update(player_2_score_rect()); - - m_player_1_score = 0; - m_player_2_score = 0; -} - -void Game::reset_ball(int serve_to_player) -{ - int position_y_min = (game_width / 2) - 50; - int position_y_max = (game_width / 2) + 50; - int position_y = get_random<u32>() % (position_y_max - position_y_min + 1) + position_y_min; - int position_x = (game_height / 2); - int velocity_y = get_random<u32>() % 3 + 1; - int velocity_x = 4 + (5 - velocity_y); - if (get_random<u32>() % 2) - velocity_y = velocity_y * -1; - if (serve_to_player == 2) - velocity_x = velocity_x * -1; - - m_ball = {}; - m_ball.position = { position_x, position_y }; - m_ball.velocity = { velocity_x, velocity_y }; -} - -void Game::show_game_over_message(int winner) -{ - GUI::MessageBox::show(window(), String::formatted("Player {} wins!", winner), "Pong", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OK); -} - -void Game::round_over(int winner) -{ - stop_timer(); - if (winner == 1) { - update(player_1_score_rect()); - m_player_1_score++; - update(player_1_score_rect()); - } - - if (winner == 2) { - update(player_2_score_rect()); - m_player_2_score++; - update(player_2_score_rect()); - } - - if (m_player_1_score == m_score_to_win || m_player_2_score == m_score_to_win) { - m_game_over = true; - show_game_over_message(winner); - return; - } - - reset_ball(winner); - reset_paddles(); - start_timer(16); -} - -void Game::calculate_move() -{ - int player_2_paddle_top = m_player2_paddle.rect.top(); - int player_2_paddle_bottom = m_player2_paddle.rect.bottom(); - - if (m_ball.velocity.x() > 0 || m_ball.x() > game_width / 2) { - // The ball is in the opponent's court, relax. - m_player2_paddle.moving_up = false; - m_player2_paddle.moving_down = false; - return; - } - - int ball_position = m_ball.y() + m_ball.radius; - - // AI paddle begins moving when the ball crosses the begin_trigger, - // but stops only if it crosses the end_trigger. end_trigger forces - // overcorrection, so that the paddle moves more smoothly. - int begin_trigger = m_player2_paddle.rect.height() / 4; - int end_trigger = m_player2_paddle.rect.height() / 2; - - if (m_player2_paddle.moving_up) { - if (player_2_paddle_top + end_trigger < ball_position) - m_player2_paddle.moving_up = false; - } else { - if (player_2_paddle_top + begin_trigger > ball_position) - m_player2_paddle.moving_up = true; - } - - if (m_player2_paddle.moving_down) { - if (player_2_paddle_bottom - end_trigger > ball_position) - m_player2_paddle.moving_down = false; - } else { - if (player_2_paddle_bottom - begin_trigger < ball_position) - m_player2_paddle.moving_down = true; - } -} - -void Game::tick() -{ - auto new_ball = m_ball; - new_ball.position += new_ball.velocity; - - update(enclosing_int_rect(m_ball.rect())); - - if (new_ball.y() < new_ball.radius || new_ball.y() > game_height - new_ball.radius) { - new_ball.position.set_y(m_ball.y()); - new_ball.velocity.set_y(new_ball.velocity.y() * -1); - } - - if (new_ball.x() < new_ball.radius) { - round_over(1); - return; - } - - if (new_ball.x() > (game_width - new_ball.radius)) { - round_over(2); - return; - } - - update(enclosing_int_rect(new_ball.rect())); - - if (new_ball.rect().intersects(m_player1_paddle.rect)) { - new_ball.position.set_x(m_ball.x()); - new_ball.velocity.set_x(new_ball.velocity.x() * -1); - - float distance_to_middle_of_paddle = new_ball.y() - m_player1_paddle.rect.center().y(); - float relative_impact_point = distance_to_middle_of_paddle / m_player1_paddle.rect.height(); - new_ball.velocity.set_y(relative_impact_point * 7); - } - - if (new_ball.rect().intersects(m_player2_paddle.rect)) { - new_ball.position.set_x(m_ball.x()); - new_ball.velocity.set_x(new_ball.velocity.x() * -1); - - float distance_to_middle_of_paddle = new_ball.y() - m_player2_paddle.rect.center().y(); - float relative_impact_point = distance_to_middle_of_paddle / m_player2_paddle.rect.height(); - new_ball.velocity.set_y(relative_impact_point * 7); - } - - if (m_player1_paddle.moving_up) { - update(enclosing_int_rect(m_player1_paddle.rect)); - m_player1_paddle.rect.set_y(max(0.0f, m_player1_paddle.rect.y() - m_player1_paddle.speed)); - if (m_cursor_paddle_target_y.has_value() && m_player1_paddle.rect.y() <= *m_cursor_paddle_target_y) { - m_cursor_paddle_target_y.clear(); - m_player1_paddle.moving_up = false; - } - update(enclosing_int_rect(m_player1_paddle.rect)); - } - if (m_player1_paddle.moving_down) { - update(enclosing_int_rect(m_player1_paddle.rect)); - m_player1_paddle.rect.set_y(min(game_height - m_player1_paddle.rect.height(), m_player1_paddle.rect.y() + m_player1_paddle.speed)); - if (m_cursor_paddle_target_y.has_value() && m_player1_paddle.rect.y() >= *m_cursor_paddle_target_y) { - m_cursor_paddle_target_y.clear(); - m_player1_paddle.moving_down = false; - } - update(enclosing_int_rect(m_player1_paddle.rect)); - } - - calculate_move(); - - if (m_player2_paddle.moving_up) { - update(enclosing_int_rect(m_player2_paddle.rect)); - m_player2_paddle.rect.set_y(max(0.0f, m_player2_paddle.rect.y() - m_player2_paddle.speed)); - update(enclosing_int_rect(m_player2_paddle.rect)); - } - if (m_player2_paddle.moving_down) { - update(enclosing_int_rect(m_player2_paddle.rect)); - m_player2_paddle.rect.set_y(min(game_height - m_player2_paddle.rect.height(), m_player2_paddle.rect.y() + m_player2_paddle.speed)); - update(enclosing_int_rect(m_player2_paddle.rect)); - } - - m_ball = new_ball; -} - -} diff --git a/Userland/Games/Pong/Game.h b/Userland/Games/Pong/Game.h deleted file mode 100644 index ab7973e63a..0000000000 --- a/Userland/Games/Pong/Game.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2020-2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/Optional.h> -#include <LibGUI/Application.h> -#include <LibGUI/MessageBox.h> -#include <LibGUI/MouseTracker.h> -#include <LibGUI/Painter.h> -#include <LibGUI/Widget.h> -#include <LibGfx/Bitmap.h> -#include <LibGfx/Font/Font.h> -#include <LibGfx/StandardCursor.h> - -namespace Pong { - -class Game final : public GUI::Widget - , GUI::MouseTracker { - C_OBJECT(Game); - -public: - static constexpr int game_width = 560; - static constexpr int game_height = 480; - - virtual ~Game() override = default; - - void reset(); - -private: - Game(); - - virtual void paint_event(GUI::PaintEvent&) override; - virtual void keyup_event(GUI::KeyEvent&) override; - virtual void keydown_event(GUI::KeyEvent&) override; - virtual void timer_event(Core::TimerEvent&) override; - virtual void track_mouse_move(Gfx::IntPoint const&) override; - - void reset_scores(); - void reset_ball(int serve_to_player); - void reset_keys(); - void reset_paddles(); - void tick(); - void round_over(int player); - void show_game_over_message(int player); - void calculate_move(); - - struct Ball { - Gfx::FloatPoint position; - Gfx::FloatPoint velocity; - float radius { 4 }; - - float x() const { return position.x(); } - float y() const { return position.y(); } - - Gfx::FloatRect rect() const - { - return { x() - radius, y() - radius, radius * 2, radius * 2 }; - } - }; - - struct Paddle { - Gfx::FloatRect rect; - float speed { 5 }; - float width { 8 }; - float height { 28 }; - bool moving_up { false }; - bool moving_down { false }; - Gfx::Color color { Color::White }; - }; - - struct Net { - Gfx::Color color { Color::White }; - Gfx::FloatRect rect() const - { - return { (game_width / 2) - 1, 0, 2, game_height }; - } - }; - - constexpr static int score_margin = 5; - - Gfx::IntRect player_1_score_rect() const - { - int score_width = font().width(String::formatted("{}", m_player_1_score)); - return { (game_width / 2) + score_margin, score_margin, score_width, font().glyph_height() }; - } - - Gfx::IntRect player_2_score_rect() const - { - int score_width = font().width(String::formatted("{}", m_player_2_score)); - return { (game_width / 2) - score_width - score_margin, score_margin, score_width, font().glyph_height() }; - } - - Gfx::IntRect cursor_paddle_target_rect() const - { - int radius = 3; - int center_x = m_player1_paddle.rect.center().x(); - int center_y = *m_cursor_paddle_target_y + m_player1_paddle.rect.height() / 2; - return { center_x - radius, center_y - radius, 2 * radius, 2 * radius }; - } - - Net m_net; - Ball m_ball; - Paddle m_player1_paddle; - Paddle m_player2_paddle; - - int m_score_to_win = 21; - int m_player_1_score = 0; - int m_player_2_score = 0; - - Optional<int> m_cursor_paddle_target_y; - bool m_up_key_held = false; - bool m_down_key_held = false; - - bool m_game_over = false; -}; - -} diff --git a/Userland/Games/Pong/main.cpp b/Userland/Games/Pong/main.cpp deleted file mode 100644 index fc9fd1c8e4..0000000000 --- a/Userland/Games/Pong/main.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020-2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Game.h" -#include <AK/URL.h> -#include <LibCore/System.h> -#include <LibDesktop/Launcher.h> -#include <LibGUI/Application.h> -#include <LibGUI/Icon.h> -#include <LibGUI/Menu.h> -#include <LibGUI/Menubar.h> -#include <LibGUI/Window.h> -#include <LibGfx/Bitmap.h> -#include <LibMain/Main.h> - -ErrorOr<int> serenity_main(Main::Arguments arguments) -{ - TRY(Core::System::pledge("stdio rpath recvfd sendfd unix")); - - auto app = TRY(GUI::Application::try_create(arguments)); - - TRY(Desktop::Launcher::add_allowed_handler_with_only_specific_urls("/bin/Help", { URL::create_with_file_protocol("/usr/share/man/man6/Pong.md") })); - TRY(Desktop::Launcher::seal_allowlist()); - - TRY(Core::System::pledge("stdio rpath recvfd sendfd")); - - TRY(Core::System::unveil("/res", "r")); - TRY(Core::System::unveil("/tmp/portal/launch", "rw")); - TRY(Core::System::unveil(nullptr, nullptr)); - - auto window = TRY(GUI::Window::try_create()); - window->resize(Pong::Game::game_width, Pong::Game::game_height); - auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-pong")); - window->set_icon(app_icon.bitmap_for_size(16)); - window->set_title("Pong"); - window->set_double_buffering_enabled(false); - auto game = TRY(window->try_set_main_widget<Pong::Game>()); - window->set_resizable(false); - - 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")), [&](auto&) { - game->reset(); - }))); - - TRY(game_menu->try_add_separator()); - - TRY(game_menu->try_add_action(GUI::CommonActions::make_quit_action([](auto&) { - GUI::Application::the()->quit(); - }))); - - auto help_menu = TRY(window->try_add_menu("&Help")); - TRY(help_menu->try_add_action(GUI::CommonActions::make_help_action([](auto&) { - Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man6/Pong.md"), "/bin/Help"); - }))); - TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Pong", app_icon, window))); - - window->show(); - - return app->exec(); -} |