Практическое обучение Rust (3) — основной игровой процесс

Rust
Практическое обучение Rust (3) — основной игровой процесс

В начале третьей главы мы вступаем в стадию реального игрового обучения.Знания, которые мы можем получить на протяжении всей третьей главы, в основном включают:

  1. game loop,
  2. basic program flow with a state machine,
  3. add a player,
  4. simulate gravity,
  5. and make the player's dragon flap its wings.
  6. Finally, add obstaches and scorekeeping to the game.

Это также основная игровая структура.

Game Loop

Что касается этого игрового цикла, мы обратимся к блок-схеме, предоставленной автором, а затем объединим наше собственное понимание.

Скриншоты взяты из текста, авторские права защищены

Основной ход игры выглядит следующим образом:

  1. Настройте приложение, окно и графику, это хорошее понимание, которое является начальным состоянием и интерфейсом игры.
  2. Опрос ОС для состояния ввода.Я понимаю, что в играх должен быть триггерный механизм для изменения состояния, такого как событие, действие и т. д .;
  3. Функция Call Tick. Насколько я понимаю, это похоже на игровой движок каждой игры, который помогает нам преобразовывать все события и действия в логику, которую понимает игра, и изменять состояние. В этой статье в основном используетсяbracket-libдвигатель.
  4. Экран обновления.При изменении статуса необходимо обновлять интерфейс в режиме реального времени.

Повторите цикл, и вы сможете запустить игру.

введено в текстbracket-libдвигатель. Давайте посмотрим, как это использовать.

Использование Bracket-Lib

Плагин импорта:

[dependencies]
bracket-lib="~0.8.1"

Описание номера версии подключаемого модуля см. во введении в Главе 1:

=0.8.1 может использовать только эту версию;

^ 0.8.1 можно использовать выше или равно этой версии, но она может быть ограничена только версией 0.x, например: 1.x нельзя использовать;

~0.8.1 может использовать любую версию выше или равную этой, даже если в какой-то будущей версии будут ошибки.

Конкретный код:

use bracket_lib::prelude::*;

struct State {}

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print(1, 1, "Hello, Bracket Terminal!");
    }
}

fn main() ->BError {
    println!("Hello, world!");

    let context = BTermBuilder::simple80x50()
        .with_title("Flappy Dragon")
        .build()?;
    
    main_loop(context, State{})
}

Сначала посмотрите на эффект бега:

Напечатать текст на экране терминала легко:Hello, Bracket Terminal!.

Creating Different Game Modes

Я думаю, что это больше похоже на описание состояния игры.В этой демо-версии игры требуются три режима:

  1. Menu: The player is waiting at the main menu.
  2. Playing: Game play is in progress.
  3. End: The game is over.

Очевидно, что эти режимы могут быть представлены перечислением:

enum GameMode {
    Menu,
    Playing,
    End,
}

Это требует, чтобы мы определилиStateплюс:

struct State {
    mode: GameMode,
}

// 并 new 时初始化
impl State {
    fn new() -> Self {
        State {
            mode: GameMode::Menu,
        }
    }
}

// main 函数同时修改
main_loop(context, State::new())

Следующим шагом с описанием состояния является выполнение различных действий в разных состояниях для достижения эффекта игры:

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        // ctx.cls();
        // ctx.print(1, 1, "Hello, Bracket Terminal!");
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
    }
}

в этотtickВ функции «в режиме реального времени» отслеживаются все изменения состояния и выполняются различные действия, такие как:Playingсостояние, выполнениеself.play(ctx)функция:

fn play(&mut self, ctx: &mut BTerm) {
    // TODO: Fill in this stub later
    ctx.cls();
    ctx.print_centered(5, "Playing Flappy Dragon");
    ctx.print_centered(8, "(E) Play End");
    ctx.print_centered(9, "(Q) Quit Game");

    if let Some(key) = ctx.key {
        match key {
            VirtualKeyCode::E => self.mode = GameMode::End,
            VirtualKeyCode::Q => ctx.quitting = true,
            _ => {}
        }
    }

    // 直接状态改变
    // self.mode = GameMode::End;
}

существуетplayВ функции по мониторингу разных клавиш определяется изменение состояния, что заставляет игру работать.

Эффект от исполнения следующий:

Полный код:

use bracket_lib::prelude::*;

enum GameMode {
    Menu,
    Playing,
    End,
}

struct State {
    mode: GameMode,
}

impl State {
    fn new() -> Self {
        State {
            mode: GameMode::Menu,
        }
    }

    fn restart(&mut self) {
        self.mode = GameMode::Playing;
    }

    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "Welcome to Flappy Dragon");
        ctx.print_centered(8, "(P) Play Game");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }
    }

    fn dead(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "You are dead!");
        ctx.print_centered(8, "(P) Play Again");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }
    }

    fn play(&mut self, ctx: &mut BTerm) {
        // TODO: Fill in this stub later
        ctx.cls();
        ctx.print_centered(5, "Playing Flappy Dragon");
        ctx.print_centered(8, "(E) Play End");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::E => self.mode = GameMode::End,
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }

        // 直接状态改变
        // self.mode = GameMode::End;
    }
}

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        // ctx.cls();
        // ctx.print(1, 1, "Hello, Bracket Terminal!");
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
    }
}

fn main() ->BError {
    println!("Hello, world!");

    let context = BTermBuilder::simple80x50()
        .with_title("Flappy Dragon")
        .build()?;
    
    main_loop(context, State::new())
}

Временно договоритесь о другой работе сегодня, следуйте процессу в книге, следуйте кодексу, передайтеbracket-libДвижок отслеживает изменения состояния в режиме реального времени и выполняет различные игровые действия.Хотя он просто использует виртуальные кнопки для реагирования на изменения состояния, чтобы имитировать ход игры, он в основном составляет логику игры.

Продолжите изучение Главы 3 завтра!