rust 编写游戏「从 Legion 开始」

979 阅读2分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

创建

完全不熟悉 rust 的同学不适合开始本篇文章的阅读。请立马离开,开始你的 rust 学习。然后再回来看本篇文章。

老规矩,开始创建 project:

> cargo new dungeon_ecs

> exa --tree
.
├── Cargo.toml
└── src
   └── main.rs

引入 legion crate

[dependencies]
bracket-lib = "=0.8.1"
legion = "=0.3.1"
  1. =version ⇒ 在开发过程中锁死 version。因为目前 rust crate 更新挺快的,说不定开发过程中就出现 api 不兼容的情况。
  2. bracket-lib ⇒ rust terminal GUI lib。使用它作为 game GUI

Prelude

mod prelude {
    pub use bracket_lib::prelude::*;
    pub use legion::*;
    pub use legion::world::SubWorld;
    pub use legion::systems::CommandBuffer;
    ...
}

prelude 这个预导入其实可以在很多库都看到使用。本质也是在 main.rs 里面减少一些模块的导入代码:将一些常用的模块在全局中可以共享。

Create World

Legion 将所有实体和组件存储在它称为 World 的结构中。游戏需要创建一个放置游戏实体的世界。

所以在 src/main.rs 中的 State 以包含一个 World、一个用于保存系统的 Schedule

struct State {
    ecs: World,
    resources: Resources,
    systems: Schedule,
}

初始化这个 State :

impl State {
    fn new() -> Self {
        let mut ecs = World::default();
        let mut resources = Resources::default();
        let mut rng = RandomNumberGenerator::new();
        // TODO resources <- Map
				 // map 需要注入到 resources
        State {
            ecs, resources,
        }
    }
}

WorldResources 是用一个简单的构造函数创建的,称为 Default。 其实就是一个空构造器,可以这么理解一下。

目前我们缺一个 Map,将这个注入到 resources ,变为公有资源


目前,ECS 是有了,我们现在需要开始第一个 component 的构建 → player,然后将起注入到 ECS 中。

Player Component

ECS 不是将与玩家相关的所有内容编码到单个模块中,而是根据玩家使用的组件来描述玩家。

  • Render ⇒ 描述玩家如何出现在屏幕上
  • Position ⇒ 指示实体在地图上的位置。 bracket-lib 中的 Point struct 非常适合于此;它包含一个 x 和一个 y 向量,它还提供了几个与点相关的数学函数。

OK,创建一个新的文件:src/components.rs

use crate::prelude::*;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Render {
    pub color: ColorPair,
    pub glyph: FontCharType,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Player;
  1. use crate::prelude::*; 就可以不用到处引用 原生库 里面的一些函数变量了
  2. Player 是一个不包含数据的空结构体,充当一个标记,指示具有该组件的实体是一个玩家。

然后你需要在 src/main.rs 中使用:

mod prelude {
    pub use bracket_lib::prelude::*;
    pub use legion::*;
    pub use legion::world::SubWorld;
    pub use legion::systems::CommandBuffer;
    pub use crate::components::*;
}
mod components;

use prelude::*;