RUST SDL2 Develop
Rust Programming by Example . Chapter 2-3-4
相关代码 https://github.com/memorywalker/rtetris
SDL2开发环境
配置SDL
SDL2的官方https://www.libsdl.org/下载最新库文件 https://github.com/libsdl-org/SDL/releases/tag/release-2.30.0
SDL2的各个子项目地址 https://www.libsdl.org/projects/
对于windows下载SDL2-devel-2.30.0-VC.zip,下载github上文件时,可以加上http://ghproxy.com/前缀,使用代理更快下载文件。
https://ghproxy.com/https://github.com/libsdl-org/SDL/releases/download/release-2.30.0/SDL2-devel-2.30.0-VC.zip
SDL2库是由C语言实现的跨平台库,为了能在rust使用可以使用https://github.com/Rust-SDL2/rust-sdl2. 这个rust对SDL2封装,就能直接使用rust语言来开发。
安装Rust-SDL2
https://github.com/Rust-SDL2/rust-sdl2. 在页面有详细的不同平台安装流程,对于Window MSVC环境:
把下载的SDL2-devel-2.30.0-VC.zip中
SDL2-2.30.0\lib\x64\
的所有文件拷贝到rustup的库目录中.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\
使用
cargo new rtetris
创建一个工程名为rtetris
的应用程序工程工程的
Cargo.toml
文件中增加以下依赖代码1
2[dependencies]
sdl2 = "0.36"把
SDL2.dll
文件拷贝到rust开发工程的根目录(和Cargo.toml
相同目录)
语义化版本(semantic version)
Semantic Versioning的版本有三个部分[major].[minor].[patch]
major: 重大修改且有不兼容的API变化
minor:增加新的功能,但不会破坏版本兼容性
patch: 修改bug的小更改
SDL特性设置
要使用sdl2的特性扩展,需要修改toml文件,不再使用之前的依赖写法,而针对sdl2单独写使用哪些特性
1 | [dependencies.sdl2] |
简单窗口程序
以下代码是一个简单的窗口程序,可以用测试程序是否可以正常编译
1 | extern crate sdl2; |
执行cargo run
只会的程序如下
外部资源使用
图片资源
配置SDL的Image扩展库
SDL的图片插件地址为https://github.com/libsdl-org/SDL_image
把下载的SDL2_image-devel-2.8.2-VC.zip和SDL库一样配置。把其中的x64目录中的所有库文件放在rustup的库目录,把动态库文件也在工程目录中放一份。
图片加载代码
书中代码编译不过,参考https://github.com/Rust-SDL2/rust-sdl2/blob/master/examples/image-demo.rs例子调整引用和初始化
1 | use sdl2::image::{LoadTexture, InitFlag}; |
其中图片资源放在工程根目录的/res/images/
目录下
读写文件
新建一个score_file.rs文件用来存取分数和行数。迭代器的next()在collect()调用的时候才会被执行。
1 | use std::fs::File; |
在main.rs文件中
1 | mod score_file; |
使用字体
https://github.com/libsdl-org/SDL_ttf
同其他功能一样把SDL2_ttf.dll
拷贝到rustup的lib目录和当前工程目录。把下载的字体文件放在工程的/res/font/xxx.ttf
添加工程依赖
1 | [dependencies.sdl2] |
加载字体
1 | let ttf_context = sdl2::ttf::init().expect("SDL TTF initialization failed"); |
使用字体
1 | fn create_texture_from_text<'a>(texture_creator: &'a TextureCreator<WindowContext>, |
俄罗斯方块游戏
数据定义
方块结构
俄罗斯方块的每一个掉落块都有四个格子组成,一共有7种方块,分别用T I L J O S Z来表示。使用4*4的二维数组表示一个方块,因为最长的I有4个格子,所以宽和高至少为4。
1 | type Piece = Vec<Vec<u8>>; // 表示一种二维图形 |
每一个方块由于旋转,又可以有不同的状态。例如S有两种状态,分别为水平方向和垂直方向。
1 | struct TetriminoS; |
游戏主体结构
游戏主体可以看作一个16*10的网格,它有16行高,每一行有10个格子。下落的方块在这个网格中不停的移动。网格初始状态下全是0,当一行全部都不为0时,这一行就消除
1 | pub struct Tetris { |
方块的行为
方块可以旋转,移动,还要判断这个方块是否和网格中的边界冲突
1 | impl Tetrimino { |
游戏主体行为
游戏的主体对象创建一个16*10的网格,随机创建一个当前要下落的方块,每一次移动方块后,把当前下落的方块和网格合并,并可以消除填满的一行。
1 | impl Tetris { |
键盘事件处理
1 | pub fn handle_events(tetris: &mut Tetris, quit: &mut bool, timer: &mut SystemTime, |
定时下落处理
在程序的主循环中调用下落函数,其中判断当前的时间间隔是否超过了当前级别的时间阈值,如果超过,就开始让当前块的y增加1,如果不能移动当前块,就把当前合并块到网格
1 | pub fn falling(tetris: & mut Tetris, timer: &mut SystemTime) { |
程序主体循环
1 | loop { |
其他关键代码
在给网格或方块填充纹理时,根据格子中的数字来填充对应的纹理。因为有7种类型的方块,每一种方块有一种固定的颜色,所以创建7个不同颜色的方块纹理。这里代码使用了宏来简化代码。
1 | // 一个用来创建正方形纹理的函数 |