diff options
author | Dmitrii Ubskii <ubskydm@gmail.com> | 2021-06-11 22:50:54 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-11 22:45:14 +0200 |
commit | 242742b6c208ae65a55ad714c2b7242636f056a0 (patch) | |
tree | d2870a14883f3346815b2256999e858f870b5fc8 | |
parent | 8a8c2572b1b456cdb2e55256fa3ddabe72a0085a (diff) | |
download | serenity-242742b6c208ae65a55ad714c2b7242636f056a0.zip |
2048: Animate sliding tiles
-rw-r--r-- | Userland/Games/2048/BoardView.cpp | 63 | ||||
-rw-r--r-- | Userland/Games/2048/BoardView.h | 1 | ||||
-rw-r--r-- | Userland/Games/2048/Game.cpp | 16 | ||||
-rw-r--r-- | Userland/Games/2048/Game.h | 12 |
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; } |