跳到主要内容

<pc-sprite>

<pc-sprite> 在实体处绘制角色、金币、地面或景物等二维图像。simple 显示资源单帧,animated 播放 <pc-sprite-clip> 子片段。

用法

精灵资源​

通过两类 <pc-asset> 构成,先声明图集:

  1. textureatlas:包含全部帧的图片,以及 data JSON 的 frames 对象。rect 为 [x, y, width, height] 像素坐标,从左下角测量。pivot 为放到实体位置的点,左下 [0, 0]、右上 [1, 1],[0.5, 0] 可使角色站稳。用于九宫格的帧还需 border,按左、下、右、上像素指定。
  2. 从图集取出的一个或多个 sprite。atlas 指图集,frame-keys 按序列出帧,pixels-per-unit 决定尺寸,例如高 24 像素、每单位 16 像素,对应 1.5 世界单位。render-mode 决定如何填充指定尺寸,详见平铺和切片。
<pc-app>
<!-- The atlas: one image, and where each frame lies in it -->
<pc-asset id="atlas" type="textureatlas" src="sprites.png"
srgb mipmaps="false" min-filter="nearest" mag-filter="nearest"
data='{ "frames": {
"coin-0": { "rect": [0, 0, 12, 12], "pivot": [0.5, 0.5] },
"coin-1": { "rect": [12, 0, 12, 12], "pivot": [0.5, 0.5] },
"coin-2": { "rect": [24, 0, 12, 12], "pivot": [0.5, 0.5] },
"platform": { "rect": [201, 46, 28, 16], "pivot": [0.5, 1], "border": [6, 0, 6, 0] }
} }'></pc-asset>
<!-- Sprites cut from it: a run of frames, at a scale -->
<pc-asset id="coin" type="sprite" atlas="atlas" frame-keys="coin-0 coin-1 coin-2" pixels-per-unit="16"></pc-asset>
<pc-asset id="platform" type="sprite" atlas="atlas" frame-keys="platform" pixels-per-unit="16" render-mode="tiled"></pc-asset>
<pc-scene>
<pc-entity name="coin" position="0 1 0">
<pc-sprite asset="coin"></pc-sprite>
</pc-entity>
</pc-scene>
</pc-app>

simple 通过 frame 选择资源的一帧,因此可用同一资源提供变体。精灵示例通过六帧 decor 绘制全部花、蘑菇和岩石;动画片段则顺序播放。

像素画​

像素画需要上例图集的四个选项:

  • min-filter 和 mag-filter 设 nearest,将像素采成硬边方块。默认线性会混合邻近像素,放大后模糊。
  • mipmaps=false 关闭预模糊缩小副本,避免缩小时变软,以及相邻图集帧颜色渗入边缘。
  • srgb 表明图片保存伽马编码颜色,与图像编辑器绘制的 PNG 一致,否则颜色偏淡。

每个图像像素覆盖整数个屏幕像素时才保持方正。正交摄像机应像示例脚本一样,在窗口变化时按画布高度计算 ortho-height。

属性​

属性类型默认值说明
asset资源 ID-sprite 资源,仅 simple 使用;animated 从片段取帧,留空不显示
clipString(字符串)-animated 活动片段名称,修改切换,重复设置可重播已结束动作,详见播放片段
colorColor(颜色)"1 1 1 1"与纹理相乘的染色,Alpha 忽略,透明用 opacity
enabledBoolean(布尔)"true"组件启用状态
flip-xBoolean(布尔)"false"水平镜像,例如改变角色朝向
flip-yBoolean(布尔)"false"垂直镜像
frameNumber(数字)"0"当前资源的帧索引。动画中设置会跳到该帧继续,但片段开始总从首帧,因此标记中的 frame 无效
heightNumber(数字)"1"世界单位高度,仅 sliced 或 tiled 使用
opacityNumber(数字)"1"不透明度,0 到 1
speedNumber(数字)"1"全部片段 fps 的倍率,0 冻结
typeEnum(枚举)"simple"simple 显示资源单帧,animated 播放子片段,由 clip 选择
widthNumber(数字)"1"世界单位宽度,仅 sliced 或 tiled 使用
精灵绘制方式

精灵不受光照、环境色、雾和色调映射影响,显示纹理乘 color 的颜色。作为 World 图层透明几何体,由远到近排序,不写深度。重叠精灵应有不同深度,例如示例沿 Z 从天空 -10 到史莱姆 1 分层。

播放片段​

