精灵动画实体
SpriteAnimatorEntity 是由 实体Entity 和 SpriteAnimatorModule 模块组合而成的新的实体。
SpriteAnimatorEntity = Entity + SpriteAnimatorModule
常用方法
SpriteAnimatorEntity 是由 实体Entity 派生而来。具体 Entity 的所有属性和方法。同时也具有SpriteAnimatorModule 的相关方法。通过 spriteAnimator 对象 可访问相关方法
| 方法 | 描述 |
|---|---|
| spriteAnimator | 获取精灵动画对象 |
| pauseAnimation | 暂停动画 |
| playAnimation | 运行动画 |
| setFrameName | 设置动画帧名称(切换动画)。⚠️ 仅对 JSON Hash 格式有效;资源加载完成前调用是空操作 |
支持格式
动画格式支持动画图像集(将所有动画图像放至一张图片上) 和 精灵图(Sprite Sheet)格式(它描述了一个包含多帧图像的动画序列,每帧图像在一个较大的图像中的位置和大小。这种格式广泛用于2D游戏开发和其他图形应用中)。
各格式的必填项:
- 动画图像集(只给
textureImageURL):必须传numberOfFrames,且所有帧须横向排成一行、图片宽度能被帧数整除,否则帧列表为空、不播放。- JSON Array(
frames是数组,如 TexturePacker 的 "JSON (Array)"):按数组顺序整体播放,无需animationNames,frameName/setFrameName无作用。- JSON Hash(
frames是以帧名为 key 的对象):必须传animationNames(按"帧名包含该字符串"分组成多段动画),并用frameName指定初始播放哪一段;缺animationNames时加载阶段抛错、实体始终不显示。
精灵图(Sprite Sheet)格式创建工具 texturepacker
使用示例
创建SpriteAnimatorEntity
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true, } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let spriteAnimatorEnt = new vjmap3d.SpriteAnimatorEntity({
startFrame: 0,
autoPlay: true,
loop: true,
numberOfFrames: 16,
textureImageURL: env.assetsPath + "sprites/alien.png",
asSprite: true
})
spriteAnimatorEnt.position.set(-2, 0, 2);
spriteAnimatorEnt.addTo(app);
加载精灵图(Sprite Sheet)格式动画
let spriteAnimatorEnt = new vjmap3d.SpriteAnimatorEntity({
startFrame: 0,
fps: 40,
autoPlay: true,
loop: true,
textureImageURL: env.assetsPath + "sprites/flame.png",
textureDataURL: env.assetsPath + "sprites/flame.json",
asSprite: true
})
spriteAnimatorEnt.position.set(2, 0, 2);
spriteAnimatorEnt.addTo(app);
动画控制
pauseAnimation 暂停动画
playAnimation 运行动画
setFrameName 设置动画帧名称——只对 JSON Hash 格式(构造时传了 animationNames)有效;对上面的图像集/JSON Array 实体调用无效果。在资源加载完成(模块 isLoaded)之前调用会被直接忽略,应在加载完成后(如用户点击时)再调用。
// JSON Hash 格式:帧名里含 'idle' / 'celebration' 的帧各成一段动画
const animNames = ['idle', 'celebration'];
let boyEnt = new vjmap3d.SpriteAnimatorEntity({
frameName: 'idle', // 初始播放的动画段
animationNames: animNames, // JSON Hash 必填
fps: 24,
autoPlay: true,
loop: true,
textureImageURL: env.assetsPath + "sprites/boy_hash.png",
textureDataURL: env.assetsPath + "sprites/boy_hash.json",
asSprite: true
});
boyEnt.addTo(app);
// 须在加载完成后调用(构造后立即调用会被忽略),例如放在按钮回调里切换动画段
const switchAnim = () => boyEnt.setFrameName('celebration');
事件交互
spriteAnimatorEnt.add(vjmap3d.EventModule, {
hoverSelect: true,
clickCallback: (ent, isClick) => {
if (!isClick) return
app.logInfo("您点击我了")
}
});
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true, } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let spriteAnimatorEnt = new vjmap3d.SpriteAnimatorEntity({
startFrame: 0,
autoPlay: true,
loop: true,
numberOfFrames: 16,
textureImageURL: env.assetsPath + "sprites/alien.png",
asSprite: true
})
spriteAnimatorEnt.position.set(-2, 0, 2);
spriteAnimatorEnt.addTo(app);
spriteAnimatorEnt.add(vjmap3d.EventModule, {
hoverSelect: true,
clickCallback: (ent, isClick) => {
if (!isClick) return
app.logInfo("您点击我了")
}
});
// fire
let entFire = new vjmap3d.SpriteAnimatorEntity({
startFrame: 0,
fps: 40,
autoPlay: true,
loop: true,
textureImageURL: env.assetsPath + "sprites/flame.png",
textureDataURL: env.assetsPath + "sprites/flame.json",
asSprite: true
})
entFire.position.set(0, 0, -5);
entFire.addTo(app);
//
const animNames = ['idle', 'celebration']
let entBoy = new vjmap3d.SpriteAnimatorEntity({
frameName: 'idle',
fps: 24,
animationNames: animNames,
autoPlay: true,
loop: true,
textureImageURL: env.assetsPath + "sprites/boy_hash.png",
textureDataURL: env.assetsPath + "sprites/boy_hash.json",
asSprite: true,
})
entBoy.position.set(2, 0, 2);
entBoy.scale.set(3, 3, 3)
entBoy.addTo(app)
//
let aniIndex = 0;
const ui = await app.getConfigPane({ title: "设置", style: { width: "250px", overflow: "hidden"}});
let cfg = [
{
type: 'button',
label: '切换动画',
value: ()=> {
let name = animNames[++aniIndex % 2];
entBoy.setFrameName(name)
}
},
{
type: 'button',
label: '停止动画',
value: ()=> {
entBoy.pauseAnimation()
}
},
{
type: 'button',
label: '开始动画',
value: ()=> {
entBoy.playAnimation()
}
},
]
cfg.forEach(c => ui.appendChild(c));