动画实现的基础是基类Animation,所有的动画都必须派生于它去实现必要的方法。让我们以一个例子来看看:
import XrFrame from 'XrFrame';
const xrFrameSystem = wx.getXrFrameSystem();
// 定制动画接受的初始化数据接口
interface IXrTeamCameraAnimtionData {
targets: {
hikari: XrFrame.Vector3;
roam: XrFrame.Vector3;
xinyi: XrFrame.Vector3;
final: XrFrame.Vector3;
},
}
// 定制动画接受的播放额外配置接口
interface IXrTeamCameraAnimationOptions {
}
// 定制动画的实现
class XrTeamCameraAnimation extends xrFrameSystem.Animation<
IXrTeamCameraAnimtionData,
IXrTeamCameraAnimationOptions
> {
private _camera: XrFrame.Transform | undefined;
private _target: XrFrame.Transform | undefined;
private _targets: IXrTeamCameraAnimtionData['targets'] | undefined;
private _startC: XrFrame.Vector3 = new xrFrameSystem.Vector3();
private _endC: XrFrame.Vector3 = new xrFrameSystem.Vector3();
private _startT: XrFrame.Vector3 = new xrFrameSystem.Vector3();
private _endT: XrFrame.Vector3 = new xrFrameSystem.Vector3();
// 动画初始化时会被执行,传入初始数据
// 必须设置`this.clipNames`,提供给动画组件必要的信息
public onInit(data: IXrTeamCameraAnimtionData) {
this._targets = data.targets;
this.clipNames = ['hikari', 'roam', 'xinyi'];
}
// 动画被播放时会被执行,必须返回片段时长`duration`
// 剩下三个返回参数是可选的,详见API文档
public onPlay(el: XrFrame.Element, clipName: string, options: IXrTeamCameraAnimationOptions): {
duration: number,
loop?: number,
delay?: number,
direction?: XrFrame.TDirection
} {
this._camera = this._camera || el.getComponent(xrFrameSystem.Transform);
this._target = el.getComponent(xrFrameSystem.Camera).target;
this._startT.set(this._target.position);
this._endT.setValue(this._targets![clipName].x, this._targets![clipName].y, this._targets![clipName].z);
this._startC.set(this._camera.position);
this._endC.set(this._endT);
this._endC.z += 2;
return {duration: 3};
}
// 动画播放进度更新是会被执行,`progress`的范围是`0~1`
// `el`参数是指这个动画目前作用于哪个元素,因为动画和元素、组件并非总是一一对应的
public onUpdate(el: XrFrame.Element, progress: number, reverse: boolean) {
progress = xrFrameSystem.noneParamsEaseFuncs['ease-in-out'](progress);
this._startT?.lerp(this._endT, progress, this._target?.position);
this._startC?.lerp(this._endC, progress, this._camera?.position);
}
// 动画播放暂停时会被执行,暂停本身的逻辑是自动的
public onPause(el: XrFrame.Element) {
}
// 动画从暂停中唤醒时会被执行
public onResume(el: XrFrame.Element) {
}
// 动画停止时会被执行,包括播放结束和手动停止
public onStop(el: XrFrame.Element) {
}
}
这段代码中,我们定制了一个动画,它的几个生命周期来定义其是如何运作的。框架内置了两种动画帧动画和gltf动画,但这里我们先不讨论它们,先看看在实现了一个动画后,如何去创建和操纵它,这也就引入了动画组件。