实体与组件

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

这对查询很有用:你可以找到所有具有给定标记的实体。

字段类型

组件字段可以是:

类型示例备注
int4232 位整数
float3.1432 位浮点数
boolTrue布尔值
str"hello"最多 31 个字符
Entityplayer对另一个实体的引用

这些约束存在是因为组件存储在 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 一开始可能感觉不太习惯。它的好处: