Как написать «Пятнашки» на Flutter
Возможно, вы уже читали о конкурсе Flutter Puzzle Hack и думаете о том, как проявить максимум творческих способностей. И мы вам в этом поможем, рассказав о том, как структурирована кодовая база нашего примера головоломки. Подробностями делимся к старту авторского курса по веб-разработке на Python.
Архитектура
В представленном исходном коде многослойная архитектура для управления состоянием реализуется с помощью flutter_bloc. Блоки помогают управлять всем — от игровой логики до настройки тем.
Все состояния управляются согласованно: чтобы изменить логику головоломки, нужно только найти и обновить соответствующий блок. Кнопки сброса и перемешивания, таймера и обратного отсчёта — тоже отдельные блоки, которые можно расположить по вашей задумке: может быть, сделать песочные часы для таймера? Или шикарно стилизовать перемешивание?
Обратите внимание: вся игровая логика находится в одном блоке PuzzleBloc, который изменяется по таким событиям, как нажатие на один из 15 квадратиков и его перемещение с помощью события TileTapped, а также полный сброс головоломки по событию PuzzleReset. Состояние головоломки изменяется при каждом изменении в игре:
class PuzzleBloc extends Bloc<PuzzleEvent, PuzzleState> {
PuzzleBloc(this._size, {this.random}) : super(const PuzzleState() {
on<PuzzleInitialized>(_onPuzzleInitialized);
on<TileTapped>(_onTileTapped);
on<PuzzleReset>(_onPuzzleReset);
}
void _onPuzzleInitialized(
PuzzleInitialized event,
Emitter<PuzzleState> emit,
) {...}
void _onTileTapped(
TileTapped event,
Emitter<PuzzleState> emit,
) {...}
void _onPuzzleReset(
PuzzleReset event,
Emitter<PuzzleState> emit,
) {...}
}
Настройка темы
В примере кода головоломки есть две темы: Simple и Dashatar. Их можно взять за основу для собственных настроек или начать с нуля — реализация зависит от вас! Творческий подход можно проявить в настройке тем головоломки.
В демо всё происходит в верхней части PuzzlePage. Достаточно поменять элементы темы в одном месте, и изменения будут отражены везде. В обеих темах определяется ряд параметров: фон экрана, меню, логотип, кнопки, цвет текста, отображение таймера (есть в Dashatar, но нет в Simple) и другие. Они находятся в корня репозитория, в директориях dashatar и simple:
/// {@template simple_theme}
/// The simple puzzle theme.
/// {@endtemplate}
class SimpleTheme extends PuzzleTheme {
/// {@macro simple_theme}
const SimpleTheme() : super();
@override
Color get backgroundColor => PuzzleColors.white;
@override
Color get buttonColor => PuzzleColors.primary6;
@override
Color get hoverColor => PuzzleColors.primary3;
@override
Color get pressedColor => PuzzleColors.primary7;
...
}
В каждой теме есть LayoutDelegate, с его помощью вычисляется макет. Новые темы можно создавать, повторно используя одни и те же объекты макета. Останется настроить параметры.
Для дизайна сложнее можно настроить всю тему LayoutDelegate. Например, чтобы создать пользовательский фон, отображаемый только на большом экране, можно переопределить backgroundBuilder:
@override
Widget backgroundBuilder(PuzzleState state) {
return Positioned(
bottom: 74,
right: 50,
child: ResponsiveLayoutBuilder(
small: (_, child) => const SizedBox(),
medium: (_, child) => const SizedBox(),
large: (_, child) => const DashatarThemePicker(),
),
);
}
Анимация
Анимация — прекрасный элемент головоломки для изучения. В простой теме Simple нет анимации, зато несколько поэтапных анимаций реализуется в коде Dashatar. Эти анимации управляются одним контроллером, в котором есть Interval для настройки задержки анимации и Tween для определения диапазона значений анимации.
Это можно увидеть в собранной головоломке, в теме Dashatar, где последовательно отображаются несколько виджетов, анимируя смещение блока и непрозрачность. Похожим образом, используя ту же технику, с каждым тиком медленно растёт, а затем исчезает таймер обратного отсчёта, прежде чем появится следующий таймер:
Большинство анимаций в теме Dashatar неявные: нет необходимости писать всю анимацию самостоятельно — изменения свойств анимируются самими виджетами. Например, виджетом DashatarPuzzleTile анимируется перемещение квадратиков по нажатию на них. Благодаря неявно анимированному AnimatedAlign текущее положение квадрата меняется согласно заданному movementDuration:
class DashatarPuzzleTile extends StatelessWidget {
...
final Tile tile;
@override
Widget build(BuildContext context) {
return AnimatedAlign(
alignment: FractionalOffset(
(tile.currentPosition.x - 1) / (size - 1),
(tile.currentPosition.y - 1) / (size - 1),
),
duration: movementDuration,
curve: Curves.easeInOut,
child: ResponsiveLayoutBuilder(...),
);
}
}
Головоломка для веба
Пример головоломки создан для веба. Для малого, среднего и большого экранов реализован адаптивный дизайн. Кроме того, есть ResponsiveLayoutBuilder с обёрткой вокруг виджета LayoutBuilder на Flutter, позволяющей указывать разные виджеты на разных контрольных точках.
Нужно учесть и дополнительные обстоятельства в вебе. Чтобы оптимизировать производительность во время игры, изображения и аудио предварительно кешируются.
Когда пользователь попадает в игру-головоломку по умолчанию — Simple, файлы для версии Dashatar загружаются в фоновом режиме. Аналогичный подход мы использовали при загрузке всех свойств для I/O Photo Booth (фотобудки ввода-вывода). Так мы гарантируем, что при переходе к теме Dashatar большинство файлов уже загружены.
Можно проявить творческий подход и попробовать сделать головоломку на несколько платформ. Как она будет выглядеть на мобильных устройствах и настольных компьютерах? Как адаптировать идеи для разных платформ?
Доступность
При создании «Пятнашек» учитывалась доступность. Взаимодействие с головоломкой возможно с помощью клавиатуры, для этого есть виджет RawKeyboardListener, который использует обратный вызов, когда пользователь нажимает или отпускает клавишу на клавиатуре.
С приложением можно взаимодействовать через программы чтения с экрана. Это делается с помощью семантических меток. Для некоторых действий есть всплывающие подсказки: используется виджет Tooltip.
Если вы пишете «Пятнашки» с нуля, настоятельно рекомендуем сделать головоломку доступной для всех пользователей (применяйте стратегии, аналогичные описанным выше).
Другие идеи
За основу берите кодовую базу из демо, или воплощайте новую идею с нуля. Важно, чтобы в заявке была рабочая головоломка, но результат зависит только от вас!
Из примеров Simple и Dashatar можно позаимствовать идеи настроек или чего-то интересного, что можно сделать самостоятельно. Одна интересная идея — проецировать на квадратики головоломки созданную Феликсом Блашке Flutter Plasma.
Эффект плазмы достигается применением виджета CustomPaint, обёрнутого в виджет Transform и анимированного с помощью AnimationController. Вот пример отрисовки плазмы из демо:
Ещё одна идея — получать изображения или другие данные от API. Например, чтобы сделать «Пятнашки», можно использовать Google Photos API, взяв фотографии одного из альбомов Google Photos. В этом конкурсе нет предела совершенству!
Посмотрите пример кода головоломки здесь. Поделитесь с нами своими творениями в Twitter с помощью хештега #FlutterPuzzleHack. Ждём с нетерпением!
Лицензия кода — MIT, так что его легко использовать в ваших «Пятнашках». А продолжить погружение в IT и прокачать ваши навыки вы сможете на наших курсах:
Выбрать другую востребованную профессию.
Краткий каталог курсов и профессий
Data Science и Machine Learning
Python, веб-разработка
Мобильная разработка
Java и C#
От основ — в глубину
А также