mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:07:35 +00:00
Solitaire: Play animation when starting a new game
This commit is contained in:
parent
ef458f7b66
commit
2ac734b7a8
2 changed files with 69 additions and 48 deletions
|
@ -31,6 +31,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
SolitaireWidget::SolitaireWidget(GUI::Window& window, Function<void(uint32_t)>&& on_score_update)
|
SolitaireWidget::SolitaireWidget(GUI::Window& window, Function<void(uint32_t)>&& on_score_update)
|
||||||
: m_on_score_update(move(on_score_update))
|
: m_on_score_update(move(on_score_update))
|
||||||
|
@ -64,17 +65,6 @@ static float rand_float()
|
||||||
return rand() / static_cast<float>(RAND_MAX);
|
return rand() / static_cast<float>(RAND_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void make_pile(NonnullRefPtrVector<Card>& cards, CardStack& stack, uint8_t count)
|
|
||||||
{
|
|
||||||
for (uint8_t i = 1; i < count; ++i) {
|
|
||||||
auto card = cards.take_last();
|
|
||||||
card->set_upside_down(true);
|
|
||||||
stack.push(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.push(cards.take_last());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SolitaireWidget::tick(GUI::Window& window)
|
void SolitaireWidget::tick(GUI::Window& window)
|
||||||
{
|
{
|
||||||
if (!is_visible() || !updates_enabled() || !window.is_visible_for_timer_purposes())
|
if (!is_visible() || !updates_enabled() || !window.is_visible_for_timer_purposes())
|
||||||
|
@ -88,7 +78,7 @@ void SolitaireWidget::tick(GUI::Window& window)
|
||||||
m_animation.tick();
|
m_animation.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_has_to_repaint || m_game_over_animation) {
|
if (m_has_to_repaint || m_game_over_animation || m_new_game_animation) {
|
||||||
m_repaint_all = false;
|
m_repaint_all = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -120,42 +110,35 @@ void SolitaireWidget::stop_game_over_animation()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_game_over_animation = false;
|
m_game_over_animation = false;
|
||||||
m_repaint_all = true;
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SolitaireWidget::setup()
|
void SolitaireWidget::setup()
|
||||||
{
|
{
|
||||||
stop_game_over_animation();
|
stop_game_over_animation();
|
||||||
|
m_timer->stop();
|
||||||
|
|
||||||
for (auto& stack : m_stacks)
|
for (auto& stack : m_stacks)
|
||||||
stack.clear();
|
stack.clear();
|
||||||
|
|
||||||
NonnullRefPtrVector<Card> cards;
|
m_new_deck.clear();
|
||||||
|
m_new_game_animation_pile = 0;
|
||||||
|
m_score = 0;
|
||||||
|
update_score(0);
|
||||||
|
|
||||||
for (int i = 0; i < Card::card_count; ++i) {
|
for (int i = 0; i < Card::card_count; ++i) {
|
||||||
cards.append(Card::construct(Card::Type::Clubs, i));
|
m_new_deck.append(Card::construct(Card::Type::Clubs, i));
|
||||||
cards.append(Card::construct(Card::Type::Spades, i));
|
m_new_deck.append(Card::construct(Card::Type::Spades, i));
|
||||||
cards.append(Card::construct(Card::Type::Hearts, i));
|
m_new_deck.append(Card::construct(Card::Type::Hearts, i));
|
||||||
cards.append(Card::construct(Card::Type::Diamonds, i));
|
m_new_deck.append(Card::construct(Card::Type::Diamonds, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
srand(time(nullptr));
|
srand(time(nullptr));
|
||||||
for (uint8_t i = 0; i < 200; ++i)
|
for (uint8_t i = 0; i < 200; ++i)
|
||||||
cards.append(cards.take(rand() % cards.size()));
|
m_new_deck.append(m_new_deck.take(rand() % m_new_deck.size()));
|
||||||
|
|
||||||
make_pile(cards, stack(Pile1), 1);
|
m_new_game_animation = true;
|
||||||
make_pile(cards, stack(Pile2), 2);
|
m_timer->start();
|
||||||
make_pile(cards, stack(Pile3), 3);
|
|
||||||
make_pile(cards, stack(Pile4), 4);
|
|
||||||
make_pile(cards, stack(Pile5), 5);
|
|
||||||
make_pile(cards, stack(Pile6), 6);
|
|
||||||
make_pile(cards, stack(Pile7), 7);
|
|
||||||
|
|
||||||
while (!cards.is_empty())
|
|
||||||
stack(Stock).push(cards.take_last());
|
|
||||||
|
|
||||||
m_score = 0;
|
|
||||||
update_score(0);
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +150,9 @@ void SolitaireWidget::update_score(int to_add)
|
||||||
|
|
||||||
void SolitaireWidget::keydown_event(GUI::KeyEvent& event)
|
void SolitaireWidget::keydown_event(GUI::KeyEvent& event)
|
||||||
{
|
{
|
||||||
|
if (m_new_game_animation || m_game_over_animation)
|
||||||
|
return;
|
||||||
|
|
||||||
if (event.key() == KeyCode::Key_F12)
|
if (event.key() == KeyCode::Key_F12)
|
||||||
start_game_over_animation();
|
start_game_over_animation();
|
||||||
}
|
}
|
||||||
|
@ -175,7 +161,7 @@ void SolitaireWidget::mousedown_event(GUI::MouseEvent& event)
|
||||||
{
|
{
|
||||||
GUI::Widget::mousedown_event(event);
|
GUI::Widget::mousedown_event(event);
|
||||||
|
|
||||||
if (m_game_over_animation)
|
if (m_new_game_animation || m_game_over_animation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto click_location = event.position();
|
auto click_location = event.position();
|
||||||
|
@ -228,7 +214,7 @@ void SolitaireWidget::mouseup_event(GUI::MouseEvent& event)
|
||||||
{
|
{
|
||||||
GUI::Widget::mouseup_event(event);
|
GUI::Widget::mouseup_event(event);
|
||||||
|
|
||||||
if (!m_focused_stack || m_focused_cards.is_empty() || m_game_over_animation)
|
if (!m_focused_stack || m_focused_cards.is_empty() || m_game_over_animation || m_new_game_animation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool rebound = true;
|
bool rebound = true;
|
||||||
|
@ -248,17 +234,13 @@ void SolitaireWidget::mouseup_event(GUI::MouseEvent& event)
|
||||||
m_focused_stack->set_dirty();
|
m_focused_stack->set_dirty();
|
||||||
stack.set_dirty();
|
stack.set_dirty();
|
||||||
|
|
||||||
if (m_focused_stack->type() == CardStack::Type::Waste
|
if (m_focused_stack->type() == CardStack::Type::Waste && stack.type() == CardStack::Type::Normal) {
|
||||||
&& stack.type() == CardStack::Type::Normal) {
|
|
||||||
update_score(5);
|
update_score(5);
|
||||||
} else if (m_focused_stack->type() == CardStack::Type::Waste
|
} else if (m_focused_stack->type() == CardStack::Type::Waste && stack.type() == CardStack::Type::Foundation) {
|
||||||
&& stack.type() == CardStack::Type::Foundation) {
|
|
||||||
update_score(10);
|
update_score(10);
|
||||||
} else if (m_focused_stack->type() == CardStack::Type::Normal
|
} else if (m_focused_stack->type() == CardStack::Type::Normal && stack.type() == CardStack::Type::Foundation) {
|
||||||
&& stack.type() == CardStack::Type::Foundation) {
|
|
||||||
update_score(10);
|
update_score(10);
|
||||||
} else if (m_focused_stack->type() == CardStack::Type::Foundation
|
} else if (m_focused_stack->type() == CardStack::Type::Foundation && stack.type() == CardStack::Type::Normal) {
|
||||||
&& stack.type() == CardStack::Type::Normal) {
|
|
||||||
update_score(-15);
|
update_score(-15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +267,7 @@ void SolitaireWidget::mousemove_event(GUI::MouseEvent& event)
|
||||||
{
|
{
|
||||||
GUI::Widget::mousemove_event(event);
|
GUI::Widget::mousemove_event(event);
|
||||||
|
|
||||||
if (!m_mouse_down || m_game_over_animation)
|
if (!m_mouse_down || m_game_over_animation || m_new_game_animation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto click_location = event.position();
|
auto click_location = event.position();
|
||||||
|
@ -311,6 +293,9 @@ void SolitaireWidget::doubleclick_event(GUI::MouseEvent& event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_new_game_animation)
|
||||||
|
return;
|
||||||
|
|
||||||
auto click_location = event.position();
|
auto click_location = event.position();
|
||||||
for (auto& to_check : m_stacks) {
|
for (auto& to_check : m_stacks) {
|
||||||
if (to_check.type() == CardStack::Type::Foundation || to_check.type() == CardStack::Type::Stock)
|
if (to_check.type() == CardStack::Type::Foundation || to_check.type() == CardStack::Type::Stock)
|
||||||
|
@ -397,7 +382,35 @@ void SolitaireWidget::paint_event(GUI::PaintEvent& event)
|
||||||
|
|
||||||
for (auto& stack : m_stacks)
|
for (auto& stack : m_stacks)
|
||||||
stack.draw(painter, s_background_color);
|
stack.draw(painter, s_background_color);
|
||||||
} else if (!m_game_over_animation) {
|
} else if (m_game_over_animation && !m_animation.card().is_null()) {
|
||||||
|
m_animation.card()->draw(painter);
|
||||||
|
} else if (m_new_game_animation) {
|
||||||
|
if (m_new_game_animation_delay < new_game_animation_delay) {
|
||||||
|
++m_new_game_animation_delay;
|
||||||
|
} else {
|
||||||
|
m_new_game_animation_delay = 0;
|
||||||
|
auto& current_pile = stack(piles.at(m_new_game_animation_pile));
|
||||||
|
|
||||||
|
if (current_pile.count() < m_new_game_animation_pile) {
|
||||||
|
auto card = m_new_deck.take_last();
|
||||||
|
card->set_upside_down(true);
|
||||||
|
current_pile.push(card);
|
||||||
|
} else {
|
||||||
|
current_pile.push(m_new_deck.take_last());
|
||||||
|
++m_new_game_animation_pile;
|
||||||
|
}
|
||||||
|
current_pile.set_dirty();
|
||||||
|
|
||||||
|
if (m_new_game_animation_pile == piles.size()) {
|
||||||
|
while (!m_new_deck.is_empty())
|
||||||
|
stack(Stock).push(m_new_deck.take_last());
|
||||||
|
stack(Stock).set_dirty();
|
||||||
|
m_new_game_animation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_game_over_animation && !m_repaint_all) {
|
||||||
if (!m_focused_cards.is_empty()) {
|
if (!m_focused_cards.is_empty()) {
|
||||||
for (auto& focused_card : m_focused_cards)
|
for (auto& focused_card : m_focused_cards)
|
||||||
focused_card.clear(painter, s_background_color);
|
focused_card.clear(painter, s_background_color);
|
||||||
|
@ -414,8 +427,7 @@ void SolitaireWidget::paint_event(GUI::PaintEvent& event)
|
||||||
focused_card.save_old_position();
|
focused_card.save_old_position();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!m_animation.card().is_null())
|
}
|
||||||
m_animation.card()->draw(painter);
|
|
||||||
|
|
||||||
m_repaint_all = true;
|
m_repaint_all = true;
|
||||||
if (!m_mouse_down) {
|
if (!m_mouse_down) {
|
||||||
|
|
|
@ -96,6 +96,7 @@ private:
|
||||||
Pile7,
|
Pile7,
|
||||||
__Count
|
__Count
|
||||||
};
|
};
|
||||||
|
static constexpr Array piles = { Pile1, Pile2, Pile3, Pile4, Pile5, Pile6, Pile7 };
|
||||||
|
|
||||||
void mark_intersecting_stacks_dirty(Card& intersecting_card);
|
void mark_intersecting_stacks_dirty(Card& intersecting_card);
|
||||||
void update_score(int to_add);
|
void update_score(int to_add);
|
||||||
|
@ -120,14 +121,22 @@ private:
|
||||||
|
|
||||||
RefPtr<Core::Timer> m_timer;
|
RefPtr<Core::Timer> m_timer;
|
||||||
NonnullRefPtrVector<Card> m_focused_cards;
|
NonnullRefPtrVector<Card> m_focused_cards;
|
||||||
Animation m_animation;
|
NonnullRefPtrVector<Card> m_new_deck;
|
||||||
CardStack* m_focused_stack { nullptr };
|
|
||||||
CardStack m_stacks[StackLocation::__Count];
|
CardStack m_stacks[StackLocation::__Count];
|
||||||
|
CardStack* m_focused_stack { nullptr };
|
||||||
Gfx::IntPoint m_mouse_down_location;
|
Gfx::IntPoint m_mouse_down_location;
|
||||||
|
|
||||||
bool m_mouse_down { false };
|
bool m_mouse_down { false };
|
||||||
bool m_repaint_all { true };
|
bool m_repaint_all { true };
|
||||||
bool m_has_to_repaint { true };
|
bool m_has_to_repaint { true };
|
||||||
|
|
||||||
|
Animation m_animation;
|
||||||
bool m_game_over_animation { false };
|
bool m_game_over_animation { false };
|
||||||
|
|
||||||
|
bool m_new_game_animation { false };
|
||||||
|
uint8_t m_new_game_animation_pile { 0 };
|
||||||
|
uint8_t m_new_game_animation_delay { 0 };
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue