用ggez游戏框架学Rust:游戏开发实战指南

📅 2026-05-29 📁 游戏编程 👁 36 次阅读

用ggez游戏框架学Rust:游戏开发实战指南(一)

用ggez游戏框架学Rust:游戏开发实战指南(二)

2. draw 方法:绘制画面

fn draw(&mut self, ctx: &mut Context) -> GameResult {
    let mut canvas = graphics::Canvas::from_frame(ctx, Color::new(0.1, 0.1, 0.2, 1.0));
  • 解释:创建一个画布,背景色是深蓝色(模拟太空)。
    // 绘制背景星星
    for star in &self.stars {
        let star_mesh = Mesh::new_circle(ctx, DrawMode::fill(), *star, 1.5, 0.1, Color::WHITE)?;
        canvas.draw(&star_mesh, graphics::DrawParam::default());
    }
  • 解释:画出白色的圆点作为背景。 *star:你需要用 * 解引用操作符来获取具体的坐标值传给 Mesh::new_circle
// ===== 绘制暂停提示 =====
        if self.paused {
            let paused_text = Text::new(TextFragment {
                text: "PAUSED".to_string(),
                color: Some(Color::YELLOW),
                font: Some("LiberationMono-Regular".into()),
                scale: Some(graphics::PxScale::from(50.0)),
                ..Default::default()
            });
            canvas.draw(
                &paused_text,
                Vec2::new(SCREEN_WIDTH / 2.0 - 100.0, SCREEN_HEIGHT / 2.0 - 30.0),
            );
        } 

if self.game_over {
        // ===== 游戏结束画面 =====
	let game_over_text = Text::new(TextFragment {
                text: "GAME OVER".to_string(),
                color: Some(Color::RED),
                font: Some("LiberationMono-Regular".into()),
                scale: Some(graphics::PxScale::from(60.0)),
                ..Default::default()
	});

	let restart_text = Text::new(TextFragment {
                text: "Press R to restart".to_string(),
                color: Some(Color::WHITE),
                font: Some("LiberationMono-Regular".into()),
                scale: Some(graphics::PxScale::from(30.0)),
                ..Default::default()
	});
	canvas.draw(
                &game_over_text,
Vec2::new(SCREEN_WIDTH / 2.0 - 180.0, SCREEN_HEIGHT / 2.0 - 80.0),
            );
	canvas.draw(
                &restart_text,
Vec2::new(SCREEN_WIDTH / 2.0 - 160.0, SCREEN_HEIGHT / 2.0 + 80.0),
            );
    } else {
// ===== 绘制玩家(多边形-绿色三角形)=====
            let player_mesh = Mesh::new_polygon(
                ctx,
                DrawMode::fill(),
                &[
Vec2::new(self.player.pos.x, self.player.pos.y - self.player.size), // 顶点
Vec2::new(self.player.pos.x - self.player.size / 2.0,
          self.player.pos.y + self.player.size / 2.0,
), // 左下
Vec2::new(self.player.pos.x + self.player.size / 2.0,
          self.player.pos.y + self.player.size / 2.0,
), // 右下
                ],
                Color::GREEN,
            )?;
canvas.draw(&player_mesh, graphics::DrawParam::default());


        // 绘制血条(红色矩形)
	for i in 0..self.player.hp {
                let hp_mesh = Mesh::new_rectangle(
                    ctx,
                    DrawMode::fill(),
                    Rect::new(10.0 + i as f32 * 25.0, 10.0, 20.0, 5.0),
                    Color::RED,
                )?;
                canvas.draw(&hp_mesh, graphics::DrawParam::default());
	}

        // ===== 绘制子弹(黄色小矩形)=====
 for bullet in &self.bullets {
   let bullet_mesh = Mesh::new_rectangle(
                    ctx,
                    DrawMode::fill(),
   Rect::new(bullet.pos.x - 3.0, bullet.pos.y - 8.0, 6.0, 16.0),
                    Color::YELLOW,
                )?;
                canvas.draw(&bullet_mesh, graphics::DrawParam::default());
  }
         
for enemy in &self.enemies {
    // ===== 绘制敌人(红色方块)=====
        // 敌人血条        
}      
        // 绘制分数等

    }
    canvas.finish(ctx)?; // 提交绘制指令
    timer::yield_now(); // 让出 CPU 时间片
    Ok(())
}//fn draw结束
}//impl EventHandler for MainState 结束
  • 解释:根据游戏状态绘制不同的 UI。正常游戏中绘制飞船、血条和分数;游戏结束时绘制大大的 GAME OVER 提示。
  • 代码中 ? 是 Rust 中一个非常强大和常用的错误传播操作符。 它的作用可以理解为:“如果前面的操作成功了,就拿到结果;如果失败了,就立刻把错误返回给调用者。”
  • 调用 yield_now() 可以告诉操作系统:“我这帧没事干了,你可以去调度其他程序,或者让我的 CPU 核心休息一下。” 这可以显著降低程序的功耗和发热。

第五部分:程序入口 (main)

fn main() -> GameResult {
    let cb = ContextBuilder::new("space_shooter", "微信公众号:会编码")
        .window_setup(ggez::conf::WindowSetup::default().title("Space Shooter - 微信公众号:会编码"))
        .window_mode(
            ggez::conf::WindowMode::default()
                .dimensions(SCREEN_WIDTH, SCREEN_HEIGHT)
                .resizable(false),
        );

    let (ctx, event_loop) = cb.build()?;
    let state = MainState::new()?;
    event::run(ctx, event_loop, state)
}
  • 解释:这是程序的起点。它创建了游戏窗口,设置了标题和大小,初始化了 MainState,最后启动了 ggez 的事件循环。游戏从此刻开始正式运行。

总结

这段代码虽然不长,但麻雀虽小五脏俱全。它展示了 ggez 框架最标准的项目结构:

  1. 定义数据 (Structs)
  2. 实现逻辑 (update - 处理输入和移动)
  3. 实现渲染 (draw - 绘制图形)
  4. 启动循环 (main)

这是一个非常完美的 2D 游戏开发入门范例,这种结构很清爽。