使用Rust开发小游戏完成过程

 更新时间:2023年11月27日 14:39:36   作者:techdashen  
这篇文章主要介绍了使用Rust开发小游戏的完整过程,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

本文是对 使用 Rust 开发一个微型游戏【已完结】

cargo new flappy

在Cargo.toml的[dependencies]下方增加:

bracket-lib = "~0.8.7"

main.rs中:

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 {
    let context: BTerm = BTermBuilder::simple80x50()
        .with_title("爽哥做游戏--Flappy Dragon")
        .build()?;
    main_loop(context, State {})
}

cargo run后,可以看到

use bracket_lib::prelude::*;
// 游戏3种模式(菜单,游戏中,结束)
enum GameMode {
    Menu,
    Playing,
    End,
}
struct State {
    mode: GameMode,
}
impl State {
    fn new() -> Self {
        State {
            mode: GameMode::Menu,
        }
    }
    fn play(&mut self, ctx: &mut BTerm) {
        //TODO
        self.mode = GameMode::End;
    }
    fn restart(&mut self) {
        self.mode = GameMode::Playing;
    }
    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "欢迎来到游戏~");
        ctx.print_centered(8, "Press P key to start Game");
        ctx.print_centered(9, "Press Q to 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, "你挂了..");
        ctx.print_centered(8, "按P键 再来一局");
        ctx.print_centered(9, "按Q键 退出游戏");
        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
            {}
        }
    }
}
impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
        // ctx.cls();
        // ctx.print(1, 1, "Hello,Bracket Terminal!");
    }
}
fn main() -> BError {
    let context: BTerm = BTermBuilder::simple80x50()
        .with_title("爽哥做游戏--Flappy Dragon")
        .build()?;
    main_loop(context, State::new())
}

增加玩家

use bracket_lib::prelude::*;
// 游戏3种模式(菜单,游戏中,结束)
enum GameMode {
    Menu,
    Playing,
    End,
}
const SCREEN_WIDTH: i32 = 80;
const SCREEN_HEIGHT: i32 = 50;
const FRAME_DURATION: f32 = 75.0;
struct Player {
    x: i32,
    y: i32,
    velocity: f32,
}
impl Player {
    fn new(x: i32, y: i32) -> Self {
        Player {
            x: 0,
            y: 0,
            velocity: 0.0,
        }
    }
    fn render(&mut self, ctx: &mut BTerm) {
        ctx.set(0, self.y, YELLOW, BLACK, to_cp437('@'));
    }
    fn gravity_and_move(&mut self) {
        if self.velocity < 2.0 {
            self.velocity += 0.2;
        }
        self.y += self.velocity as i32;
        self.x += 1;
        if self.y < 0 {
            self.y = 0;
        }
    }
    fn flap(&mut self) {
        self.velocity = -2.0;
    }
}
struct State {
    player: Player,
    frame_time: f32,
    mode: GameMode,
}
impl State {
    fn new() -> Self {
        State {
            player: Player::new(5, 25),
            frame_time: 0.0,
            mode: GameMode::Menu,
        }
    }
    fn play(&mut self, ctx: &mut BTerm) {
        ctx.cls_bg(NAVY);
        self.frame_time += ctx.frame_time_ms;
        if self.frame_time >= FRAME_DURATION {
            self.player.gravity_and_move();
            self.frame_time = 0.0;
        }
        // 按空格
        if let Some(VirtualKeyCode::Space) = ctx.key {
            self.player.flap();
        }
        self.player.render(ctx);
        ctx.print(0, 0, "按空格起飞~");
        if self.player.y > SCREEN_HEIGHT {
            self.mode = GameMode::End;
        }
    }
    fn restart(&mut self) {
        self.player = Player::new(5, 25);
        self.frame_time = 0.0;
        self.mode = GameMode::Playing;
    }
    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "欢迎来到游戏~");
        ctx.print_centered(8, "Press P key to start Game");
        ctx.print_centered(9, "Press Q to 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, "你挂了..");
        ctx.print_centered(8, "按P键 再来一局");
        ctx.print_centered(9, "按Q键 退出游戏");
        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
            {}
        }
    }
}
impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
        // ctx.cls();
        // ctx.print(1, 1, "Hello,Bracket Terminal!");
    }
}
fn main() -> BError {
    let context: BTerm = BTermBuilder::simple80x50()
        .with_title("爽哥做游戏--Flappy Dragon")
        .build()?;
    main_loop(context, State::new())
}

