1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:07:44 +00:00

Solitaire: Place files in Solitaire namespace and rename main widget

The purpose is to allow the Solitaire widget to be used in GML. The
macro to register a widget requires a namespace, so this moves all files
in the application to the Solitaire namespace. This also renames the
SolitaireWidget class to Game - this is to avoid the redundancy /
verbosity of typing "Solitaire::SolitaireWidget", and matches many other
games in Serenity (Breakout, 2048, etc.).
This commit is contained in:
Timothy Flynn 2021-05-05 09:42:59 -04:00 committed by Andreas Kling
parent 15f0ee1727
commit e1492e9a62
8 changed files with 59 additions and 35 deletions

View file

@ -1,8 +1,8 @@
set(SOURCES set(SOURCES
Card.cpp Card.cpp
CardStack.cpp CardStack.cpp
Game.cpp
main.cpp main.cpp
SolitaireWidget.cpp
) )
serenity_app(Solitaire ICON app-solitaire) serenity_app(Solitaire ICON app-solitaire)

View file

@ -9,6 +9,8 @@
#include <LibGfx/Font.h> #include <LibGfx/Font.h>
#include <LibGfx/FontDatabase.h> #include <LibGfx/FontDatabase.h>
namespace Solitaire {
static const NonnullRefPtr<Gfx::CharacterBitmap> s_diamond = Gfx::CharacterBitmap::create_from_ascii( static const NonnullRefPtr<Gfx::CharacterBitmap> s_diamond = Gfx::CharacterBitmap::create_from_ascii(
" # " " # "
" ### " " ### "
@ -155,3 +157,5 @@ void Card::clear_and_draw(GUI::Painter& painter, const Color& background_color)
draw(painter); draw(painter);
save_old_position(); save_old_position();
} }
}

View file

@ -13,6 +13,8 @@
#include <LibGfx/Rect.h> #include <LibGfx/Rect.h>
#include <ctype.h> #include <ctype.h>
namespace Solitaire {
class Card final : public Core::Object { class Card final : public Core::Object {
C_OBJECT(Card) C_OBJECT(Card)
public: public:
@ -63,3 +65,5 @@ private:
bool m_moving { false }; bool m_moving { false };
bool m_upside_down { false }; bool m_upside_down { false };
}; };
}

View file

@ -6,6 +6,8 @@
#include "CardStack.h" #include "CardStack.h"
namespace Solitaire {
CardStack::CardStack() CardStack::CardStack()
: m_position({ 0, 0 }) : m_position({ 0, 0 })
, m_type(Invalid) , m_type(Invalid)
@ -216,3 +218,5 @@ void CardStack::calculate_bounding_box()
m_bounding_box.set_size(Card::width + width, Card::height + height); m_bounding_box.set_size(Card::width + width, Card::height + height);
} }
}

View file

