summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitrii Ubskii <ubskydm@gmail.com>2021-06-11 22:50:54 +0300
committerAndreas Kling <kling@serenityos.org>2021-06-11 22:45:14 +0200
commit242742b6c208ae65a55ad714c2b7242636f056a0 (patch)
treed2870a14883f3346815b2256999e858f870b5fc8
parent8a8c2572b1b456cdb2e55256fa3ddabe72a0085a (diff)
downloadserenity-242742b6c208ae65a55ad714c2b7242636f056a0.zip
2048: Animate sliding tiles
-rw-r--r--Userland/Games/2048/BoardView.cpp63
-rw-r--r--Userland/Games/2048/BoardView.h1
-rw-r--r--Userland/Games/2048/Game.cpp16
-rw-r--r--Userland/Games/2048/Game.h12
4 files changed, 77 insertions, 15 deletions
diff --git a/Userland/Games/2048/BoardView.cpp b/Userland/Games/2048/BoardView.cpp
index d79b70f03e..3608f0aa44 100644
--- a/Userland/Games/2048/BoardView.cpp
+++ b/Userland/Games/2048/BoardView.cpp
@@ -24,6 +24,7 @@ void BoardView::set_board(Game::Board const* board)
if (has_timer())
stop_timer();
+ slide_animation_frame = 0;
pop_in_animation_frame = 0;
start_timer(frame_duration_ms);
@@ -167,7 +168,10 @@ Gfx::Color BoardView::text_color_for_cell(u32 value)
void BoardView::timer_event(Core::TimerEvent&)
{
- if (pop_in_animation_frame < animation_duration) {
+ if (slide_animation_frame < animation_duration) {
+ slide_animation_frame++;
+ update();
+ } else if (pop_in_animation_frame < animation_duration) {
pop_in_animation_frame++;
update();
if (pop_in_animation_frame == animation_duration)
@@ -201,22 +205,51 @@ void BoardView::paint_event(GUI::PaintEvent& event)
field_rect.center_within(rect());
painter.fill_rect(field_rect, background_color);
- for (size_t column = 0; column < columns(); ++column) {
- for (size_t row = 0; row < rows(); ++row) {
- auto center = Gfx::IntPoint {
- field_rect.x() + m_padding + (m_cell_size + m_padding) * column + m_cell_size / 2,
- field_rect.y() + m_padding + (m_cell_size + m_padding) * row + m_cell_size / 2,
- };
- auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
- if (pop_in_animation_frame < animation_duration && Game::Board::Position { row, column } == m_board->last_added_position()) {
- float pop_in_size = m_min_cell_size + (m_cell_size - m_min_cell_size) * (pop_in_animation_frame / (float)animation_duration);
- tile_size = Gfx::IntSize { pop_in_size, pop_in_size };
+ auto tile_center = [&](size_t row, size_t column) {
+ return Gfx::IntPoint {
+ field_rect.x() + m_padding + (m_cell_size + m_padding) * column + m_cell_size / 2,
+ field_rect.y() + m_padding + (m_cell_size + m_padding) * row + m_cell_size / 2,
+ };
+ };
+
+ if (slide_animation_frame < animation_duration) {
+ // background
+ for (size_t column = 0; column < columns(); ++column) {
+ for (size_t row = 0; row < rows(); ++row) {
+ auto center = tile_center(row, column);
+ auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
+ auto rect = Gfx::IntRect::centered_on(center, tile_size);
+ painter.fill_rect(rect, background_color_for_cell(0));
}
+ }
+
+ for (auto& sliding_tile : m_board->sliding_tiles()) {
+ auto center_from = tile_center(sliding_tile.row_from, sliding_tile.column_from);
+ auto center_to = tile_center(sliding_tile.row_to, sliding_tile.column_to);
+ auto offset = Gfx::FloatPoint(center_to - center_from);
+ auto center = center_from + Gfx::IntPoint(offset * (slide_animation_frame / (float)animation_duration));
+
+ auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
auto rect = Gfx::IntRect::centered_on(center, tile_size);
- auto entry = tiles[row][column];
- painter.fill_rect(rect, background_color_for_cell(entry));
- if (entry > 0)
- painter.draw_text(rect, String::number(entry), font(), Gfx::TextAlignment::Center, text_color_for_cell(entry));
+
+ painter.fill_rect(rect, background_color_for_cell(sliding_tile.value_from));
+ painter.draw_text(rect, String::number(sliding_tile.value_from), font(), Gfx::TextAlignment::Center, text_color_for_cell(sliding_tile.value_from));
+ }
+ } else {
+ for (size_t column = 0; column < columns(); ++column) {
+ for (size_t row = 0; row < rows(); ++row) {
+ auto center = tile_center(row, column);
+ auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
+ if (pop_in_animation_frame < animation_duration && Game::Board::Position { row, column } == m_board->last_added_position()) {
+ float pop_in_size = m_min_cell_size + (m_cell_size - m_min_cell_size) * (pop_in_animation_frame / (float)animation_duration);
+ tile_size = Gfx::IntSize { pop_in_size, pop_in_size };
+ }
+ auto rect = Gfx::IntRect::centered_on(center, tile_size);
+ auto entry = tiles[row][column];
+ painter.fill_rect(rect, background_color_for_cell(entry));
+ if (entry > 0)
+ painter.draw_text(rect, String::number(entry), font(), Gfx::TextAlignment::Center, text_color_for_cell(entry));
+ }
}
}
}
diff --git a/Userland/Games/2048/BoardView.h b/Userland/Games/2048/BoardView.h
index 41d79a47df..9b97632f67 100644
--- a/Userland/Games/2048/BoardView.h
+++ b/Userland/Games/2048/BoardView.h
@@ -45,4 +45,5 @@ private:
static constexpr int animation_duration = 5;
int pop_in_animation_frame = 0;
+ int slide_animation_frame = 0;
};
diff --git a/Userland/Games/2048/Game.cpp b/Userland/Games/2048/Game.cpp
index 70da92d1e5..ce827d29ff 100644
--- a/Userland/Games/2048/Game.cpp
+++ b/Userland/Games/2048/Game.cpp
@@ -52,6 +52,10 @@ void Game::Board::transpose()
for (size_t j = 0; j < i; j++)
swap(m_tiles[i][j], m_tiles[j][i]);
}
+ for (auto& t : m_sliding_tiles) {
+ swap(t.row_from, t.column_from);
+ swap(t.row_to, t.column_to);
+ }
}
void Game::Board::reverse()
@@ -60,6 +64,12 @@ void Game::Board::reverse()
for (size_t i = 0; i < row.size() / 2; ++i)
swap(row[i], row[row.size() - i - 1]);
}
+
+ auto const row_size = m_tiles[0].size();
+ for (auto& t : m_sliding_tiles) {
+ t.column_from = row_size - t.column_from - 1;
+ t.column_to = row_size - t.column_to - 1;
+ }
}
size_t Game::Board::slide_row(size_t row_index)
@@ -85,12 +95,16 @@ size_t Game::Board::slide_row(size_t row_index)
while (first < row.size()) {
auto second = next_nonempty(first + 1);
if (second == row.size() || row[first] != row[second]) {
+ m_sliding_tiles.append({ row_index, first, row[first], row_index, current_index, row[first] });
+
row[current_index] = row[first];
current_index++;
first = second;
} else {
VERIFY(row[first] == row[second]);
+ m_sliding_tiles.append({ row_index, first, row[first], row_index, current_index, 2 * row[first] });
+ m_sliding_tiles.append({ row_index, second, row[second], row_index, current_index, 2 * row[first] });
row[current_index] = 2 * row[first];
current_index++;
@@ -107,6 +121,8 @@ size_t Game::Board::slide_row(size_t row_index)
size_t Game::Board::slide_left()
{
+ m_sliding_tiles.clear();
+
size_t successful_merge_score = 0;
for (size_t row_index = 0; row_index < m_tiles.size(); row_index++)
diff --git a/Userland/Games/2048/Game.h b/Userland/Games/2048/Game.h
index 459c7bd6e9..92f49ebcc7 100644
--- a/Userland/Games/2048/Game.h
+++ b/Userland/Games/2048/Game.h
@@ -67,6 +67,17 @@ public:
};
SlideResult slide_tiles(Direction);
+ struct SlidingTile {
+ size_t row_from;
+ size_t column_from;
+ u32 value_from;
+
+ size_t row_to;
+ size_t column_to;
+ u32 value_to;
+ };
+ Vector<SlidingTile> const& sliding_tiles() const { return m_sliding_tiles; }
+
private:
void reverse();
void transpose();
@@ -79,6 +90,7 @@ public:
Tiles m_tiles;
Position m_last_added_position { 0, 0 };
+ Vector<SlidingTile> m_sliding_tiles;
};
Board const& board() const { return m_board; }