pyxen.Entity
Entity 是一个轻量级句柄——组件的容器。
有关实体组件系统的介绍,请参见实体与组件。
内置组件
| 组件 | 访问方式 |
|---|---|
| Transform | e.x, e.y, e.rotation, e.scale |
| Sprite | e.sprite, e.color |
| Animation | e.animation |
| Sound | e.sound |
| Music | e.music |
| GridBody | e.body |
| GridMap | e.map |
| Node | e.parent, e.children |
| Layer | e.layer |
| Name | e.name |
| Camera | e.camera |
Transform
e.x = 100
e.y = 50
e.rotation = 45
e.scale = (2, 2)
读取 scale 返回一个 Vector2:
s = e.scale
print(s.x, s.y)
Sprite
e.sprite = sprite
e.color = (1.0, 0.5, 0.5, 1.0)
读取 color 返回一个 Color:
c = e.color
print(c.r, c.g, c.b, c.a)
精灵动画
当使用 animation 参数创建精灵时,引擎会自动播放动画。你可以通过 e.animation 读取动画状态:
player.sprite = Sprite("hero", animation="walk")
属性
| 属性 | 类型 | 描述 |
|---|---|---|
name | str | 当前动画片段的名称 |
frame | int | 片段内的当前帧索引 |
playing | bool | 动画正在播放时为 True |
finished | bool | 一次性动画播放完成时为 True |
anim = player.animation
if anim:
print(anim.name) # "walk"
print(anim.frame) # 2
print(anim.playing) # True
print(anim.finished) # False
如果没有活动动画,e.animation 返回 None:
player.sprite = Sprite("hero", tile=(0, 0, 16, 16))
print(player.animation) # None
取消
将 e.animation 设为 None 以停止播放:
player.animation = None
赋值新的精灵会自动取消任何现有动画。
一次性动画
使用 loop=False 播放只执行一次的动画:
player.sprite = Sprite("hero", animation="attack", loop=False)
def update():
if player.animation and player.animation.finished:
player.sprite = Sprite("hero", animation="idle")
Tweens
Tweens 可以随时间平滑地动画化实体的属性。引擎自动处理插值——无需逐帧编写代码。
entity.tween()
# 指定属性名形式
entity.tween("x", to=200, duration=1.0)
entity.tween("alpha", to=0, duration=0.5, ease="out_quad")
# 关键字简写形式——同时动画多个属性
entity.tween(x=200, y=100, duration=1.0, ease="out_quad")
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
property | str | — | 属性名称(位置参数或关键字形式) |
to | float | — | 目标值 |
by | float | — | 相对偏移量(to 的替代) |
start | float | 当前值 | 起始值(默认为当前值) |
duration | float | 1.0 | 持续时间(秒) |
ease | str | "linear" | 缓动函数名称 |
使用 to 指定绝对目标值,或 by 指定相对偏移量:
entity.tween("x", to=200, duration=1.0) # 移动到 x=200
entity.tween("x", by=50, duration=0.5) # 向右移动 50 像素
使用 start 覆盖起始值:
entity.tween("x", to=200, start=0, duration=1.0) # 始终从 0 开始
可动画属性
| 组件 | 属性 |
|---|---|
| Transform | x, y, rotation, sx, sy |
| Sprite | r, g, b, alpha |
| Camera | zoom |
缓动函数
| 名称 | 曲线 |
|---|---|
linear | 匀速(默认) |
in_quad | 慢启动,加速 |
out_quad | 快启动,减速 |
in_out_quad | 慢启动和结束 |
in_cubic | 比 quad 更慢的启动 |
out_cubic | 比 quad 更快的启动 |
in_out_cubic | 平滑的慢启动和结束 |
in_expo | 非常慢的启动,爆发式加速 |
in_out_expo | 中段爆发 |
out_expo | 非常快的启动,柔和停止 |
in_back | 先后退再前进 |
out_back | 超越目标后回落 |
in_out_back | 后退和超越 |
in_elastic | 弹性蓄力 |
out_elastic | 弹性超越和弹跳 |
in_out_elastic | 两端弹性 |
entity.tweens.cancel()
取消实体的 tweens。传递属性名称可取消单个 tween,不传参数则取消所有 tweens。值冻结在当前位置。
entity.tweens.cancel("x") # 取消一个属性
entity.tweens.cancel() # 取消所有
冲突解决
在同一实体和属性上启动新的 tween 会替换之前的。不同属性的 tweens 独立运行。
entity.tween("x", to=100, duration=1.0)
entity.tween("x", to=200, duration=0.5) # 替换第一个 tween
entity.tween("y", to=50, duration=1.0) # 与 x 的 tween 并行运行
已销毁实体上的 tweens 会自动清理。
在属性上启动 animate() 会取消该属性上任何活动的 tween(),反之亦然。
动画
无限运行的连续动画 — 正弦波振荡(脉冲、呼吸、摆动)和恒速旋转。
entity.animate() — 振荡
使用正弦波围绕中心值振荡属性。
entity.animate("sx", "sy", by=0.15, speed=6.0) # coin pulse
entity.animate("alpha", by=0.3, center=0.7, speed=4.0) # flicker 0.4–1.0
值遵循:center + sin(elapsed * speed) * by
entity.animate() — 旋转
以恒定速率累积值。省略 by= 以使用旋转模式。
entity.animate("rotation", speed=180) # 180°/sec clockwise
参数
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
*props | str | — | 一个或多个属性名(位置参数) |
by | float | — | 振幅(振荡模式)。旋转时省略。 |
center | float | 当前值 | 振荡的中心值 |
speed | float | 1.0 | 角频率(振荡)或单位/秒(旋转) |
与 tweens 相同的 10 个属性:x, y, rotation, sx, sy, r, g, b, alpha, zoom。
entity.animations.cancel()
取消实体上的动画。传递属性名称可取消单个动画,不传参数则取消所有动画。
entity.animations.cancel("rotation") # 取消一个属性
entity.animations.cancel() # 取消所有
Parent / Children
child.parent = parent
访问子节点:
for c in parent.children:
print(c.name)
获取子节点数量:
parent.children.count
自定义组件
组件通过赋值创建:
- 字典——结构化组件
- 布尔值——标记组件
e.cell = {
'row': 0,
'col': 0
}
第一次赋值创建模式。字段类型会被推断,模式一旦确定就固定了——之后无法添加新字段。
在系统中使用组件
for cell in world.all("cell"):
...
标记组件
e.alive = True
标记不存储数据——它们仅表示存在。像普通组件一样查询:
for e in world.all("alive"):
...
访问组件字段
e.cell.row
e.cell.col
e.cell.row = 5
支持的字段类型
| Python 类型 | 存储为 |
|---|---|
int | 32 位整数 |
float | 32 位浮点数 |
bool | 布尔值 |
str | 固定字符串(最多 31 字符) |
Entity | 实体引用 |
无效类型会抛出:
TypeError: invalid value type in dict
模式规则
- 最大组件大小:256 字节
- 字符串最多:31 个字符
- 字典键必须是字符串
- 模式创建后无法添加新字段
e.cell = {'row': 0}
e.cell = {'row': 0, 'new_field': 5}
ValueError: cannot create new fields after schema is complete
后续赋值时可以省略字段——它们会默认为 0、0.0、False、"" 等。
检查组件
e.has("cell")
如果实体拥有该组件返回 True,否则返回 False。
这对自定义和内置组件名称都有效:
e.has("sprite") # True if the entity has a sprite
e.has("body") # True if the entity has a grid body
查询后代
entity.all(*components, without=(), include_self=False)
返回实体所有后代的迭代器(通过场景图层级进行深度优先遍历),匹配给定的组件过滤器。
工作方式与 world.all() 完全相同,但范围限定在子树而非整个世界。
# All descendants with "enemy" component
for e in parent.all("enemy"):
...
# With exclusion
for e in parent.all("enemy", without=("boss",)):
...
# Include the parent entity itself
for e in parent.all("tag", include_self=True):
...
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
*components | str | — | 要求的组件名称 |
without | tuple | () | 要排除的组件名称 |
include_self | bool | False | 是否包含实体本身 |
支持内置和自定义组件名称。
移除组件
使用 del 或赋值 None 来移除实体上的组件:
# 两种方式等效:
del entity.health
entity.health = None
移除后,entity.has("health") 返回 False,该实体不再匹配对该组件的查询。
e = world.spawn()
e.health = {'hp': 100}
del e.health
e.has("health") # False
# world.all("health") 不会包含 e
你可以在移除后重新添加组件:
del e.health
e.health = {'hp': 50} # 正常工作
内置组件
所有内置组件都可以移除:
del e.sprite # 清除精灵数据
del e.body # 清除物理碰撞体
del e.camera # 移除摄像机
del e.text # 移除文本
del e.sound # 移除音效
del e.music # 移除音乐
del e.map # 移除网格地图
Sprite 和 body 会被零初始化(实体仍保留存储空间,但数据为空)。Camera、text、sound、music 和 map 会被完全擦除。
标记
e.enemy = True
del e.enemy # 或:e.enemy = None
e.has("enemy") # False
实体生命周期
- 通过
world.spawn()创建 - 通过组件赋值修改
- 通过
del或= None移除组件 - 通过
world.destroy()销毁