import { Object3D } from './Object3D';
import { ModelAnimationComponent } from '../components/ModelAnimationComponent';
const __ = {
private: Symbol('private'),
}
/**
* 动画组件默认名称 不要修改!
*/
const _internalAnimationComponentName = '_internalAnimation';
const registerComponentParam = { autoRegister: false, isResident: true };
/**
* @class BaseEntity
* 在场景中加载3d模型资源的物体,支持动画播放
* @memberof THING
* @extends THING.Object3D
* @public
*/
class BaseEntity extends Object3D {
/**
* 基础实体类,负责在场景中加载3D模型资源并支持动画播放
* </br>场景中加载三维模型资源的基础实体对象。
* @param {object} param 初始化参数 这里支持Object3D初始化的所有参数,此外可接受url作为资源路径
* @param {string} param.url 资源路径
*/
constructor(param) {
super(param);
this._animation = this._animation || null;
}
// #region Private
_playDelayAnimation() {
// Make sure object is alive
if (this.destroyed) {
return;
}
// Get the renderable node
let node = this.bodyNode;
// If entity has animation then complete the delayed commands of it
if (node.hasAnimation()) {
// Refresh the animation component
if (this._animation) {
this._animation.refreshAnimations();
}
this.animation.runDelayedCommands();
}
// If entity do not have any animations, then use the dummy animation component
else {
if (this._animation) {
this.removeComponent('animation');
}
this._animation = ModelAnimationComponent.cDummyAnimationInterface;
}
}
// #endregion
// #region Object3D overrides
onAfterSetup(param) {
if (param.extras && param.extras.animInfo) {
const animInfo = param.extras.animInfo;
this.playAnimation(animInfo);
}
}
onLoadComplete(options) {
super.onLoadComplete(options);
this._playDelayAnimation();
}
unloadResource(recursive = true) {
this.clearInternalAnimation();
return super.unloadResource(recursive);
}
clearInternalAnimation() {
if (this._animation) {
this._animation.stopAllAnimations();
this._animation = null;
this.removeComponent(_internalAnimationComponentName);
}
}
// #endregion
// #region Internal components attributes and functions
// #region Component - animation
get animation() {
if (!this._animation) {
this._animation = new ModelAnimationComponent();
this.addComponent(this._animation, _internalAnimationComponentName, registerComponentParam);
}
return this._animation;
}
/**
* 获取资源自带的所有动画信息
* @type {Array<AnimationResult>}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* let animations = UinoSpaceman.animations;
* let ret = animations[0].name == 'Walk';
* // @expect(ret == true);
* });
* @public
*/
get animations() { return this.animation.animations; }
/**
* 获取资源自带的所有动画名称
* @type {Array<string>}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* let animations = UinoSpaceman.animationNames;
* let ret = animations[0] == 'Walk';
* // @expect(ret == true);
* });
* @public
*/
get animationNames() { return this.animation.animationNames; }
/**
* @typedef {object} PlayAnimationArgs 动画播放的参数
* @property {string} name 动画名称
* @property {number} times? 循环次数
* @property {LoopType} loopType? 循环类型
* @property {number} [speed=1] 播放速度
* @property {boolean} [reverse=false] 是否反向播放
* @property {Function} [onComplete=null] 播放完成回调函数
* @public
*/
/**
* 播放动画,会停止所有其他正在播放的动画
* @param {PlayAnimationArgs} param 参数
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret = UinoSpaceman.isAnimationPlaying('Walk');
* // @expect(ret == true);
* });
* @public
*/
playAnimation() { this.animation.playAnimation.apply(this.animation, arguments); }
/**
* 异步模式下播放动画,会停止所有其他正在播放的动画。
* @param {PlayAnimationArgs} param 动画播放参数
* @returns {Promise<any>} 返回一个Promise,用于异步处理动画播放完成后的回调
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimationAsync({ name: 'Walk', loopType: "Repeat" });
* let ret = UinoSpaceman.isAnimationPlaying('Walk');
* // @expect(ret == true);
* });
* @private
*/
playAnimationAsync() { return this.animation.playAnimationAsync.apply(this.animation, arguments); }
/**
* 播放动画,播放时不会影响该物体正在播放的其他动画
* @param {PlayAnimationArgs} param 动画播放参数
* @returns {void} 无返回值
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.blendAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret = UinoSpaceman.isAnimationPlaying('Walk');
* // @expect(ret == true);
* });
* @public
*/
blendAnimation() { return this.animation.blendAnimation.apply(this.animation, arguments); }
/**
* 异步模式下混合动画,不会停止所有其他正在播放的动画。
* @param {PlayAnimationArgs} param 动画播放参数
* @returns {Promise<any>} 返回一个Promise,用于异步处理动画播放完成后的回调
* @private
*/
blendAnimationAsync() { return this.animation.blendAnimationAsync.apply(this.animation, arguments); }
/**
* 根据动画名称检查该对象身上是否有这个动画
* @param {string} name 动画名称
* @returns {boolean} 返回一个布尔值,表示是否有指定名称的动画
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* let ret = UinoSpaceman.hasAnimation('Walk');
* // @expect(ret == true);
* });
* @public
*/
hasAnimation() { return this.animation.hasAnimation.apply(this.animation, arguments); }
/**
* 该名称的动画是否正在播放
* @returns {boolean}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret = UinoSpaceman.isAnimationPlaying('Walk');
* // @expect(ret == true);
* });
* @public
*/
isAnimationPlaying() { return this.animation.isAnimationPlaying.apply(this.animation, arguments); }
/**
* 暂停动画(暂停名称匹配的所有动画)
* @param {string|string[]} name 动画名称或动画名称的数组
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret1 = UinoSpaceman.isAnimationPlaying('Walk');
* UinoSpaceman.pauseAnimation('Walk');
* let ret2 = UinoSpaceman.getAnimationState() == 'Paused';
* // @expect(ret1 == true && ret2 == true);
* });
* @public
*/
pauseAnimation() { this.animation.pauseAnimation.apply(this.animation, arguments); }
/**
* 暂停所有动画
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret1 = UinoSpaceman.isAnimationPlaying('Walk');
* UinoSpaceman.pauseAllAnimations();
* let ret2 = UinoSpaceman.getAnimationState() == 'Paused';
* // @expect(ret1 == true && ret2 == true);
* });
* @public
*/
pauseAllAnimations() { this.animation.pauseAllAnimations.apply(this.animation, arguments); }
/**
* 恢复动画(恢复名称匹配的所有动画)
* @param {string|Array<string>} name 动画名称或动画名称的数组
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret1 = UinoSpaceman.isAnimationPlaying('Walk');
* UinoSpaceman.pauseAnimation('Walk');
* let ret2 = UinoSpaceman.getAnimationState() == 'Paused';
* UinoSpaceman.resumeAnimation('Walk');
* let ret3 = UinoSpaceman.isAnimationPlaying('Walk');
* // @expect(ret1 == true && ret2 == true && ret3 == true);
* });
* @public
*/
resumeAnimation() { this.animation.resumeAnimation.apply(this.animation, arguments); }
/**
* 恢复所有动画
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret1 = UinoSpaceman.isAnimationPlaying('Walk');
* UinoSpaceman.pauseAnimation('Walk');
* let ret2 = UinoSpaceman.getAnimationState() == 'Paused';
* UinoSpaceman.resumeAllAnimations();
* let ret3 = UinoSpaceman.isAnimationPlaying('Walk');
* // @expect(ret1 == true && ret2 == true && ret3 == true);
* });
* @public
*/
resumeAllAnimations() { this.animation.resumeAllAnimations.apply(this.animation, arguments); }
/**
* 停止动画
* @param {string} name 动画名称
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret1 = UinoSpaceman.isAnimationPlaying('Walk');
* UinoSpaceman.stopAnimation('Walk');
* let ret2 = UinoSpaceman.getAnimationState() == 'Stopped';
* // @expect(ret1 == true && ret2 == true);
* });
* @public
*/
stopAnimation() { this.animation.stopAnimation.apply(this.animation, arguments); }
/**
* 停止所有动画
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let ret1 = UinoSpaceman.isAnimationPlaying('Walk');
* UinoSpaceman.stopAllAnimations();
* let ret2 = UinoSpaceman.getAnimationState() == 'Stopped';
* // @expect(ret1 == true && ret2 == true);
* });
* @public
*/
stopAllAnimations() { this.animation.stopAllAnimations.apply(this.animation, arguments); }
/**
* @typedef {object} AnimationResult 动画信息
* @property {string} name 动画名称
* @property {number} duration 时长(秒)
* @property {number} speed 播放速度
* @property {PlayState} state 播放状态
* @public
*/
/**
* 根据名称获取动画信息
* @param {string} name 动画名称
* @returns {AnimationResult} 动画信息
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* let animation = UinoSpaceman.getAnimation('Walk');
* let ret = animation.name == 'Walk';
* // @expect(ret == true);
* });
* @public
*/
getAnimation() { return this.animation.getAnimation.apply(this.animation, arguments); }
/**
* 根据名称获取动画播放状态
* @param {string} name 动画名称
* @returns {PlayState}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let state = UinoSpaceman.getAnimationState('Walk');
* let ret = state == 'Playing';
* // @expect(ret == true);
* });
* @public
*/
getAnimationState() { return this.animation.getAnimationState.apply(this.animation, arguments); }
/**
* 获取所有正在播放的动画
* @returns {Array<AnimationResult>}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat" });
* let animations = UinoSpaceman.getPlayingAnimations();
* let ret = animations[0].state == 'Playing';
* // @expect(ret == true);
* });
* @public
*/
getPlayingAnimations() { return this.animation.getPlayingAnimations.apply(this.animation, arguments); }
/**
* 获取动画播放的方向(正向/反向)
* </br>获取动画的方向类型。
* @param {string} name 动画名称
* @returns {AnimationDirectionType}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* let direction = UinoSpaceman.getAnimationDirectionType('Walk');
* let ret = direction == 'Normal';
* // @expect(ret == true);
* });
* @public
*/
getAnimationDirectionType() { return this.animation.getAnimationDirectionType.apply(this.animation, arguments); }
/**
* 设置动画的方向类型。
* @param {string} name 动画名称
* @param {AnimationDirectionType} value 方向类型(THING.AnimationDirectionType.Normal/THING.AnimationDirectionType.Reverse)
* @returns {boolean} 返回一个布尔值,表示是否设置成功
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.setAnimationDirectionType('Walk', 'Reverse');
* let direction = UinoSpaceman.getAnimationDirectionType('Walk');
* let ret = direction == 'Reverse';
* // @expect(ret == true);
* });
* @public
*/
setAnimationDirectionType() { return this.animation.setAnimationDirectionType.apply(this.animation, arguments); }
/**
* 获取动画速度
* @param {string} name 动画名称
* @returns {number} 播放速度
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat", speed: 10 });
* let speed = UinoSpaceman.getAnimationSpeed('Walk');
* let ret = speed == 10;
* // @expect(ret == true);
* });
* @public
*/
getAnimationSpeed() { return this.animation.getAnimationSpeed.apply(this.animation, arguments); }
/**
* 设置动画速度
* @param {string} name 动画名称
* @param {number} value 速度
* @returns {boolean}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat", speed: 10 });
* UinoSpaceman.setAnimationSpeed('Walk', 20)
* let speed = UinoSpaceman.getAnimationSpeed('Walk');
* let ret = speed == 20;
* // @expect(ret == true);
* });
* @public
*/
setAnimationSpeed() { return this.animation.setAnimationSpeed.apply(this.animation, arguments); }
/**
* 获取动画权重
* @param {string} name 动画名称
* @returns {number} 播放权重
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat", speed: 10 });
* let weight = UinoSpaceman.getAnimationWeight('Walk');
* let ret = weight == 0;
* // @expect(ret == true);
* });
* @public
*/
getAnimationWeight() { return this.animation.getAnimationWeight.apply(this.animation, arguments); }
/**
* 设置动画速度
* @param {string} name 动画名称
* @param {number} value 权重
* @returns {boolean}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* UinoSpaceman.playAnimation({ name: 'Walk', loopType: "Repeat", speed: 10 });
* UinoSpaceman.setAnimationWeight('Walk', 0.5)
* let weight = UinoSpaceman.getAnimationWeight('Walk');
* let ret = weight == 0.5;
* // @expect(ret == true);
* });
* @public
*/
setAnimationWeight() { return this.animation.setAnimationWeight.apply(this.animation, arguments); }
// #endregion
/**
* Promote node as child object.
* @param {string} name The node name.
* @param {THING.Object3D} parent The parent object, if it's null then indicates use current object as parent.
* @param {Function} [cls] The class type of the promoted object.
* @returns {THING.Object3D} The promoted object.
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* UinoSpaceman.waitForComplete().then(() => {
* let obj = UinoSpaceman.promoteNode('pasted__head');
* let ret1 = obj instanceof THING.BaseEntity;
* let ret2 = obj.name == 'pasted__head';
* // @expect(ret1 == true && ret2 == true);
* });
*/
promoteNode(name, parent, cls = BaseEntity) {
return super.promoteNode(name, parent, cls);
}
/**
* Check whether it's BaseEntity type or inherit from it.
* @type {boolean}
* @example
* var UinoSpaceman = new THING.Entity({url:'.assets/models/UinoSpaceman/UinoSpaceman.gltf'});
* let ret = UinoSpaceman.isBaseEntity;
* // @expect(ret == true);
*/
get isBaseEntity() {
return true;
}
}
export { BaseEntity }