0Pricing
Learn Rust Coding · Aula

Colisões e estado do jogo

Adicione regras e condições de vitória.

Colisões e estado do jogo é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Learn Rust Coding, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Learn Rust Coding inclui 4 aulas no total.

Noções básicas de colisão AABB

O teste de colisão mais simples é a sobreposição de caixas delimitadoras alinhadas aos eixos (AABB). Dois retângulos colidem quando se sobrepõem nos eixos x e y.

Para sprites, isso é rápido e suficiente para muitos jogos 2D antes de recorrer a um mecanismo de física completo.

fn overlaps(a_pos: Vec2, a_size: Vec2, b_pos: Vec2, b_size: Vec2) -> bool {
    (a_pos.x - b_pos.x).abs() < (a_size.x + b_size.x) * 0.5
        && (a_pos.y - b_pos.y).abs() < (a_size.y + b_size.y) * 0.5
}

Um componente Collider

Anexe um componente Collider que contenha as semidimensões ou o tamanho total de cada entidade. Os sistemas então leem o transform e o collider para testar sobreposições.

Manter o tamanho em seu próprio componente permite que entidades diferentes compartilhem o mesmo sistema de colisão.

#[derive(Component)]
struct Collider {
    size: Vec2,
}

Detectando colisões em um sistema

Para comparar um jogador com muitos obstáculos, consulte o jogador uma vez e itere pelos obstáculos. Duas consultas separadas evitam pegar os mesmos dados duas vezes.

Quando houver sobreposição, reaja — cause dano, faça ricochetear ou remova a entidade — por meio de Commands ou alterando componentes.

fn detect(
    player: Query<(&Transform, &Collider), With<Player>>,
    walls: Query<(&Transform, &Collider), With<Wall>>,
) {
    let (pt, pc) = player.single().unwrap();
    for (wt, wc) in &walls {
        if overlaps(pt.translation.truncate(), pc.size, wt.translation.truncate(), wc.size) {
            info!("hit a wall");
        }
    }
}

Reagindo com eventos

Em vez de lidar com as consequências diretamente, envie um Event personalizado. Um sistema detecta colisões e emite eventos; outro os lê e aplica os efeitos.

Isso desacopla a detecção da reação e mantém cada sistema pequeno.

#[derive(Event)]
struct CollisionEvent { entity: Entity }

fn emit(mut writer: EventWriter<CollisionEvent>, e: Entity) {
    writer.send(CollisionEvent { entity: e });
}

Lendo eventos

Um sistema leitor obtém os eventos enfileirados com um EventReader e age sobre cada um. Os eventos permanecem por dois quadros, então qualquer leitor pode vê-los.

Esse fluxo de publicação e assinatura escala bem: muitos produtores e muitos consumidores sem acoplamento rígido.

fn on_hit(mut reader: EventReader<CollisionEvent>, mut commands: Commands) {
    for ev in reader.read() {
        commands.entity(ev.entity).despawn();
    }
}

Atualizando a pontuação

Quando o jogador coleta um item, altere o recurso global Score com ResMut.

Como os recursos são únicos, qualquer sistema pode ler ou atualizar a pontuação sem precisar passá-la manualmente.

fn collect(mut score: ResMut<Score>, mut reader: EventReader<PickupEvent>) {
    for _ in reader.read() {
        score.0 += 10;
    }
}

Estados: a visão geral

Os jogos alternam entre modos — menu, jogando, pausado e fim de jogo. O Bevy modela esses modos com um enum States registrado por meio de init_state.

Apenas um estado fica ativo por vez, e os sistemas podem ser condicionados para serem executados em estados específicos.

#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
enum GameState {
    #[default]
    Menu,
    Playing,
    GameOver,
}

Registrando um estado

Adicione o estado ao aplicativo com init_state. O Bevy passa a acompanhar o valor atual e disponibiliza os recursos State e NextState.

Leia o estado atual com Res<State<GameState>> quando um sistema precisar saber o modo.

App::new()
    .add_plugins(DefaultPlugins)
    .init_state::<GameState>()
    .run();

Executando sistemas em um estado

Restrinja os sistemas a um estado com a condição run_if in_state. O movimento e as colisões só são executados enquanto Playing estiver ativo.

É assim que a pausa funciona: interrompa os sistemas de jogabilidade saindo do estado Playing, e eles simplesmente não serão executados.

app.add_systems(
    Update,
    (drive, detect).run_if(in_state(GameState::Playing)),
);

Fazendo transições entre estados

Para alterar o estado, defina NextState em qualquer sistema. O Bevy aplica a transição no próximo limite de quadro.

Use os agendamentos OnEnter e OnExit para criar a interface ao entrar em um estado ou fazer a limpeza ao sair dele.

fn lose(mut next: ResMut<NextState<GameState>>, health: Res<Health>) {
    if health.0 == 0 {
        next.set(GameState::GameOver);
    }
}

Limpeza ao sair

Ao sair de Playing, remova as entidades do jogo para que a próxima rodada comece de forma organizada. Marque-as com um marcador e remova tudo que o tiver.

Registre a limpeza em OnExit(GameState::Playing) para que ela seja executada exatamente uma vez por transição.

fn cleanup(mut commands: Commands, q: Query<Entity, With<GameEntity>>) {
    for e in &q {
        commands.entity(e).despawn();
    }
}
// app.add_systems(OnExit(GameState::Playing), cleanup);

Verificação rápida

Considere como pausar o jogo de forma adequada.

Recapitulação: colisões e estado do jogo

Os testes de AABB junto com um componente Collider detectam sobreposições; os eventos dissociam a detecção da reação, e um recurso Score acompanha o progresso. O sistema States, com run_if, NextState e OnEnter/OnExit, estrutura os menus, o jogo e o fim de jogo.

Agora o ciclo está completo: criar, controlar, colidir e fazer a transição. Construa um jogo completo no Bevy com essas peças.

Perguntas Frequentes

A aula “Colisões e estado do jogo” é grátis?

Sim — o texto completo de “Colisões e estado do jogo” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Learn Rust Coding, atualize para CoddyKit PRO. O curso de Learn Rust Coding inclui 4 aulas no total.

O que vou aprender em “Colisões e estado do jogo”?

Adicione regras e condições de vitória. Você pratica Learn Rust Coding com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Learn Rust Coding?

Nenhuma experiência prévia é necessária. Learn Rust Coding no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Colisões e estado do jogo”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Learn Rust Coding?

Sim. Cada aula de Learn Rust Coding inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. A mentalidade ECS
  2. Criando e movendo entidades
  3. Lidando com entrada e tempo
  4. Colisões e estado do jogo
← Voltar para Learn Rust Coding