这是我参与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"
=version
⇒ 在开发过程中锁死 version。因为目前 rust crate 更新挺快的,说不定开发过程中就出现 api 不兼容的情况。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,
}
}
}
World
和 Resources
是用一个简单的构造函数创建的,称为 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;
use crate::prelude::*;
就可以不用到处引用 原生库 里面的一些函数变量了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::*;