增加障碍

use std::fmt::format;
use bracket_lib::prelude::*;
// 游戏3种模式(菜单,游戏中,结束)
enum GameMode {
    Menu,
    Playing,
    End,
}
const SCREEN_WIDTH: i32 = 80;
const SCREEN_HEIGHT: i32 = 50;
const FRAME_DURATION: f32 = 75.0;
struct Player {
    x: i32,
    y: i32,
    velocity: f32,
}
impl Player {
    fn new(x: i32, y: i32) -> Self {
        Player {
            x: 0,
            y: 0,
            velocity: 0.0,
        }
    }
    fn render(&mut self, ctx: &mut BTerm) {
        ctx.set(0, self.y, YELLOW, BLACK, to_cp437('@'));
    }
    fn gravity_and_move(&mut self) {
        if self.velocity < 2.0 {
            self.velocity += 0.2;
        }
        self.y += self.velocity as i32;
        self.x += 1;
        if self.y < 0 {
            self.y = 0;
        }
    }
    fn flap(&mut self) {
        self.velocity = -2.0;
    }
}
struct State {
    player: Player,
    frame_time: f32,
    mode: GameMode,
    obstacle: Obstacle,
    score: i32,
}
impl State {
    fn new() -> Self {
        State {
            player: Player::new(5, 25),
            frame_time: 0.0,
            mode: GameMode::Menu,
            obstacle: Obstacle::new(SCREEN_WIDTH, 0),
            score: 0,
        }
    }
    fn play(&mut self, ctx: &mut BTerm) {
        ctx.cls_bg(NAVY);
        self.frame_time += ctx.frame_time_ms;
        if self.frame_time >= FRAME_DURATION {
            self.player.gravity_and_move();
            self.frame_time = 0.0;
        }
        // 按空格
        if let Some(VirtualKeyCode::Space) = ctx.key {
            self.player.flap();
        }
        self.player.render(ctx);
        ctx.print(0, 0, "按空格起飞~");
        //  障碍物&积分
        // 实时打印分数
        ctx.print(0, 1, &format!("Score: {}", self.score));
        self.obstacle.render(ctx, self.player.x);
        if self.player.x > self.obstacle.x {
            self.score += 1; // 分数+1
            self.obstacle = Obstacle::new(self.player.x + SCREEN_WIDTH, self.score);
        }
        if self.player.y > SCREEN_HEIGHT || self.obstacle.hit_obstacle(&self.player) {
            self.mode = GameMode::End;
        }
    }
    fn restart(&mut self) {
        self.player = Player::new(5, 25);
        self.frame_time = 0.0;
        self.mode = GameMode::Playing;
        // 重置分数和障碍物
        self.obstacle = Obstacle::new(SCREEN_WIDTH, 0);
        self.score = 0;
    }
    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "欢迎来到游戏~");
        ctx.print_centered(8, "Press P key to start Game");
        ctx.print_centered(9, "Press Q to 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, "你挂了..");
        // 挂了后显示一下分数
        ctx.print_centered(6, &format!("本局获得了 {} 分", self.score));
        ctx.print_centered(8, "按P键 再来一局");
        ctx.print_centered(9, "按Q键 退出游戏");
        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
            {}
        }
    }
}
impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
    }
}
struct Obstacle {
    x: i32,
    gap_y: i32,
    size: i32,
}
impl Obstacle {
    fn new(x: i32, score: i32) -> Self {
        let mut random: RandomNumberGenerator = RandomNumberGenerator::new();
        Obstacle {
            x,
            gap_y: random.range(10, 40),
            size: i32::max(2, 20 - score),
        }
    }
    fn render(&mut self, ctx: &mut BTerm, player_x: i32) {
        let screen_x = self.x - player_x;
        let half_size = self.size / 2;
        for y in 0..self.gap_y - half_size {
            ctx.set(screen_x, y, RED, BLACK, to_cp437('|'));
        }
        for y in self.gap_y + half_size..SCREEN_HEIGHT {
            ctx.set(screen_x, y, RED, BLACK, to_cp437('|'));
        }
    }
    fn hit_obstacle(&self, player: &Player) -> bool {
        let half_size = self.size / 2;
        let does_x_match = player.x == self.x;
        let player_above_gap = player.y < self.gap_y - half_size;
        let player_below_gap = player.y > self.gap_y + half_size;
        does_x_match && (player_above_gap || player_below_gap)
    }
}
fn main() -> BError {
    let context: BTerm = BTermBuilder::simple80x50()
        .with_title("爽哥做游戏--Flappy Dragon")
        .build()?;
    main_loop(context, State::new())
}