@ -9,6 +9,8 @@
#include "Card.h" #include "Card.h"
#include <AK/Vector.h> #include <AK/Vector.h>
namespace Solitaire {
class CardStack final { class CardStack final {
public: public:
enum Type { enum Type {
@ -78,3 +80,5 @@ private:
bool m_dirty { false }; bool m_dirty { false };
Gfx::IntRect m_base; Gfx::IntRect m_base;
}; };
}

View file

@ -4,25 +4,27 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include "SolitaireWidget.h" #include "Game.h"
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <time.h> #include <time.h>
namespace Solitaire {
static const Color s_background_color { Color::from_rgb(0x008000) }; static const Color s_background_color { Color::from_rgb(0x008000) };
static constexpr uint8_t new_game_animation_delay = 5; static constexpr uint8_t new_game_animation_delay = 5;
static constexpr int s_timer_interval_ms = 1000 / 60; static constexpr int s_timer_interval_ms = 1000 / 60;
SolitaireWidget::SolitaireWidget(Function<void(uint32_t)>&& on_score_update) Game::Game(Function<void(uint32_t)>&& on_score_update)
: m_on_score_update(move(on_score_update)) : m_on_score_update(move(on_score_update))
{ {
set_fill_with_background_color(false); set_fill_with_background_color(false);
m_stacks[Stock] = CardStack({ 10, 10 }, CardStack::Type::Stock); m_stacks[Stock] = CardStack({ 10, 10 }, CardStack::Type::Stock);
m_stacks[Waste] = CardStack({ 10 + Card::width + 10, 10 }, CardStack::Type::Waste); m_stacks[Waste] = CardStack({ 10 + Card::width + 10, 10 }, CardStack::Type::Waste);
m_stacks[Foundation4] = CardStack({ SolitaireWidget::width - Card::width - 10, 10 }, CardStack::Type::Foundation); m_stacks[Foundation4] = CardStack({ Game::width - Card::width - 10, 10 }, CardStack::Type::Foundation);
m_stacks[Foundation3] = CardStack({ SolitaireWidget::width - 2 * Card::width - 20, 10 }, CardStack::Type::Foundation); m_stacks[Foundation3] = CardStack({ Game::width - 2 * Card::width - 20, 10 }, CardStack::Type::Foundation);
m_stacks[Foundation2] = CardStack({ SolitaireWidget::width - 3 * Card::width - 30, 10 }, CardStack::Type::Foundation); m_stacks[Foundation2] = CardStack({ Game::width - 3 * Card::width - 30, 10 }, CardStack::Type::Foundation);
m_stacks[Foundation1] = CardStack({ SolitaireWidget::width - 4 * Card::width - 40, 10 }, CardStack::Type::Foundation); m_stacks[Foundation1] = CardStack({ Game::width - 4 * Card::width - 40, 10 }, CardStack::Type::Foundation);
m_stacks[Pile1] = CardStack({ 10, 10 + Card::height + 10 }, CardStack::Type::Normal); m_stacks[Pile1] = CardStack({ 10, 10 + Card::height + 10 }, CardStack::Type::Normal);
m_stacks[Pile2] = CardStack({ 10 + Card::width + 10, 10 + Card::height + 10 }, CardStack::Type::Normal); m_stacks[Pile2] = CardStack({ 10 + Card::width + 10, 10 + Card::height + 10 }, CardStack::Type::Normal);
m_stacks[Pile3] = CardStack({ 10 + 2 * Card::width + 20, 10 + Card::height + 10 }, CardStack::Type::Normal); m_stacks[Pile3] = CardStack({ 10 + 2 * Card::width + 20, 10 + Card::height + 10 }, CardStack::Type::Normal);
@ -32,7 +34,7 @@ SolitaireWidget::SolitaireWidget(Function<void(uint32_t)>&& on_score_update)
m_stacks[Pile7] = CardStack({ 10 + 6 * Card::width + 60, 10 + Card::height + 10 }, CardStack::Type::Normal); m_stacks[Pile7] = CardStack({ 10 + 6 * Card::width + 60, 10 + Card::height + 10 }, CardStack::Type::Normal);
} }
SolitaireWidget::~SolitaireWidget() Game::~Game()
{ {
} }
@ -41,11 +43,11 @@ static float rand_float()
return rand() / static_cast<float>(RAND_MAX); return rand() / static_cast<float>(RAND_MAX);
} }
void SolitaireWidget::timer_event(Core::TimerEvent&) void Game::timer_event(Core::TimerEvent&)
{ {
if (m_game_over_animation) { if (m_game_over_animation) {
VERIFY(!m_animation.card().is_null()); VERIFY(!m_animation.card().is_null());
if (m_animation.card()->position().x() > SolitaireWidget::width || m_animation.card()->rect().right() < 0) if (m_animation.card()->position().x() > Game::width || m_animation.card()->rect().right() < 0)
create_new_animation_card(); create_new_animation_card();
m_animation.tick(); m_animation.tick();
@ -57,18 +59,18 @@ void SolitaireWidget::timer_event(Core::TimerEvent&)
} }
} }
void SolitaireWidget::create_new_animation_card() void Game::create_new_animation_card()
{ {
srand(time(nullptr)); srand(time(nullptr));
auto card = Card::construct(static_cast<Card::Type>(rand() % Card::Type::__Count), rand() % Card::card_count); auto card = Card::construct(static_cast<Card::Type>(rand() % Card::Type::__Count), rand() % Card::card_count);
card->set_position({ rand() % (SolitaireWidget::width - Card::width), rand() % (SolitaireWidget::height / 8) }); card->set_position({ rand() % (Game::width - Card::width), rand() % (Game::height / 8) });
int x_sgn = card->position().x() > (SolitaireWidget::width / 2) ? -1 : 1; int x_sgn = card->position().x() > (Game::width / 2) ? -1 : 1;
m_animation = Animation(card, rand_float() + .4f, x_sgn * ((rand() % 3) + 2), .6f + rand_float() * .4f); m_animation = Animation(card, rand_float() + .4f, x_sgn * ((rand() % 3) + 2), .6f + rand_float() * .4f);
} }
void SolitaireWidget::start_game_over_animation() void Game::start_game_over_animation()
{ {
if (m_game_over_animation) if (m_game_over_animation)
return; return;
@ -77,7 +79,7 @@ void SolitaireWidget::start_game_over_animation()
m_game_over_animation = true; m_game_over_animation = true;
} }
void SolitaireWidget::stop_game_over_animation() void Game::stop_game_over_animation()
{ {
if (!m_game_over_animation) if (!m_game_over_animation)
return; return;
@ -86,7 +88,7 @@ void SolitaireWidget::stop_game_over_animation()
update(); update();
} }
void SolitaireWidget::setup() void Game::setup()
{ {
stop_game_over_animation(); stop_game_over_animation();
stop_timer(); stop_timer();
@ -115,13 +117,13 @@ void SolitaireWidget::setup()
update(); update();
} }
void SolitaireWidget::update_score(int to_add) void Game::update_score(int to_add)
{ {
m_score = max(static_cast<int>(m_score) + to_add, 0); m_score = max(static_cast<int>(m_score) + to_add, 0);
m_on_score_update(m_score); m_on_score_update(m_score);
} }
void SolitaireWidget::keydown_event(GUI::KeyEvent& event) void Game::keydown_event(GUI::KeyEvent& event)
{ {
if (m_new_game_animation || m_game_over_animation) if (m_new_game_animation || m_game_over_animation)
return; return;
@ -130,7 +132,7 @@ void SolitaireWidget::keydown_event(GUI::KeyEvent& event)
start_game_over_animation(); start_game_over_animation();
} }
void SolitaireWidget::mousedown_event(GUI::MouseEvent& event) void Game::mousedown_event(GUI::MouseEvent& event)
{ {
GUI::Widget::mousedown_event(event); GUI::Widget::mousedown_event(event);
@ -183,7 +185,7 @@ void SolitaireWidget::mousedown_event(GUI::MouseEvent& event)
} }
} }
void SolitaireWidget::mouseup_event(GUI::MouseEvent& event) void Game::mouseup_event(GUI::MouseEvent& event)
{ {
GUI::Widget::mouseup_event(event); GUI::Widget::mouseup_event(event);
@ -236,7 +238,7 @@ void SolitaireWidget::mouseup_event(GUI::MouseEvent& event)
m_has_to_repaint = true; m_has_to_repaint = true;
} }
void SolitaireWidget::mousemove_event(GUI::MouseEvent& event) void Game::mousemove_event(GUI::MouseEvent& event)
{ {
GUI::Widget::mousemove_event(event); GUI::Widget::mousemove_event(event);
@ -256,7 +258,7 @@ void SolitaireWidget::mousemove_event(GUI::MouseEvent& event)
m_has_to_repaint = true; m_has_to_repaint = true;
} }
void SolitaireWidget::doubleclick_event(GUI::MouseEvent& event) void Game::doubleclick_event(GUI::MouseEvent& event)
{ {
GUI::Widget::doubleclick_event(event); GUI::Widget::doubleclick_event(event);
@ -297,7 +299,7 @@ void SolitaireWidget::doubleclick_event(GUI::MouseEvent& event)
m_has_to_repaint = true; m_has_to_repaint = true;
} }
void SolitaireWidget::check_for_game_over() void Game::check_for_game_over()
{ {
for (auto& stack : m_stacks) { for (auto& stack : m_stacks) {
if (stack.type() != CardStack::Type::Foundation) if (stack.type() != CardStack::Type::Foundation)
@ -309,7 +311,7 @@ void SolitaireWidget::check_for_game_over()
start_game_over_animation(); start_game_over_animation();
} }
void SolitaireWidget::move_card(CardStack& from, CardStack& to) void Game::move_card(CardStack& from, CardStack& to)
{ {
auto card = from.pop(); auto card = from.pop();
@ -325,7 +327,7 @@ void SolitaireWidget::move_card(CardStack& from, CardStack& to)
m_has_to_repaint = true; m_has_to_repaint = true;
} }
void SolitaireWidget::mark_intersecting_stacks_dirty(Card& intersecting_card) void Game::mark_intersecting_stacks_dirty(Card& intersecting_card)
{ {
for (auto& stack : m_stacks) { for (auto& stack : m_stacks) {
if (intersecting_card.rect().intersects(stack.bounding_box())) { if (intersecting_card.rect().intersects(stack.bounding_box())) {
@ -335,7 +337,7 @@ void SolitaireWidget::mark_intersecting_stacks_dirty(Card& intersecting_card)
} }
} }
void SolitaireWidget::paint_event(GUI::PaintEvent& event) void Game::paint_event(GUI::PaintEvent& event)
{ {
GUI::Widget::paint_event(event); GUI::Widget::paint_event(event);
@ -412,3 +414,5 @@ void SolitaireWidget::paint_event(GUI::PaintEvent& event)
} }
} }
} }
}

