案例来自于Rust Programming by Example
,由于按照书籍的操作会存在一些错误,所以用此博客来记录更多的细节。
实验环境
- MacOS M2:
13.5.2
- Rust:
1.70.0
初始化开发环境
- 创建工程
cargo new tetris
- 添加依赖于
Cargo.toml
[package]
name = "tetris"
version = "0.0.1"
[dependencies]
sdl2 = "0.34.5"
- 安装SDL2
brew install sdl2
- 配置环境变量
export RUSTFLAGS="-L /opt/homebrew/lib"
此处RUSTFLAGS
环境变量的内容需要根据自己的SDL2库的安装路径来配置,由于我的库安装路径是/opt/homebrew/lib
下。
执行cargo build
编译程序会依赖SDL的动态库;同时我也尝试了其他两种方法并没有成功
其它方法一:
设置环境变量DYLD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=/opt/homebrew/lib
其它方法二: 在Cargo.toml中添加
[build]
rustc-link-search = ["/opt/homebrew/lib"]
- 基础示例代码
extern crate sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use std::time::Duration;
fn main() {
// 初始化SDL2
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
// 创建窗口和画布
let window = video_subsystem
.window("SDL2 Window", 800, 600)
.position_centered()
.build()
.unwrap();
let mut canvas = window.into_canvas().build().expect("Failed to convert window into canvas");
// 渲染代码
canvas.set_draw_color(Color::RGB(255, 0, 0));
canvas.clear();
canvas.present();
// 创建事件处理器
let mut event_pump = sdl_context.event_pump().expect("Failed to get SDL event pump");
// 主循环
'runningloop: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'runningloop;
}
_ => {}
}
}
// 添加延迟以控制帧率
std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
}
}
- 构建程序
cargo build
- 运行程序
cargo run
运行结果如下图:
- 实现过程
-
导入外部crate SDL2
extern crate sdl2;
-
初始化
SDL context
let sdl_context = sdl2::init().expect("SDL initialization failed");
-
获取
video subsystem
let video_subsystem = sdl_context.video().expect("Couldn't get SDL
video subsystem"); -
创建
windows
let window = video_subsystem.window("Tetris", 800, 600)
.position_centered()
.opengl()
.build()
.expect("Failed to create window");- the parameters for the window method
title
width
height
.position_centered()
method- 在屏幕中间获取窗口
.opengl()
- 让
SDL
使用opengl
渲染
- 让
.build()
- 根据前面提供的参数创建窗口
.expect()
- 处理异常
- the parameters for the window method
-
事件循环 正常情况下,展示一个窗口并关闭特别快,我们需要添加时间循环确保窗口一直在运行。
- 导入必要相关的库
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use std::thread::sleep;
use std::time::Duration;- 获取时间循环管理器
let mut event_pump = sdl_context.event_pump().expect("Failed to
get SDL event pump");- 创建无限循环循环事件
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. } |
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running // We "break" the infinite loop.
},
_ => {}
}
}
sleep(Duration::new(0, 1_000_000_000u32 / 60));
}running
是一个循环跳出的标签(label
) 收到一个quit event
或者按Esc
键,程序退出
画布(Canvas)
- 当我们有了一个窗口(window)时,我们需要获取(get)窗口的画布(window's canvas)
let mut canvas = window.into_canvas()
.target_texture()
.present_vsync()
.build()
.expect("Couldn't get window's canvas");
以上代码的简单说明:
- into_canvas: 将窗口(window)转换为画布(canvas),以便我们可以轻松操作它
- target_texture: 激活纹理渲染支持
- present_vsync: 允许v-sync(竖直同步操作)限制
- build: 应用前面设置的参数创建画布(canvas)