Rust游戏开发宏库macroquad_macro的使用,简化2D游戏渲染与跨平台开发
Rust游戏开发宏库macroquad_macro的使用,简化2D游戏渲染与跨平台开发
简介
macroquad_macro
是macroquad游戏引擎的内部宏库,用于简化2D游戏开发和跨平台部署。它提供了便捷的宏来定义游戏主循环和窗口配置。
安装
在项目目录中运行以下Cargo命令:
cargo add macroquad_macro
或者在Cargo.toml中添加:
macroquad_macro = "0.1.8"
基本用法
示例代码
// 使用macroquad_macro创建简单的2D游戏
use macroquad::prelude::*;
#[macroquad::main("MyGame")]
async fn main() {
loop {
clear_background(BLACK);
// 绘制一个简单的红色方块
draw_rectangle(screen_width() / 2.0 - 30.0,
screen_height() / 2.0 - 30.0,
60.0, 60.0,
RED);
next_frame().await;
}
}
完整示例
下面是一个完整的2D游戏示例,展示了如何使用macroquad_macro简化游戏开发:
use macroquad::prelude::*;
// 定义一个简单的游戏状态
struct GameState {
player_pos: Vec2,
player_speed: f32,
score: u32,
}
#[macroquad::main("Simple Game")]
async fn main() {
// 初始化游戏状态
let mut game = GameState {
player_pos: vec2(screen_width() / 2.0, screen_height() / 2.0),
player_speed: 5.0,
score: 0,
};
// 加载纹理
let texture: Texture2D = load_texture("assets/player.png").await.unwrap();
loop {
// 处理输入
if is_key_down(KeyCode::Right) {
game.player_pos.x += game.player_speed;
}
if is_key_down(KeyCode::Left) {
game.player_pos.x -= game.player_speed;
}
if is_key_down(KeyCode::Up) {
game.player_pos.y -= game.player_speed;
}
if is_key_down(KeyCode::Down) {
game.player_pos.y += game.player_speed;
}
// 边界检查
game.player_pos.x = game.player_pos.x.clamp(0.0, screen_width());
game.player_pos.y = game.player_pos.y.clamp(0.0, screen_height());
// 渲染
clear_background(BLACK);
// 绘制玩家
draw_texture(texture, game.player_pos.x, game.player_pos.y, WHITE);
// 绘制分数
draw_text(
&format!("Score: {}", game.score),
20.0,
20.0,
30.0,
WHITE,
);
// 每帧增加分数
game.score += 1;
next_frame().await;
}
}
特性
- 简化窗口创建:通过
#[macroquad::main]
宏自动处理窗口创建和事件循环 - 跨平台支持:支持Windows、macOS、Linux、WebAssembly和移动平台
- 异步支持:内置async/await支持,简化资源加载和游戏逻辑
- 2D渲染:提供简单的2D渲染API,包括精灵、形状和文本绘制
许可证
本项目采用MIT或Apache-2.0许可证。
1 回复
macroquad_macro: 简化Rust 2D游戏开发与跨平台渲染的宏库
介绍
macroquad_macro是macroquad游戏引擎的配套宏库,它提供了一系列过程宏来简化2D游戏开发流程,特别适合快速原型开发和跨平台项目。macroquad本身是一个轻量级的、即时模式的游戏框架,灵感来自Raylib,而macroquad_macro则通过宏进一步简化了常见模式。
主要特性
- 简化窗口和游戏循环配置
- 自动处理跨平台渲染
- 提供便捷的着色器和资源加载宏
- 减少样板代码
- 支持WebAssembly目标
基本使用方法
1. 添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
macroquad = "0.4"
macroquad_macro = "0.4"
2. 基本游戏结构
使用main!
宏简化入口点和游戏循环:
use macroquad::prelude::*;
use macroquad_macro::main;
#[main]
async fn main() {
loop {
clear_background(BLACK);
draw_text("Hello macroquad!", 20.0, 20.0, 30.0, WHITE);
next_frame().await;
}
}
3. 配置窗口
使用window!
宏配置窗口属性:
#[window]
struct WindowConfig {
title: String,
width: i32,
height: i32,
resizable: bool,
}
#[main]
async fn main() {
// 游戏代码...
}
4. 着色器宏
shader!
宏简化了着色器的加载:
use macroquad_macro::shader;
let shader = shader! {
vertex: "
#version 100
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
",
fragment: "
#version 100
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
",
}.unwrap();
5. 资源加载宏
resource!
宏简化了资源路径处理:
use macroquad_macro::resource;
let texture = load_texture(resource!("assets/player.png")).await.unwrap();
完整示例:简单2D游戏
use macroquad::prelude::*;
use macroquad_macro::{main, window, resource};
#[window]
struct WindowConfig {
title: String,
width: i32,
height: i32,
}
struct Player {
position: Vec2,
texture: Texture2D,
}
impl Player {
async fn new() -> Self {
Self {
position: vec2(100.0, 100.0),
texture: load_texture(resource!("assets/player.png")).await.unwrap(),
}
}
fn update(&mut self) {
if is_key_down(KeyCode::Right) {
self.position.x += 2.0;
}
if is_key_down(KeyCode::Left) {
self.position.x -= 2.0;
}
}
fn draw(&self) {
draw_texture(self.texture, self.position.x, self.position.y, WHITE);
}
}
#[main]
async fn main() {
let mut player = Player::new().await;
loop {
player.update();
clear_background(BLUE);
player.draw();
next_frame().await;
}
}
跨平台开发
macroquad_macro的一个主要优势是它简化了跨平台开发。相同的代码可以编译为:
- Windows/macOS/Linux原生应用
- WebAssembly (通过
cargo build --target wasm32-unknown-unknown
) - Android/iOS (需要额外配置)
高级用法
自定义渲染管道
use macroquad_macro::pipeline;
pipeline! {
name: "custom_pipeline",
params: {
time: f32,
},
vertex: "
#version 100
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
",
fragment: "
#version 100
uniform float time;
void main() {
gl_FragColor = vec4(sin(time), 0.0, 0.0, 1.0);
}
",
}
场景管理
虽然macroquad是即时模式的,但可以结合宏实现简单的场景管理:
use macroquad_macro::scene;
scene! {
enum GameScene {
Menu,
Game,
Pause,
}
}
#[main]
async fn main() {
let mut current_scene = GameScene::Menu;
loop {
match current_scene {
GameScene::Menu => {
if is_key_pressed(KeyCode::Enter) {
current_scene = GameScene::Game;
}
// 绘制菜单...
}
GameScene::Game => {
// 游戏逻辑...
if is_key_pressed(KeyCode::Escape) {
current_scene = GameScene::Pause;
}
}
GameScene::Pause => {
// 暂停逻辑...
}
}
next_frame().await;
}
}
完整示例Demo
下面是一个完整的2D游戏示例,包含场景管理、角色控制和简单的碰撞检测:
use macroquad::prelude::*;
use macroquad_macro::{main, window, resource, scene};
// 定义游戏场景
scene! {
enum GameScene {
MainMenu,
GamePlay,
GameOver,
}
}
// 窗口配置
#[window]
struct WindowConfig {
title: String,
width: i32,
height: i32,
fullscreen: bool,
}
// 玩家角色
struct Player {
rect: Rect,
speed: f32,
texture: Texture2D,
}
impl Player {
async fn new() -> Self {
Self {
rect: Rect::new(100.0, 100.0, 50.0, 50.0),
speed: 5.0,
texture: load_texture(resource!("assets/player.png")).await.unwrap(),
}
}
fn update(&mut self) {
// 键盘控制移动
if is_key_down(KeyCode::Right) {
self.rect.x += self.speed;
}
if is_key_down(KeyCode::Left) {
self.rect.x -= self.speed;
}
if is_key_down(KeyCode::Up) {
self.rect.y -= self.speed;
}
if is_key_down(KeyCode::Down) {
self.rect.y += self.speed;
}
// 简单的边界检查
self.rect.x = self.rect.x.clamp(0.0, screen_width() - self.rect.w);
self.rect.y = self.rect.y.clamp(0.0, screen_height() - self.rect.h);
}
fn draw(&self) {
draw_texture_ex(
self.texture,
self.rect.x,
self.rect.y,
WHITE,
DrawTextureParams {
dest_size: Some(vec2(self.rect.w, self.rect.h)),
..Default::default()
},
);
}
}
// 敌人角色
struct Enemy {
rect: Rect,
speed: f32,
texture: Texture2D,
}
impl Enemy {
async fn new(x: f32, y: f32) -> Self {
Self {
rect: Rect::new(x, y, 40.0, 40.0),
speed: 2.0,
texture: load_texture(resource!("assets/enemy.png")).await.unwrap(),
}
}
fn update(&mut self, player_rect: &Rect) {
// 简单AI:向玩家移动
if self.rect.x < player_rect.x {
self.rect.x += self.speed;
} else {
self.rect.x -= self.speed;
}
if self.rect.y < player_rect.y {
self.rect.y += self.speed;
} else {
self.rect.y -= self.speed;
}
}
fn draw(&self) {
draw_texture_ex(
self.texture,
self.rect.x,
self.rect.y,
WHITE,
DrawTextureParams {
dest_size: Some(vec2(self.rect.w, self.rect.h)),
..Default::default()
},
);
}
}
#[main]
async fn main() {
// 初始化游戏状态
let mut current_scene = GameScene::MainMenu;
let mut player = Player::new().await;
let mut enemies = vec![
Enemy::new(200.0, 200.0).await,
Enemy::new(400.0, 300.0).await,
Enemy::new(100.0, 400.0).await,
];
let mut score = 0;
let font = load_ttf_font(resource!("assets/font.ttf")).await.unwrap();
loop {
match current_scene {
GameScene::MainMenu => {
// 绘制主菜单
clear_background(BLACK);
draw_text_ex(
"RUST GAME DEMO",
screen_width() / 2. - 150.,
screen_height() / 2. - 50.,
TextParams {
font,
font_size: 48,
color: WHITE,
..Default::default()
},
);
draw_text_ex(
"按ENTER键开始游戏",
screen_width() / 2. - 120.,
screen_height() / 2. + 50.,
TextParams {
font,
font_size: 24,
color: WHITE,
..Default::default()
},
);
if is_key_pressed(KeyCode::Enter) {
current_scene = GameScene::GamePlay;
}
}
GameScene::GamePlay => {
// 更新游戏逻辑
player.update();
for enemy in &mut enemies {
enemy.update(&player.rect);
// 碰撞检测
if player.rect.overlaps(&enemy.rect) {
current_scene = GameScene::GameOver;
}
}
// 绘制游戏场景
clear_background(Color::from_rgba(30, 30, 40, 255));
player.draw();
for enemy in &enemies {
enemy.draw();
}
// 绘制分数
draw_text_ex(
&format!("分数: {}", score),
20.0,
40.0,
TextParams {
font,
font_size: 32,
color: WHITE,
..Default::default()
},
);
score += 1;
if is_key_pressed(KeyCode::Escape) {
current_scene = GameScene::MainMenu;
}
}
GameScene::GameOver => {
// 绘制游戏结束画面
clear_background(Color::from_rgba(40, 10, 10, 255));
draw_text_ex(
"游戏结束!",
screen_width() / 2. - 80.,
screen_height() / 2. - 50.,
TextParams {
font,
font_size: 48,
color: WHITE,
..Default::default()
},
);
draw_text_ex(
&format!("最终分数: {}", score),
screen_width() / 2. - 100.,
screen_height() / 2. + 20.,
TextParams {
font,
font_size: 32,
color: WHITE,
..Default::default()
},
);
draw_text_ex(
"按R键重新开始",
screen_width() / 2. - 100.,
screen_height() / 2. + 80.,
TextParams {
font,
font_size: 24,
color: WHITE,
..Default::default()
},
);
if is_key_pressed(KeyCode::R) {
// 重置游戏状态
player = Player::new().await;
enemies = vec![
Enemy::new(200.0, 200.0).await,
Enemy::new(400.0, 300.0).await,
Enemy::new(100.0, 400.0).await,
];
score = 0;
current_scene = GameScene::GamePlay;
}
if is_key_pressed(KeyCode::Escape) {
current_scene = GameScene::MainMenu;
}
}
}
next_frame().await;
}
}
总结
macroquad_macro通过提供一系列便利宏,显著简化了Rust中2D游戏开发的流程,特别是:
- 减少了初始化代码
- 统一了跨平台资源管理
- 简化了着色器使用
- 提供了更简洁的游戏循环结构
对于想要快速开发2D游戏原型或小型游戏的Rust开发者来说,macroquad_macro是一个值得考虑的选择。