animated 改为播放命名子片段,每个 <pc-sprite-clip> 指定名称、资源、帧率和循环,由 clip 选择:

<pc-sprite id="slime" type="animated" clip="idle">
<pc-sprite-clip name="idle" asset="slime-idle" fps="8" loop></pc-sprite-clip>
<pc-sprite-clip name="hop" asset="slime-hop" fps="12" loop></pc-sprite-clip>
<pc-sprite-clip name="land" asset="slime-land" fps="12"></pc-sprite-clip>
</pc-sprite>

clip 实时生效,可从标记、开发者工具或 JavaScript 修改。

  • 改变名称立即切换,从首帧开始,不支持交叉淡变。
  • 重复设置同名会重启已结束片段,适合落地等单次动作;仍在播放则不受影响。
  • 重新启用精灵从首帧播放当前片段。禁用组件或实体会停止,重新启用前可先设置 clip。
  • 名称无匹配时不操作且不警告,之后添加同名子片段会立即播放。空 clip 保留当前播放。

非循环片段停在末帧,并触发底层 end,可据此切换下一动作:

import { whenReady } from '@playcanvas/web-components';

const slime = await whenReady('#slime');

slime.clip = 'land'; // the property and the attribute are interchangeable

slime.component.on('end', (clip) => {
if (clip.name === 'land') {
slime.clip = 'idle';
}
});

平铺与九宫格精灵​

资源默认 simple 按帧尺寸绘制,width 和 height 无效。tiled 或 sliced 则按组件指定的世界单位宽高绘制,角落保留,边缘和中部拉伸或重复。

常见用途有两个:

  • 重复地砖。 没有 border 时整帧属于中间区,tiled 可将一块 16 像素草地重复为任意长度。
  • 任意尺寸面板或平台。 border 保持两端,例如示例平台左右各 6 像素,无论宽度如何,圆角不变,仅重复中间。
<!-- One tile of grass, repeated along 96 units of ground -->
<pc-sprite asset="grass" width="96" height="1"></pc-sprite>

<!-- The same platform sprite at two widths, its ends unchanged -->
<pc-sprite asset="platform" width="2.75"></pc-sprite>
<pc-sprite asset="platform" width="4.75"></pc-sprite>

宽高默认均为 1,除非该方向原本就是一个单位,应显式设置。例如每单位 16 像素、平台高 16 像素时只需设置宽。

示例​

平铺草地、九宫格平台、同一三帧资源的三朵花,以及动画史莱姆。按钮切换 clip 和 flip-x,可改平台宽、史莱姆颜色或 speed=0.5:

