Разработка мультижанровой игры (пока RPG составляющая) на Bevy, LDtk, и прочее, прочее…
Вступление
Hello, Habr! Эта статья не является ни путеводителем, ни тем более полным руководством, я лишь хочу описать свой опыт общения с движком и другим софтом, который использую впервые - можно сказать свой путь.
Буду рад советам в комментах, особенно по тем вопросам, которые я прямо задаю!
Также, буду ждать обратной связи на тему, а интересен ли такой контент вообще)
Почему стайка
При выборе игрового движка я руководствовался предпочтениями к языку — бывало писал на плюсах, и про шарп кое‑что знаю, но в сердце запал именно Rust).
К тому же, погружаться в огромные Unity и Unreal, пусть и с огромным количеством туториалов и документации — дело объемное, а про остальные движки ничего не скажу — остались ведь в основном ребята под скриптовые ЯП? (не моя любимая тема). Так вот, мой путь — это относительно небольшой модульный набор библиотек, которые можно осваивать с ранних этапов развития.
В пользу вышесказанного играет и моя неопытность в игровой разработке, желание «прохавать» её с низов — поиграть с графическими дровами, посмотреть, загрузить пару спрайтов по пикселям через байт‑буфер).
Итого - берём Bevy. Я начал с чего-то вроде 0.10, но мигрировал вплоть до 0.14.
Первые спрайты
Я не художник, не музыкант и не кто бы то ни было ещё, кроме кодера, но мне важно хотя бы поверхностно разобраться в большинстве аспектов разработки (и других вещей) прежде чем я смогу делегировать этот самый аспект (сейчас речь о рисовании) на случайные спрайты с просторов сети или другие ресурсы. Рисовал я в Aseprite и Pixel Studio.
И встречайте мои первые наброски, вот они - слева направо!
Осторожно, вырвиглаз




Думаю, для начала неплохо)
Emotions, Calm, Sabotage
Знаю, из моих разговоров о расте не сделаешь вывод о том, что я закоренелый ООП разработчик, но это так...
Название этой главы отражает не только примерное положение дел и связей в настоящем ECS, но и опыт знакомства с этим стилем - было долго, тяжело, местами сущность эмоций с определённым компонентом спокойствия попадала в систему саботирования.
Пока с трудом представляю себе, как под капотом реализована система архетипов, но уже в какой-то мере получается определять компоненты, создавать на их основе сущности, и даже воздействовать на них через системы.
Я провёл аналогию между trait'ами и Component, и структурами (вернее будет сказать их экземплярами) и Entity. А системы в этой идее воспринимаются как функции, принимающие экземпляр чего-то вроде impl Component. Это сильно упрощает на ранних этапах, хотя хочется мыслить не на уровне аналогий, а со сдвигом парадигмы)
Первый код
Ну, что тут скажешь, знакомство...
Система для перемещения игрока
Сорри за хардкод и unused:)
fn sprite_movement(time: Res<Time>,
mut sprite_position: Query<(&mut Transform)>,
movement_x: Res<Movement_X>,
movement_y: Res<Movement_Y>)
{
for mut transform in &mut sprite_position{
match movement_y.get() {
MovementY::Up => transform.translation.y += 5.,
MovementY::Down => transform.translation.y -= 5.,
_ => {}
}
match movement_x.get() {
MovementX::Left => transform.translation.x -= 5.,
MovementX::Right => transform.translation.x += 5.,
_ => {}
}
}
}
Что у нас тут, моё изобретение из одинаково названных перечислений и компонентов, их скрывающих. А нет, это ресурсы...
В пару к этой системе вероятно должна идти та, которая принимает пользовательский ввод:
fn keyboard_input_system(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut movement_x: ResMut<Movement_X>,
mut movement_y: ResMut<Movement_Y>)
{
match (keyboard_input.pressed(KeyCode::KeyS),keyboard_input.pressed(KeyCode::KeyW)) {
(true, false)=>movement_y.set(MovementY::Down),
(false, true)=>movement_y.set(MovementY::Up),
_ => movement_y.set(MovementY::No),
}
match (keyboard_input.pressed(KeyCode::KeyA),keyboard_input.pressed(KeyCode::KeyD)) {
(true, false)=>movement_x.set(MovementX::Left),
(false, true)=>movement_x.set(MovementX::Right),
_ => movement_x.set(MovementX::No),
}
}
Система спавна игрока
Заспавнить обычный спрайт - одна строка кода. Я хотел чтобы у игрока, да и у любого персонажа в игре была возможность модификаций, сменить шляпку или ещё что - так родилась эта система
fn setup_character(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>)
{
let texture = asset_server.load("goose/universal_man.png");
let num_of_sprites = 8;
let num_of_frames = 2;
let layout =
TextureAtlasLayout::from_grid(
Vec2::new(64.0,64.0),
num_of_frames,
num_of_sprites,
None,
None);
let texture_atlas_layout= texture_atlas_layouts.add(layout);
let transform = Transform{scale:Vec3::splat(3.0), translation: Vec3::new(100., 0., 0.),..default()};
let sprite_bundle = SpriteBundle{
texture,
transform,
..default()
};
for i in 0..num_of_sprites {
if i == 4 || i == 6 {
continue
}
let animation_indices = AnimationIndices { first: i* num_of_frames, last:(i+1)* num_of_frames -1 };
let k = (
sprite_bundle.clone(),
TextureAtlas {
layout: texture_atlas_layout.clone(),
index: animation_indices.first,
},
animation_indices,
AnimationTimer(Timer::from_seconds(0.3, TimerMode::Repeating)),
Direction::Up,
);
commands.spawn(k);
}
}
Сейчас обеих систем не существует. То есть есть, конечно, система перемещений, но она переработана донельзя, и естественно допускает перемещение не только самого Игрока с большой буквы.
Задача трёх тел
Я специально не сильно комментировал вторую и последнюю описанную выше систему — к ней есть претензии.
Работает она, мягко говоря, плохо — вечно что‑то не на том слое отображается.
Кто знает, как грамотно загружает спрайты под отдельные элементы экипировки и инкапсулировать всё это в сущности персонажа, да так ещё чтобы это были спрайты анимированные — дайте знать)
Планы
В следующей статье будет описан опыт работы с LDtk, есть у меня пара нерешённых проблем и там - может как раз получится разобраться.
Насчет непосредственно планов на развитие проекта в ближайшей перспективе:
Добавить NPC и механику диалога
Механика инвентаря
Пофиксить наконец слоёные спрайты и их анимацию
Механика боя
Квесты
Генерация мира
Поиграть с коллизиями (спойлер)
Переименовать козу в помидор или перерисовать помидор в козу (спойлер)
ИИ, который не просто ходит в случайном направлении (спойлер)
Логичный переход по локациям (спойлер)
Скрин к спойлеру?