View file

@ -10,17 +10,19 @@
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGUI/Widget.h> #include <LibGUI/Widget.h>
class SolitaireWidget final : public GUI::Widget { namespace Solitaire {
C_OBJECT(SolitaireWidget)
class Game final : public GUI::Widget {
C_OBJECT(Game)
public: public:
static constexpr int width = 640; static constexpr int width = 640;
static constexpr int height = 480; static constexpr int height = 480;
virtual ~SolitaireWidget() override; virtual ~Game() override;
void setup(); void setup();
private: private:
SolitaireWidget(Function<void(uint32_t)>&& on_score_update); Game(Function<void(uint32_t)>&& on_score_update);
class Animation { class Animation {
public: public:
@ -43,9 +45,9 @@ private:
VERIFY(!m_animation_card.is_null()); VERIFY(!m_animation_card.is_null());
m_y_velocity += m_gravity; m_y_velocity += m_gravity;
if (m_animation_card->position().y() + Card::height + m_y_velocity > SolitaireWidget::height + 1 && m_y_velocity > 0) { if (m_animation_card->position().y() + Card::height + m_y_velocity > Game::height + 1 && m_y_velocity > 0) {
m_y_velocity = min((m_y_velocity * -m_bouncyness), -8.f); m_y_velocity = min((m_y_velocity * -m_bouncyness), -8.f);
m_animation_card->rect().set_y(SolitaireWidget::height - Card::height); m_animation_card->rect().set_y(Game::height - Card::height);
m_animation_card->rect().translate_by(m_x_velocity, 0); m_animation_card->rect().translate_by(m_x_velocity, 0);
} else { } else {
m_animation_card->rect().translate_by(m_x_velocity, m_y_velocity); m_animation_card->rect().translate_by(m_x_velocity, m_y_velocity);
@ -119,3 +121,5 @@ private:
uint32_t m_score { 0 }; uint32_t m_score { 0 };
Function<void(uint32_t)> m_on_score_update; Function<void(uint32_t)> m_on_score_update;
}; };
}

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include "SolitaireWidget.h" #include "Game.h"
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Application.h> #include <LibGUI/Application.h>
#include <LibGUI/Icon.h> #include <LibGUI/Icon.h>
@ -37,9 +37,9 @@ int main(int argc, char** argv)
auto window = GUI::Window::construct(); auto window = GUI::Window::construct();
window->set_resizable(false); window->set_resizable(false);
window->resize(SolitaireWidget::width, SolitaireWidget::height); window->resize(Solitaire::Game::width, Solitaire::Game::height);
auto widget = SolitaireWidget::construct([&](uint32_t score) { auto widget = Solitaire::Game::construct([&](uint32_t score) {
window->set_title(String::formatted("Score: {} - Solitaire", score)); window->set_title(String::formatted("Score: {} - Solitaire", score));
}); });