mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 02:27:43 +00:00
Solitaire: Refactor CardStack layout code
This commit is contained in:
parent
4bc8768737
commit
ef458f7b66
6 changed files with 64 additions and 52 deletions
|
@ -166,7 +166,7 @@ void Card::save_old_position()
|
|||
m_old_position_valid = true;
|
||||
}
|
||||
|
||||
void Card::draw_complete(GUI::Painter& painter, const Color& background_color)
|
||||
void Card::clear_and_draw(GUI::Painter& painter, const Color& background_color)
|
||||
{
|
||||
if (is_old_position_valid())
|
||||
clear(painter, background_color);
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
|
||||
void draw(GUI::Painter&) const;
|
||||
void clear(GUI::Painter&, const Color& background_color) const;
|
||||
void draw_complete(GUI::Painter&, const Color& background_color);
|
||||
void clear_and_draw(GUI::Painter&, const Color& background_color);
|
||||
|
||||
private:
|
||||
Card(Type type, uint8_t value);
|
||||
|
|
|
@ -29,22 +29,17 @@
|
|||
CardStack::CardStack()
|
||||
: m_position({ 0, 0 })
|
||||
, m_type(Invalid)
|
||||
, m_shift_x(0)
|
||||
, m_shift_y(0)
|
||||
, m_step(1)
|
||||
, m_base(m_position, { Card::width, Card::height })
|
||||
{
|
||||
}
|
||||
|
||||
CardStack::CardStack(const Gfx::IntPoint& position, Type type, uint8_t shift_x, uint8_t shift_y, uint8_t step)
|
||||
CardStack::CardStack(const Gfx::IntPoint& position, Type type)
|
||||
: m_position(position)
|
||||
, m_type(type)
|
||||
, m_shift_x(shift_x)
|
||||
, m_shift_y(shift_y)
|
||||
, m_step(step)
|
||||
, m_rules(rules_for_type(type))
|
||||
, m_base(m_position, { Card::width, Card::height })
|
||||
{
|
||||
ASSERT(step && type != Invalid);
|
||||
ASSERT(type != Invalid);
|
||||
calculate_bounding_box();
|
||||
}
|
||||
|
||||
|
@ -88,7 +83,7 @@ void CardStack::draw(GUI::Painter& painter, const Gfx::Color& background_color)
|
|||
if (is_empty())
|
||||
return;
|
||||
|
||||
if (m_shift_x == 0 && m_shift_y == 0) {
|
||||
if (m_rules.shift_x == 0 && m_rules.shift_y == 0) {
|
||||
auto& card = peek();
|
||||
card.draw(painter);
|
||||
return;
|
||||
|
@ -96,11 +91,12 @@ void CardStack::draw(GUI::Painter& painter, const Gfx::Color& background_color)
|
|||
|
||||
for (auto& card : m_stack) {
|
||||
if (!card.is_moving())
|
||||
card.draw_complete(painter, background_color);
|
||||
card.clear_and_draw(painter, background_color);
|
||||
}
|
||||
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
void CardStack::rebound_cards()
|
||||
{
|
||||
ASSERT(m_stack_positions.size() == m_stack.size());
|
||||
|
@ -183,15 +179,14 @@ bool CardStack::is_allowed_to_push(const Card& card) const
|
|||
|
||||
void CardStack::push(NonnullRefPtr<Card> card)
|
||||
{
|
||||
int size = m_stack.size();
|
||||
int ud_shift = (m_type == Normal) ? 3 : 1;
|
||||
auto size = m_stack.size();
|
||||
auto top_most_position = m_stack_positions.is_empty() ? m_position : m_stack_positions.last();
|
||||
|
||||
if (size && size % m_step == 0) {
|
||||
if (size && size % m_rules.step == 0) {
|
||||
if (peek().is_upside_down())
|
||||
top_most_position.move_by(m_shift_x, ((m_shift_y == 0) ? 0 : ud_shift));
|
||||
top_most_position.move_by(m_rules.shift_x, m_rules.shift_y_upside_down);
|
||||
else
|
||||
top_most_position.move_by(m_shift_x, m_shift_y);
|
||||
top_most_position.move_by(m_rules.shift_x, m_rules.shift_y);
|
||||
}
|
||||
|
||||
if (m_type == Stock)
|
||||
|
@ -225,16 +220,15 @@ void CardStack::calculate_bounding_box()
|
|||
|
||||
uint16_t width = 0;
|
||||
uint16_t height = 0;
|
||||
int card_position = 0;
|
||||
size_t card_position = 0;
|
||||
for (auto& card : m_stack) {
|
||||
if (card_position % m_step == 0 && card_position) {
|
||||
if (card.is_upside_down() && m_type != Stock) {
|
||||
int ud_shift = (m_type == Normal) ? 3 : 1;
|
||||
width += m_shift_x;
|
||||
height += (m_shift_y == 0) ? 0 : ud_shift;
|
||||
if (card_position % m_rules.step == 0 && card_position) {
|
||||
if (card.is_upside_down()) {
|
||||
width += m_rules.shift_x;
|
||||
height += m_rules.shift_y_upside_down;
|
||||
} else {
|
||||
width += m_shift_x;
|
||||
height += m_shift_y;
|
||||
width += m_rules.shift_x;
|
||||
height += m_rules.shift_y;
|
||||
}
|
||||
}
|
||||
++card_position;
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
};
|
||||
|
||||
CardStack();
|
||||
CardStack(const Gfx::IntPoint& position, Type type, uint8_t shift_x, uint8_t shift_y, uint8_t step = 1);
|
||||
CardStack(const Gfx::IntPoint& position, Type type);
|
||||
|
||||
bool is_dirty() const { return m_dirty; }
|
||||
bool is_empty() const { return m_stack.is_empty(); }
|
||||
|
@ -64,6 +64,28 @@ public:
|
|||
void clear();
|
||||
|
||||
private:
|
||||
struct StackRules {
|
||||
uint8_t shift_x { 0 };
|
||||
uint8_t shift_y { 0 };
|
||||
uint8_t step { 1 };
|
||||
uint8_t shift_y_upside_down { 0 };
|
||||
};
|
||||
|
||||
constexpr StackRules rules_for_type(Type stack_type)
|
||||
{
|
||||
switch (stack_type) {
|
||||
case Foundation:
|
||||
return { 2, 1, 4, 1 };
|
||||
case Normal:
|
||||
return { 0, 15, 1, 3 };
|
||||
case Stock:
|
||||
case Waste:
|
||||
return { 2, 1, 8, 1 };
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void calculate_bounding_box();
|
||||
|
||||
NonnullRefPtrVector<Card> m_stack;
|
||||
|
@ -71,9 +93,7 @@ private:
|
|||
Gfx::IntPoint m_position;
|
||||
Gfx::IntRect m_bounding_box;
|
||||
Type m_type { Invalid };
|
||||
uint8_t m_shift_x { 0 };
|
||||
uint8_t m_shift_y { 0 };
|
||||
uint8_t m_step {};
|
||||
StackRules m_rules;
|
||||
bool m_focused { false };
|
||||
bool m_dirty { false };
|
||||
Gfx::IntRect m_base;
|
||||
|
|
|
@ -37,19 +37,19 @@ SolitaireWidget::SolitaireWidget(GUI::Window& window, Function<void(uint32_t)>&&
|
|||
{
|
||||
set_fill_with_background_color(false);
|
||||
|
||||
m_stacks[Stock] = CardStack({ 10, 10 }, CardStack::Type::Stock, 2, 1, 8);
|
||||
m_stacks[Waste] = CardStack({ 10 + Card::width + 10, 10 }, CardStack::Type::Waste, 2, 1, 8);
|
||||
m_stacks[Foundation4] = CardStack({ SolitaireWidget::width - Card::width - 10, 10 }, CardStack::Type::Foundation, 2, 1, 4);
|
||||
m_stacks[Foundation3] = CardStack({ SolitaireWidget::width - 2 * Card::width - 20, 10 }, CardStack::Type::Foundation, 2, 1, 4);
|
||||
m_stacks[Foundation2] = CardStack({ SolitaireWidget::width - 3 * Card::width - 30, 10 }, CardStack::Type::Foundation, 2, 1, 4);
|
||||
m_stacks[Foundation1] = CardStack({ SolitaireWidget::width - 4 * Card::width - 40, 10 }, CardStack::Type::Foundation, 2, 1, 4);
|
||||
m_stacks[Pile1] = CardStack({ 10, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Pile2] = CardStack({ 10 + Card::width + 10, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Pile3] = CardStack({ 10 + 2 * Card::width + 20, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Pile4] = CardStack({ 10 + 3 * Card::width + 30, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Pile5] = CardStack({ 10 + 4 * Card::width + 40, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Pile6] = CardStack({ 10 + 5 * Card::width + 50, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Pile7] = CardStack({ 10 + 6 * Card::width + 60, 10 + Card::height + 10 }, CardStack::Type::Normal, 0, 15);
|
||||
m_stacks[Stock] = CardStack({ 10, 10 }, CardStack::Type::Stock);
|
||||
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[Foundation3] = CardStack({ SolitaireWidget::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[Foundation1] = CardStack({ SolitaireWidget::width - 4 * Card::width - 40, 10 }, CardStack::Type::Foundation);
|
||||
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[Pile3] = CardStack({ 10 + 2 * Card::width + 20, 10 + Card::height + 10 }, CardStack::Type::Normal);
|
||||
m_stacks[Pile4] = CardStack({ 10 + 3 * Card::width + 30, 10 + Card::height + 10 }, CardStack::Type::Normal);
|
||||
m_stacks[Pile5] = CardStack({ 10 + 4 * Card::width + 40, 10 + Card::height + 10 }, CardStack::Type::Normal);
|
||||
m_stacks[Pile6] = CardStack({ 10 + 5 * Card::width + 50, 10 + Card::height + 10 }, CardStack::Type::Normal);
|
||||
m_stacks[Pile7] = CardStack({ 10 + 6 * Card::width + 60, 10 + Card::height + 10 }, CardStack::Type::Normal);
|
||||
|
||||
m_timer = Core::Timer::construct(1000 / 60, [&]() { tick(window); });
|
||||
m_timer->stop();
|
||||
|
@ -66,7 +66,7 @@ static float rand_float()
|
|||
|
||||
static void make_pile(NonnullRefPtrVector<Card>& cards, CardStack& stack, uint8_t count)
|
||||
{
|
||||
for (int i = 1; i < count; ++i) {
|
||||
for (uint8_t i = 1; i < count; ++i) {
|
||||
auto card = cards.take_last();
|
||||
card->set_upside_down(true);
|
||||
stack.push(card);
|
||||
|
@ -81,10 +81,9 @@ void SolitaireWidget::tick(GUI::Window& window)
|
|||
return;
|
||||
|
||||
if (m_game_over_animation) {
|
||||
if (m_animation.card()->position().x() > SolitaireWidget::width
|
||||
|| m_animation.card()->rect().right() < 0) {
|
||||
ASSERT(!m_animation.card().is_null());
|
||||
if (m_animation.card()->position().x() > SolitaireWidget::width || m_animation.card()->rect().right() < 0)
|
||||
create_new_animation_card();
|
||||
}
|
||||
|
||||
m_animation.tick();
|
||||
}
|
||||
|
@ -141,7 +140,7 @@ void SolitaireWidget::setup()
|
|||
}
|
||||
|
||||
srand(time(nullptr));
|
||||
for (int i = 0; i < 200; ++i)
|
||||
for (uint8_t i = 0; i < 200; ++i)
|
||||
cards.append(cards.take(rand() % cards.size()));
|
||||
|
||||
make_pile(cards, stack(Pile1), 1);
|
||||
|
@ -415,7 +414,7 @@ void SolitaireWidget::paint_event(GUI::PaintEvent& event)
|
|||
focused_card.save_old_position();
|
||||
}
|
||||
}
|
||||
} else if (m_animation.card() != nullptr)
|
||||
} else if (!m_animation.card().is_null())
|
||||
m_animation.card()->draw(painter);
|
||||
|
||||
m_repaint_all = true;
|
||||
|
|
|
@ -56,15 +56,14 @@ private:
|
|||
{
|
||||
}
|
||||
|
||||
Card* card() { return m_animation_card; }
|
||||
RefPtr<Card> card() { return m_animation_card; }
|
||||
|
||||
void tick()
|
||||
{
|
||||
ASSERT(!m_animation_card.is_null());
|
||||
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 > SolitaireWidget::height + 1 && m_y_velocity > 0) {
|
||||
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().move_by(m_x_velocity, 0);
|
||||
|
@ -107,7 +106,7 @@ private:
|
|||
void check_for_game_over();
|
||||
void tick(GUI::Window&);
|
||||
|
||||
inline CardStack& stack(StackLocation location)
|
||||
ALWAYS_INLINE CardStack& stack(StackLocation location)
|
||||
{
|
||||
return m_stacks[location];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue