mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
Breakout: Add player lives game mechanic and pause functionality
This commit is contained in:
parent
afba614d68
commit
0cc970bd07
Notes:
sideshowbarker
2024-07-19 00:42:51 +09:00
Author: https://github.com/bcoles Commit: https://github.com/SerenityOS/serenity/commit/0cc970bd07c Pull-request: https://github.com/SerenityOS/serenity/pull/4465
3 changed files with 73 additions and 5 deletions
|
@ -29,6 +29,7 @@
|
|||
#include <LibGUI/Application.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/StandardCursor.h>
|
||||
|
||||
namespace Breakout {
|
||||
|
@ -39,6 +40,7 @@ Game::Game()
|
|||
auto level_dialog = LevelSelectDialog::show(m_board, window());
|
||||
if (level_dialog != GUI::Dialog::ExecOK)
|
||||
m_board = -1;
|
||||
set_paused(false);
|
||||
start_timer(16);
|
||||
reset();
|
||||
}
|
||||
|
@ -56,6 +58,9 @@ void Game::reset_paddle()
|
|||
|
||||
void Game::reset()
|
||||
{
|
||||
m_lives = 3;
|
||||
m_pause_count = 0;
|
||||
m_cheater = false;
|
||||
reset_ball();
|
||||
reset_paddle();
|
||||
generate_bricks();
|
||||
|
@ -63,6 +68,8 @@ void Game::reset()
|
|||
|
||||
void Game::generate_bricks()
|
||||
{
|
||||
m_bricks = {};
|
||||
|
||||
Gfx::Color colors[] = {
|
||||
Gfx::Color::Red,
|
||||
Gfx::Color::Green,
|
||||
|
@ -105,8 +112,24 @@ void Game::generate_bricks()
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void Game::timer_event(Core::TimerEvent&)
|
||||
{
|
||||
if (m_paused)
|
||||
return;
|
||||
tick();
|
||||
}
|
||||
|
||||
|
@ -125,10 +148,23 @@ void Game::paint_event(GUI::PaintEvent& event)
|
|||
if (!brick.dead)
|
||||
painter.fill_rect(enclosing_int_rect(brick.rect), brick.color);
|
||||
}
|
||||
|
||||
int msg_width = font().width(String::formatted("Lives: {}", m_lives));
|
||||
int msg_height = font().glyph_height();
|
||||
painter.draw_text({ (game_width - msg_width - 2), 2, msg_width, msg_height }, String::formatted("Lives: {}", m_lives), Gfx::TextAlignment::Center, Color::White);
|
||||
|
||||
if (m_paused) {
|
||||
const char* 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();
|
||||
painter.draw_text({ (game_width / 2) - (msg_width / 2), (game_height / 2) - (msg_height / 2), msg_width, msg_height }, msg, Gfx::TextAlignment::Center, Color::White);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::keyup_event(GUI::KeyEvent& event)
|
||||
{
|
||||
if (m_paused)
|
||||
return;
|
||||
switch (event.key()) {
|
||||
case Key_Left:
|
||||
m_paddle.moving_left = false;
|
||||
|
@ -143,6 +179,8 @@ void Game::keyup_event(GUI::KeyEvent& event)
|
|||
|
||||
void Game::keydown_event(GUI::KeyEvent& event)
|
||||
{
|
||||
if (m_paused)
|
||||
return;
|
||||
switch (event.key()) {
|
||||
case Key_Escape:
|
||||
GUI::Application::the()->quit();
|
||||
|
@ -160,6 +198,8 @@ void Game::keydown_event(GUI::KeyEvent& event)
|
|||
|
||||
void Game::mousemove_event(GUI::MouseEvent& event)
|
||||
{
|
||||
if (m_paused)
|
||||
return;
|
||||
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);
|
||||
|
@ -185,7 +225,13 @@ void Game::reset_ball()
|
|||
void Game::hurt()
|
||||
{
|
||||
stop_timer();
|
||||
GUI::MessageBox::show(window(), "Ouch!", "Breakout", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OK);
|
||||
m_lives--;
|
||||
if (m_lives <= 0) {
|
||||
update();
|
||||
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);
|
||||
|
@ -194,7 +240,12 @@ void Game::hurt()
|
|||
void Game::win()
|
||||
{
|
||||
stop_timer();
|
||||
GUI::MessageBox::show(window(), "You win!", "Breakout", GUI::MessageBox::Type::Information, GUI::MessageBox::InputType::OK);
|
||||
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);
|
||||
}
|
||||
|
@ -268,6 +319,9 @@ void Game::tick()
|
|||
|
||||
m_ball = new_ball;
|
||||
|
||||
if (m_pause_count > 50)
|
||||
m_cheater = true;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
|
||||
virtual ~Game() override;
|
||||
|
||||
void set_paused(bool paused);
|
||||
|
||||
private:
|
||||
Game();
|
||||
|
||||
|
@ -94,7 +96,11 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
|
|
@ -59,16 +59,24 @@ int main(int argc, char** argv)
|
|||
|
||||
auto window = GUI::Window::construct();
|
||||
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 = GUI::Icon::default_icon("app-breakout");
|
||||
window->set_icon(app_icon.bitmap_for_size(16));
|
||||
window->set_title("Breakout");
|
||||
window->set_double_buffering_enabled(false);
|
||||
window->set_main_widget<Breakout::Game>();
|
||||
auto& game = window->set_main_widget<Breakout::Game>();
|
||||
window->show();
|
||||
|
||||
auto menubar = GUI::MenuBar::construct();
|
||||
|
||||
auto& app_menu = menubar->add_menu("Breakout");
|
||||
app_menu.add_action(GUI::Action::create_checkable("Pause", { {}, Key_P }, [&](auto& action) {
|
||||
game.set_paused(action.is_checked());
|
||||
return;
|
||||
}));
|
||||
|
||||
app_menu.add_separator();
|
||||
|
||||
app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
|
||||
GUI::Application::the()->quit();
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue