Sobre a Bevy
Bevy engine é uma das game engines mais promissoras do mercado e um grande esforço coletivo para a comunidade rust_gamedev. Se trata de uma engine orientada a dados, gratuíta e open source, sob as licenças Apache e MIT, ou seja, perfeita para qualquer projeto. Ela possui como objetivos de design:
- Um conjunto completo de features para jogos 2D e 3D, podendo inclusive ser aplicada para outros objetivos.
- Simples e poderosa, mas mantendo o fácil aprendizado.
- Orientada a dados utilizando o paradigma ECS (Entity component system, no próximo capítulo).
- Modular, use o que quiser, adicione o que quiser, e substitua o que quiser.
- Rápida, paralela e em Rust <3.
- Compilação rápida
A atual versão da Bevy é e este livro foi desenvolvido com a versão 0.7
, mas contém guias de migração para as versões 0.8
e 0.9
. A compatibilidade com Rust esta garantida para a versão 1.66
.
Iniciando o projeto
Para iniciar um projeto com a Bevy é necessário possuir Rust e Cargo, caso você não possua basta fazer download em https://rustup.rs/.
Vamos iniciar nosso projeto com um simples cargo new bevy-snake --bin
, que gera um projeto executável em Rust chamado bevy-snake
. Este projeto vai possuir um Cargo.toml
(onde os metadados do projeto estão localizados), um src/main.rs
e um .gitignore
:
// src/main.rs fn main() { println!("Hello, world!"); }
# .gitignore
/target
Agora adicionamos versão atual da bevy (bevy = "0.7"
) a seção [dependencies]
do Cargo.toml. Adicionamos também a crate de aleatoriedade rand
:
[dependencies]
bevy = "0.7"
rand = "0.7"
Com essas mudanças no Cargo.toml
podemos começar a usar o prelude
da bevy e criar nosso primeiro app com:
use bevy::prelude::*; fn main() { App::new().run(); }
Instanciando uma Janela
Instanciar uma janela com a Bevy é bastante trivial e pode ser feito através do uso de plugins, neste caso o DefaultPlugins
contém um conjunto básico de plugins que tornam a bevy operacional:
fn main() { App::new().add_plugins(DefaultPlugins).run(); }
Agora se executarmos cargo run
veremos uma janela com fundo cinza. Por padrão, os plugins da Bevy não incluem camera, pois o uso de camera é muito variado em jogos, assim, precisamos criar nosso próprio sistema de cameras. Usaremos uma camera ortográfica 2D com o commando OrthographicCameraBundle::new_2d()
em uma função que fará a configuração do sistema de cameras inicial alterando a variável do tipo mut Commands
. Commands
é um tipo muito comum ao escrever sistemas com a Bevy e é usado para enfileirar comandos com o objetivo de modificar o mundo (que chamaremos de world
) e os recursos (que chamaremos de resources
). Assim, na função a seguir, setup_camera
, receberemos como argumento mut commands: Commands
e utilizaremos ele para instanciar (chamado de spawn
) uma nova entidade bundle com os componentes de uma câmera 2D ortográfica:
#![allow(unused)] fn main() { fn setup_camera(mut commands: Commands) { commands.spawn_bundle(OrthographicCameraBundle::new_2d()); } }
E agora basta adicionar esse função ao nosso App
através de um add_startup_system
:
fn main() { App::new() .add_startup_system(setup_camera) .add_plugins(DefaultPlugins) .run(); } fn setup_camera(mut commands: Commands) { commands.spawn_bundle(OrthographicCameraBundle::new_2d()); }
Plugins
A Bevy é pensada de forma que todas suas partes sejam modularizáveis, assim, todas as core features da engine são implementadas como plugins que podem ser substituídos, evoluídos e customizados, além disso, os próprios jogos são encarados como plugins. Assim, se você não precisar de uma UI, basta não registrar o sistema de UI, quer um sistema de UI diferente, registre o seu próprio. Para o caso de servidores, basta não registrar o plugin RenderPlugin
.
Caso você não precise de uma experiência tão avançada com a Bevy, é possível utilizar o DefaultPlugins
que utilizamos anteriormente, que possui sistemas como Rendering, gerenciamento de assets, sistema de UI, janelas e gerenciamento de entrada de dados.
Criando um Plugin
Para criar um plugin simplesmente precisamos implementar a trait Plugin
em um tipo que comporte as informações necessárias. No caso do plugin que vamos implementar é apenas um hello world
para plugins, então não precisamos de dados, criando apenas um
#![allow(unused)] fn main() { pub struct HelloPlugin; impl Plugin for HelloPlugin { fn build(&self, app: &mut App) { // lógica do plugin } } }
Agora precisamos de uma função que nosso sistema vai executar, neste caso um simples println
:
#![allow(unused)] fn main() { fn hello_plugin() { println!("hello plugin!"); } }
E adicionamos essa função como um startup_system
no nosso plugin:
#![allow(unused)] fn main() { impl Plugin for HelloPlugin { fn build(&self, app: &mut App) { app.add_startup_system(hello_plugin); } } }
Por último, basta adicionarmos nosso plugin ao App
principal e executar cargo run
:
fn main() { App::new() .add_startup_system(setup_camera) .add_plugin(HelloPlugin) .add_plugins(DefaultPlugins) .run(); }
Veremos algo no terminal como:
2022-06-20T05:28:52.725036Z INFO bevy_render::renderer: AdapterInfo { name: "AMD Radeon Pro 5500M", vendor: 0, device: 0, device_type: DiscreteGpu, backend: Metal }
hello plugin!