实体与组件
Pyxen 使用实体组件系统(ECS)。如果你使用过基于类继承的游戏引擎——其中 Player 继承自 Character 继承自 GameObject——这里不同。在 Pyxen 中,没有继承。一切都是组合。
实体
实体是一个游戏对象。它可以是玩家、墙壁、子弹、粒子——任何东西。在底层,实体只是一个 ID。它本身不持有数据。相反,你给它附加组件。
player = world.spawn(name="player", x=100, y=50)
这创建了一个位于 (100, 50) 的实体,并赋予名称。实体存在于世界中,如果它有精灵,就会被渲染。
组件
组件是附加到实体上的数据片段。Pyxen 有两种组件:
内置组件
这些由引擎提供:
| 组件 | 用途 |
|---|---|
| Transform | 位置 (x, y)、旋转、缩放 |
| Sprite | 视觉外观——图片、图块、锚点、颜色 |
| Camera | 带缩放的视口 |
| GridBody | 网格上的碰撞体 |
| GridMap | 带行、列和图块数据的图块地图 |
| Sound | 音效播放 |
| Music | 音乐流播放 |
| Name | 用于查找的字符串标识符 |
| Layer | 渲染图层 (0–255) |
| Parent / Children | 场景层级 |
你可以在生成时或通过实体属性设置内置组件:
e = world.spawn(
x=50, y=80,
sprite=Sprite("hero"),
name="player"
)
# later
e.x = 100
e.sprite = Sprite("hero", tile=(16, 0, 16, 16))
自定义组件
你可以给任何实体附加自己的组件。自定义组件是一个带有类型字段的字典:
player.health = {"value": 100, "max": 100}
player.speed = {"value": 2.5}
附加后,直接访问字段:
player.health.value -= 10
你也可以使用标记组件——没有数据、充当标签的组件:
player.alive = True
enemy.boss = True
这对查询很有用:你可以找到所有具有给定标记的实体。
字段类型
组件字段可以是:
| 类型 | 示例 | 备注 |
|---|---|---|
int | 42 | 32 位整数 |
float | 3.14 | 32 位浮点数 |
bool | True | 布尔值 |
str | "hello" | 最多 31 个字符 |
| Entity | player | 对另一个实体的引用 |
这些约束存在是因为组件存储在 C++ 引擎内部紧凑的、缓存友好的布局中。这是查询快速的原因。
查询实体
world 允许你通过组件查找实体:
# all entities with a "health" component
for e in world.all("health"):
if e.health.value <= 0:
world.destroy(e)
# combine: has "enemy", does not have "dead"
for e in world.all("enemy", without=("dead",)):
e.x += e.speed.value
你也可以按内置组件查询,如 "sprite"、"body"、"camera"、"sound"、"music" 和 "map":
# all entities with a sprite
for e in world.all("sprite"):
e.color = (1, 1, 1, 1)
# entities with both a sprite and the "enemy" custom component
for e in world.all("sprite", "enemy"):
e.color = (1, 0, 0, 1)
查询是你在 Pyxen 中编写游戏逻辑的主要方式。不是每个对象自行更新,而是编写遍历具有特定组件的实体的系统。
查看完整 API:world.all()、Entity
为什么选择 ECS?
如果你习惯了面向对象的游戏代码,ECS 一开始可能感觉不太习惯。它的好处:
- 无类层级 — 你不需要预先决定 PowerUp 是不是一种 Collectible 是不是一种 Entity。只需附加你需要的组件。
- 易于组合行为 — 一个实体可以同时拥有
health、enemy、flying和boss组件,无需多重继承。 - 快速查询 — 引擎将组件存储在连续内存中,因此遍历具有特定组件的所有实体非常高效。
- 易于调试 — 每个实体只是一堆数据。帧检查器会精确显示每个实体上附加了什么。