mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-06 02:55:49 +03:00
2048: Animate sliding tiles
This commit is contained in:
parent
8a8c2572b1
commit
242742b6c2
Notes:
sideshowbarker
2024-07-18 12:23:28 +09:00
Author: https://github.com/dmitrii-ubskii Commit: https://github.com/SerenityOS/serenity/commit/242742b6c20 Pull-request: https://github.com/SerenityOS/serenity/pull/8000 Reviewed-by: https://github.com/alimpfard ✅
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,5 @@ private:
|
||||
static constexpr int animation_duration = 5;
|
||||
|
||||
int pop_in_animation_frame = 0;
|
||||
int slide_animation_frame = 0;
|
||||
};
|
||||
|
@ -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++)
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user