参考资料[1]

使用 Rust 开发一个微型游戏【已完结】: https://www.bilibili.com/video/BV1vM411J74S

到此这篇关于使用Rust开发小游戏的文章就介绍到这了,更多相关Rust开发小游戏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Rust动态数组Vec基本概念及用法

    Rust动态数组Vec基本概念及用法

    Rust中的Vec是一种动态数组,它可以在运行时自动调整大小,本文主要介绍了Rust动态数组Vec基本概念及用法,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • Rust中的引用循环与内存泄漏详解

    Rust中的引用循环与内存泄漏详解

    这篇文章主要介绍了在Rust中如何使用Rc和RefCell来创建引用循环,以及引用循环可能导致的内存泄漏问题,文章还讨论了如何使用Weak类型来解决引用循环问题,特别是在需要双向引用的场景中,如树形结构,通过理解和掌握这些智能指针的使用,可以编写更高效且内存安全的Rust程序
    2025-02-02
  • Rust 模式匹配示例详解

    Rust 模式匹配示例详解

    这篇文章主要为大家介绍了Rust 模式匹配示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • Rust 连接 SQLite 数据库的过程解析

    Rust 连接 SQLite 数据库的过程解析

    本文通过一个例子给大家介绍了Rust 连接 SQLite 数据库的详细过程,我使用rusqlite这个crate,对Rust 连接 SQLite 数据库相关知识感兴趣的朋友跟随小编一起看看吧
    2022-01-01
  • Rust中字符串类型&str和String的使用

    Rust中字符串类型&str和String的使用

    在Rust中,字符串是一种非常重要的数据类型,&str和String是Rust中两种主要的字符串类型,本文主要介绍了Rust中字符串类型&str和String的使用,感兴趣的可以了解一下
    2024-03-03
  • Rust控制流运算符match的用法详解

    Rust控制流运算符match的用法详解

    match 是Rust中一个极为强大的控制流运算符,用于模式匹配和控制流的选择,它允许将一个值与一系列的模式相比较,根据匹配的模式执行相应代码,本文给大家详细介绍了Rust控制流运算符match的用法,需要的朋友可以参考下
    2024-01-01
  • Rust如何进行模块化开发技巧分享

    Rust如何进行模块化开发技巧分享

    Rust模块化,模块化有助于代码的管理和层次逻辑的清晰,本文主要介绍了Rust如何进行模块化开发,结合实例代码给大家讲解的非常详细,需要的朋友可以参考下
    2023-01-01
  • Rust语言中的String和HashMap使用示例详解

    Rust语言中的String和HashMap使用示例详解

    这篇文章主要介绍了Rust语言中的String和HashMap使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 深入探究在Rust中函数、方法和关联函数有什么区别

    深入探究在Rust中函数、方法和关联函数有什么区别

    在 Rust 中,函数、方法和关联函数都是用来封装行为的,它们之间的区别主要在于它们的定义和调用方式,本文将通过一个简单的rust代码示例来给大家讲讲Rust中函数、方法和关联函数区别,需要的朋友可以参考下
    2023-08-08
  • Rust指南之生命周期机制详解

    Rust指南之生命周期机制详解

    Rust 生命周期机制是与所有权机制同等重要的资源管理机制,之所以引入这个概念主要是应对复杂类型系统中资源管理的问题,这篇文章主要介绍了Rust指南之生命周期机制详解,需要的朋友可以参考下
    2022-10-10

最新评论