Ну, вот и доделал ремейк игры Apple с БК-0010 на Rust.
Предыдущие части: Перечислимые структуры, Трусливый код и Event Loop, Первый результат, Лыко-мочало, Время жизни, Графическая прокладка, Дженерики, Композиция, Модули, Начальное проектирование, Итоги про память, Что там с памятью, Колхозим интерфейсы, Где у него классы, Поддержка SDL2, Полируем ржавчину
Смотреть можно здесь:
Правда, не совсем доделал. Нужна ещё музыка, но я не хочу просто проигрывать внешний WAV-файл, так как оригинальная игра этого не делает. Я попробую сделать генерацию звука программно, как положено. Но это на потом.
Текущая версия полностью функциональна.
Разберём, что и как в ней получилось.
Объём кода составил 48 килобайт. С одной стороны, для языка высокого уровня это немного, но с другой подобную игру можно уложить наверное в один килобайт (не считая графики). Что же помешало?
Как я и писал изначально, я делал не одну игру, а скорее архитектуру под неё и другие игры. Соответственно, архитектура получилась такая:
MVC
В игре есть 4 игровых экрана: заставка, меню выбора сложности, собственно игра, и экран окончания (победа или проигрыш). В каждом из этих экранов происходит своя активность: в заставке можно нажать любую клавишу, в меню выбирать сложность, в игре двигать человечка. Соответственно, за каждую активность отвечает свой контроллер.
Далее, у каждой активности есть своё представление: в заставке рисуется логотип, в меню меню, в игре игровой уровень и т.д. Соответственно, каждое представление представлено своим объектом.
Наконец, у каждой активности есть своя модель данных.
Игра эмулирует экран БК-0010, который имеет разрешение 256*256 пикселов. При этом реальный экран игры имеет разрешение 1024*768. А собственно логика игры (движения человека и яблока) происходит в сетке 32*32.
Контроллер ничего не знает о графике и работает только с сеткой и с габаритами объектов в единицах сетки. Поэтому, например, для контроллера игрок смещается не на 8 пикселов, а на 1 ячейку сетки. Представление работает с виртуальным БК-экраном 256*256 пикселов, переводя объекты из координат сетки в координаты виртуального экрана. И наконец компонент сцены (Stage) рисует объекты с помощью SDL2, перенося их в координаты реального экрана, при этом каждый пиксел становится размером 4*3 (у БК в цветном режиме пикселы не квадратные).
Абсолютно всё рисование делается цветными прямоугольниками, битмапов и блиттинга как таковых нет.
Управление
Контроллер опять же не знает о том, как физически устроено управление, клавиатура это или что-то другое. Вместо этого есть компонент Input, который может обрабатывать события от физической клавиатуры или от чего-то ещё, и генерировать уже собственные события стандартного вида, которые понятны контроллеру.
Например, на входе Input получает событие "нажата стрелка влево", а на выходе он отдаёт контроллеру уже собственное событие "активно движение влево", так что контроллер не должен думать, это была клавиатура или что-то ещё, у него есть готовый и понятный ему результат.
При этом у каждого контроллера может быть собственный компонент Input, который обрабатывает события специально для него.
Например, у контроллера, отвечающего за заставку, Input принимает нажатие любой клавиши, а порождает единственное событие GameStateEvent::Continue, то есть продолжить. Тот же самый Input работает в конце игры, где также ожидается нажатие любой клавиши. А вот во время игры подставляется другой Input, который различает нажатия стрелок и генерирует разные события.
Контроллеры после очередного цикла обновления также возвращают события, на основе которых главный игровой цикл принимает решение, что делать дальше – продолжать игру или менять контроллер, модель и представление на другие.
Ну, остальное уже обсуждалось в предыдущих частях.
Я рад, что наконец-то можно перейти к другим проектам. И особенно рад, что они будут не на Rust (Пирог заждался, например).