- PVSM.RU - https://www.pvsm.ru -
В этой статье я расскажу о личном опыте разработки небольшой игры на Rust. На создание рабочей версии ушло около 24 часов (преимущественно я работала по вечерам или на выходных). Игра еще далека от завершения, но я думаю, что опыт будет полезным. Я расскажу, чему научилась, и о некоторых наблюдениях, сделанных при построении игры с нуля.
Skillbox рекомендует: Двухлетний практический курс «Я – веб-разработчик PRO» [1].
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».
Я выбрала этот язык, поскольку слышала о нем много хорошего и вижу, что он становится все более популярным в сфере разработки игр. До написания игры у меня был небольшой опыт разработки простых приложений на Rust. Этого было как раз достаточно, чтобы почувствовать определенную свободу во время написания игры.
Создание игр — это весело! Я бы хотела, чтобы причин было больше, но для «домашних» проектов я выбираю темы, которые не слишком тесно связаны с моей обычной работой. Что за игра? Мне хотелось сделать что-то вроде теннисного симулятора, где сочетаются Cities Skylines, Zoo Tycoon, Prison Architect и собственно теннис. В общем, получилась игра об академии тенниса, куда люди приходят для игры.
Мне хотелось использовать Rust, но я не знала точно, насколько «с нуля» понадобится начать работу. Я не хотела писать пиксельные шейдеры и использовать drag-n-drop, поэтому искала самые гибкие решения.
Нашла полезные ресурсы, которыми делюсь с вами:
Я изучила несколько игровых движков Rust, выбрав в конечном итоге Piston и ggez. С ними я сталкивалась при работе над предыдущим проектом. В итоге выбрала ggez, поскольку он показался более подходящим для реализации небольшой 2D-игры. Модульная структура Piston чересчур сложна для начинающего разработчика (или того, кто впервые работает с Rust).
Я потратила немного времени на размышления об архитектуре проекта. Первый шаг — сделать «землю», людей и теннисные корты. Люди должны перемещаться по кортам и ждать. У игроков должны быть навыки, совершенствующиеся с течением времени. Плюс ко всему должен быть редактор, который позволяет добавлять новых людей и корты, но это уже не бесплатно.
Продумав все, я приступила к работе.
Начало: окружности и абстракции
Я взяла пример из ggez и получила круг на экране. Удивительно! Теперь немного абстракций. Мне показалось, что неплохо абстрагироваться от идеи игрового объекта. Каждый объект должен быть отрендерен и обновлен, как указано здесь:
// the game object trait
trait GameObject {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()>;
fn draw(&mut self, ctx: &mut Context) -> GameResult<()>;
}
// a specific game object - Circle
struct Circle {
position: Point2,
}
impl Circle {
fn new(position: Point2) -> Circle {
Circle { position }
}
}
impl GameObject for Circle {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
let circle =
graphics::Mesh::new_circle(ctx, graphics::DrawMode::Fill, self.position, 100.0, 2.0)?;
graphics::draw(ctx, &circle, na::Point2::new(0.0, 0.0), 0.0)?;
Ok(())
}
}
Этот участок кода позволил мне получить отличный список объектов, которые я могу обновлять и рендерить в не менее отличном цикле.
mpl event::EventHandler for MainState {
fn update(&mut self, context: &mut Context) -> GameResult<()> {
// Update all objects
for object in self.objects.iter_mut() {
object.update(context)?;
}
Ok(())
}
fn draw(&mut self, context: &mut Context) -> GameResult<()> {
graphics::clear(context);
// Draw all objects
for object in self.objects.iter_mut() {
object.draw(context)?;
}
graphics::present(context);
Ok(())
}
}
main.rs необходим потому, что в нем — все строки кода. Я потратила немного времени, чтобы разделить файлы и оптимизировать структуру директорий. Вот как все стало выглядеть после этого:
resources -> this is where all the assets are (images)
src
— entities
— game_object.rs
— circle.rs
— main.rs -> main loop
Люди, этажи и изображения
Следующий этап — создание игрового объекта Person и загрузка изображений. Все должно строиться на основе плиток размером 32*32.
Теннисные корты
Изучив, как выглядят теннисные корты, я решила сделать их из плиток 4*2. Изначально можно было сделать изображение такого размера либо же составить вместе 8 отдельных плиток. Но потом я поняла, что необходимы лишь две уникальные плитки, и вот почему.
Всего у нас две таких плитки: 1 и 2.
Каждая секция корта состоит из плитки 1 или плитки 2. Они могут располагаться как обычно или быть перевернутыми на 180 градусов.
Основной режим строительства (сборки)
После того как получилось добиться рендеринга площадок, людей и карт, я поняла, что необходим еще и базовый режим сборки. Его реализовала так: когда нажата кнопка — объект выбран, а клик размещает его на нужном месте. Так, кнопка 1 дает возможность выбрать корт, а кнопка 2 позволяет выбрать игрока.
Но ведь нужно еще запомнить, что у нас означает 1 и 2, поэтому я добавила вайрфрейм для того, чтобы было понятно, какой объект выбран. Вот как это выглядит.
Вопросы по архитектуре и рефакторингу
Теперь у меня есть несколько игровых объектов: люди, корты и этажи. Но для того, чтобы работали вайрфреймы, нужно каждой сущности объекта сообщить, находятся ли сами объекты в режиме демонстрации, или же просто нарисована рамка. Это не очень удобно.
Мне показалось, что нужно переосмыслить архитектуру так, чтобы выявились некоторые ограничения:
Я провела дополнительное изучение и обнаружила архитектуру ECS — Entity Component System [5], которая обычно используется в играх. Вот преимущества ECS:
- данные отделены от логики;
- компоновка вместо наследования;
- архитектура, ориентированная на данные.
Для ECS характерны три базовых концепта:
После изучения стало ясно, что ECS решает такие проблемы:
Вот что получилось после внедрения ECS.
resources -> this is where all the assets are (images)
src
— components
— position.rs
— person.rs
— tennis_court.rs
— floor.rs
— wireframe.rs
— mouse_tracked.rs
— resources
— mouse.rs
— systems
— rendering.rs
— constants.rs
— utils.rs
— world_factory.rs -> world factory functions
— main.rs -> main loop
ECS сделала жизнь проще. Теперь у меня был системный путь добавления данных к сущностям и добавление логики, основанной на этих данных. А это, в свою очередь, позволило организовать распределение людей по кортам.
Что я сделала:
Мне очень понравилось работать над этой простой игрой. Более того, я довольна, что использовала для ее написания Rust, поскольку:
Разработка игр на Rust сейчас только начинается. Но уже есть стабильное и довольно большое комьюнити, работающее над тем, чтобы открыть Rust для всех. Поэтому я смотрю на будущее языка с оптимизмом, с нетерпением ожидая результатов нашей общей работы.
Skillbox рекомендует:
- Онлайн-курс «Профессия frontend-разработчик» [6].
- Практический курс «Мобильный разработчик PRO» [7].
- Практический годовой курс «PHP-разработчик с 0 до PRO» [8].
Автор: fokus-lop
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/312008
Ссылки в тексте:
[1] «Я – веб-разработчик PRO»: https://iamwebdev.skillbox.ru/?utm_source=skillbox.media&utm_medium=habr.com&utm_campaign=WEBDEVPRO&utm_content=articles&utm_term=rust24
[2] Are we game yet: http://arewegameyet.com/
[3] Rust game dev сабреддит;: https://www.reddit.com/r/rust_gamedev
[4] Бесплатный пиксель-арт.: https://kenney.nl
[5] ECS — Entity Component System: https://en.wikipedia.org/wiki/Entity_component_system
[6] «Профессия frontend-разработчик»: https://skillbox.ru/frontend-developer/?utm_source=skillbox.media&utm_medium=habr.com&utm_campaign=FRENDEV&utm_content=articles&utm_term=rust24
[7] «Мобильный разработчик PRO»: https://skillbox.ru/agima/?utm_source=skillbox.media&utm_medium=habr.com&utm_campaign=AGIMA&utm_content=articles&utm_term=rust24
[8] «PHP-разработчик с 0 до PRO»: https://skillbox.ru/php/?utm_source=skillbox.media&utm_medium=habr.com&utm_campaign=PHPDEV&utm_content=articles&utm_term=rust24
[9] Источник: https://habr.com/ru/post/444364/?utm_source=habrahabr&utm_medium=rss&utm_campaign=444364
Нажмите здесь для печати.