组件和实体
在本节中,我们将创建组件,学习如何创建实体,并注册所有内容以确保 hecs
正常工作。
定义组件
我们先从定义组件开始。之前我们讨论了 Position
(位置组件)、Renderable
(可渲染组件)和 Movement
(动作组件),但暂时我们会跳过动作组件。我们还需要一些组件来标识每个实体。例如,我们需要一个 Wall
(墙)组件,通过它来标识一个实体是墙。
希望这很直观:位置组件存储 x、y 和 z 坐标,用于告诉我们某物在地图上的位置;可渲染组件会接收一个字符串路径,指向一张可以渲染的图片。所有其他组件都是marker
组件。marker
组件这个名字听起来可能有些吓人,但它本质上只是一个没有任何其他数据字段的标签。
创建实体
实体只是一个与一组组件相关联的数字标识符。因此,我们创建实体的方法是简单地指定它们包含哪些组件。
现在,创建实体的代码如下所示:
资源
您可能已经注意到,我们在上面的实体创建中引用了要使用的资源。您可以自由创建自己的资源,或者下载我们提供的资源(右键点击图片并选择“另存为”)。
让我们将这些图片添加到项目中。创建一个 resources
文件夹,用于存放所有资源。目前,这些资源仅包括图片,但将来我们可能会添加配置文件或音频文件(继续阅读,您将在 第三章第三节 学习如何播放声音)。在 resources
文件夹下再创建一个 images
文件夹,将我们的 PNG 图片放入其中。您也可以使用不同的文件夹结构,但在本节后续部分使用图片时,请确保路径正确。
项目的目录结构如下所示:
├── resources
│ └── images
│ ├── box.png
│ ├── box_spot.png
│ ├── floor.png
│ ├── player.png
│ └── wall.png
├── src
│ └── main.rs
└── Cargo.toml
创建游戏世界
最后,让我们将所有内容整合在一起。我们需要创建一个 specs::World
对象,将其添加到我们的 Game
结构中,并在主函数中首先初始化它。以下是完整代码,现在运行时仍会显示一个空白窗口,但我们在设置游戏组件和实体方面已经取得了巨大进展!接下来,我们将进入渲染部分,最终在屏幕上看到内容!
pub fn main() -> GameResult {
let world = World::new();
// Create a game context and event loop
let context_builder = ggez::ContextBuilder::new("rust_sokoban", "sokoban")
.window_setup(conf::WindowSetup::default().title("Rust Sokoban!"))
.window_mode(conf::WindowMode::default().dimensions(800.0, 600.0))
.add_resource_path(path::PathBuf::from("./resources"));
let (context, event_loop) = context_builder.build()?;
// Create the game state
let game = Game { world };
// Run the main event loop
event::run(context, event_loop, game)
}
注意:运行时,控制台可能会报告一些关于未使用导入或字段的警告,不用担心这些问题,我们将在后续章节中修复它们。
CODELINK: 您可以在 这里 查看本节完整代码。