实时示例
<pc-app>
<!-- One atlas image holding every frame, read pixel for pixel -->
<pc-asset id="atlas" type="textureatlas" src="https://developer.playcanvas.com/assets/sprites.png" srgb mipmaps="false" min-filter="nearest" mag-filter="nearest" data='{ "frames": {
"slime-idle-0": { "rect": [150, 164, 24, 24], "pivot": [0.5, 0] },
"slime-idle-1": { "rect": [175, 164, 24, 24], "pivot": [0.5, 0] },
"slime-idle-2": { "rect": [200, 164, 24, 24], "pivot": [0.5, 0] },
"slime-idle-3": { "rect": [225, 164, 24, 24], "pivot": [0.5, 0] },
"slime-idle-4": { "rect": [150, 139, 24, 24], "pivot": [0.5, 0] },
"slime-idle-5": { "rect": [175, 139, 24, 24], "pivot": [0.5, 0] },
"slime-idle-6": { "rect": [200, 139, 24, 24], "pivot": [0.5, 0] },
"slime-idle-7": { "rect": [225, 139, 24, 24], "pivot": [0.5, 0] },
"slime-hop-0": { "rect": [150, 114, 24, 24], "pivot": [0.5, 0] },
"slime-hop-1": { "rect": [175, 114, 24, 24], "pivot": [0.5, 0] },
"slime-hop-2": { "rect": [200, 114, 24, 24], "pivot": [0.5, 0] },
"slime-hop-3": { "rect": [225, 114, 24, 24], "pivot": [0.5, 0] },
"slime-hop-4": { "rect": [150, 89, 24, 24], "pivot": [0.5, 0] },
"slime-hop-5": { "rect": [175, 89, 24, 24], "pivot": [0.5, 0] },
"grass": { "rect": [232, 46, 16, 16], "pivot": [0.5, 1] },
"platform": { "rect": [201, 46, 28, 16], "pivot": [0.5, 1], "border": [6, 0, 6, 0] },
"flower-red": { "rect": [245, 8, 7, 10], "pivot": [0.5, 0] },
"flower-yellow": { "rect": [13, 1, 7, 10], "pivot": [0.5, 0] },
"flower-blue": { "rect": [21, 1, 7, 10], "pivot": [0.5, 0] }
} }'></pc-asset>
<!-- Sprites cut from the atlas, at 16 pixels per world unit -->
<pc-asset id="slime-idle" type="sprite" atlas="atlas" frame-keys="slime-idle-0 slime-idle-1 slime-idle-2 slime-idle-3 slime-idle-4 slime-idle-5 slime-idle-6 slime-idle-7" pixels-per-unit="16"></pc-asset>
<pc-asset id="slime-hop" type="sprite" atlas="atlas" frame-keys="slime-hop-0 slime-hop-1 slime-hop-2 slime-hop-3 slime-hop-4 slime-hop-5" pixels-per-unit="16"></pc-asset>
<pc-asset id="grass" type="sprite" atlas="atlas" frame-keys="grass" pixels-per-unit="16" render-mode="tiled"></pc-asset>
<pc-asset id="platform" type="sprite" atlas="atlas" frame-keys="platform" pixels-per-unit="16" render-mode="tiled"></pc-asset>
<pc-asset id="flowers" type="sprite" atlas="atlas" frame-keys="flower-red flower-yellow flower-blue" pixels-per-unit="16"></pc-asset>
<pc-scene>
<pc-entity name="camera" position="0 1.5 10">
<pc-camera projection="orthographic" ortho-height="2.5" clear-color="#161a3c"></pc-camera>
</pc-entity>
<!-- Tiled: one tile repeated across the view -->
<pc-entity name="grass">
<pc-sprite asset="grass" width="12"></pc-sprite>
</pc-entity>
<!-- Tiled with borders: the ends keep their size, the middle repeats -->
<pc-entity name="platform" position="2.25 2.25 0">
<pc-sprite asset="platform" width="3.5"></pc-sprite>
</pc-entity>
<!-- Simple: one frame each of the same sprite -->
<pc-entity name="flower" position="-3.25 0 0.5">
<pc-sprite asset="flowers" frame="0"></pc-sprite>
</pc-entity>
<pc-entity name="flower" position="0.25 0 0.5">
<pc-sprite asset="flowers" frame="1"></pc-sprite>
</pc-entity>
<pc-entity name="flower" position="3 2.25 0.5">
<pc-sprite asset="flowers" frame="2"></pc-sprite>
</pc-entity>
<!-- Animated: plays the clip that clip names -->
<pc-entity name="slime" position="-1.5 0 1">
<pc-sprite id="slime" type="animated" clip="idle">
<pc-sprite-clip name="idle" asset="slime-idle" fps="8" loop></pc-sprite-clip>
<pc-sprite-clip name="hop" asset="slime-hop" fps="12" loop></pc-sprite-clip>
</pc-sprite>
</pc-entity>
</pc-scene>
</pc-app>
<div class="controls">
<button id="idle">Idle</button>
<button id="hop">Hop</button>
<button id="flip">Flip</button>
</div>
<style>
.controls {
position: absolute;
top: 12px;
left: 12px;
display: flex;
gap: 8px;
}
</style>
<script type="module">
const slime = document.getElementById('slime');

document.getElementById('idle').onclick = () => slime.setAttribute('clip', 'idle');
document.getElementById('hop').onclick = () => slime.setAttribute('clip', 'hop');
document.getElementById('flip').onclick = () => slime.toggleAttribute('flip-x');
</script>

完整精灵示例据此构建横向关卡,包含视差景物、可收集金币及跳跃史莱姆。

JavaScript 接口​

可以通过 SpriteComponentElement API创建和操作元素。

asset、clip、color、flipX、flipY、frame、height、opacity、speed、type 和 width 均有对应 property。

component 是底层 SpriteComponent,就绪前为 null,支持 pause、resume、stop、clip(name)、layers、drawOrder 和 batchGroupId。切换优先使用元素 clip,而非底层 play(name),因为重新启用时按 clip 播放,play 不更新它。

组件在各播放阶段触发事件,参数为对应 SpriteAnimationClip:

组件事件说明
play开始播放
pause暂停
resume恢复暂停
stop禁用或 stop() 导致停止,切换片段不触发
end非循环片段到达末帧
loop循环片段到末帧后重启

另请参阅​

示例:精灵。