diff --git a/ShadowEditor.Web/src/animation/Animation.js b/ShadowEditor.Web/src/animation/Animation.js index 99f8fcc1..c14d52db 100644 --- a/ShadowEditor.Web/src/animation/Animation.js +++ b/ShadowEditor.Web/src/animation/Animation.js @@ -16,7 +16,7 @@ function Animation(options) { this.name = options.name || `动画${ID--}`; // 动画名称 this.target = options.target || null; // 动画对象uuid this.type = options.type || AnimationType.Tween; // 动画类型 - this.startTime = options.startTime || 0; // 开始时间(秒) + this.beginTime = options.beginTime || 0; // 开始时间(秒) this.endTime = options.endTime || 10; // 结束时间(秒) // 补间动画 diff --git a/ShadowEditor.Web/src/component/animation/BasicAnimationComponent.js b/ShadowEditor.Web/src/component/animation/BasicAnimationComponent.js index b08ff2a6..1808c2d5 100644 --- a/ShadowEditor.Web/src/component/animation/BasicAnimationComponent.js +++ b/ShadowEditor.Web/src/component/animation/BasicAnimationComponent.js @@ -95,7 +95,7 @@ BasicAnimationComponent.prototype.render = function () { text: '开始时间' }, { xtype: 'number', - id: 'startTime', + id: 'beginTime', scope: this.id, range: [0, Infinity], onChange: this.onChange.bind(this) @@ -144,7 +144,7 @@ BasicAnimationComponent.prototype.updateUI = function (animation) { var name = UI.get('name', this.id); var target = UI.get('target', this.id); var type = UI.get('type', this.id); - var startTime = UI.get('startTime', this.id); + var beginTime = UI.get('beginTime', this.id); var endTime = UI.get('endTime', this.id); name.setValue(this.animation.name); @@ -162,7 +162,7 @@ BasicAnimationComponent.prototype.updateUI = function (animation) { } type.setValue(this.animation.type); - startTime.setValue(this.animation.startTime); + beginTime.setValue(this.animation.beginTime); endTime.setValue(this.animation.endTime); }; @@ -180,12 +180,12 @@ BasicAnimationComponent.prototype.onSetTarget = function () { BasicAnimationComponent.prototype.onChange = function () { var name = UI.get('name', this.id); var type = UI.get('type', this.id); - var startTime = UI.get('startTime', this.id); + var beginTime = UI.get('beginTime', this.id); var endTime = UI.get('endTime', this.id); this.animation.name = name.getValue(); this.animation.type = type.getValue(); - this.animation.startTime = startTime.getValue(); + this.animation.beginTime = beginTime.getValue(); this.animation.endTime = endTime.getValue(); this.app.call('animationChanged', this, this.animation); diff --git a/ShadowEditor.Web/src/editor/bottom/AnimationPanel.js b/ShadowEditor.Web/src/editor/bottom/AnimationPanel.js index f80d0c93..58e22124 100644 --- a/ShadowEditor.Web/src/editor/bottom/AnimationPanel.js +++ b/ShadowEditor.Web/src/editor/bottom/AnimationPanel.js @@ -208,8 +208,8 @@ AnimationPanel.prototype.updateUI = function () { item.className = 'item'; item.setAttribute('draggable', true); item.setAttribute('droppable', false); - item.style.left = m.startTime * timeline.scale + 'px'; - item.style.width = (m.endTime - m.startTime) * timeline.scale + 'px'; + item.style.left = m.beginTime * timeline.scale + 'px'; + item.style.width = (m.endTime - m.beginTime) * timeline.scale + 'px'; item.innerHTML = m.name; item.addEventListener('dragstart', this.onDragStartAnimation.bind(this)); item.addEventListener('dragend', this.onDragEndAnimation.bind(this)); @@ -357,7 +357,7 @@ AnimationPanel.prototype.onDblClick = function (event) { event.stopPropagation(); var animation = new Animation({ - startTime: event.offsetX / timeline.scale, + beginTime: event.offsetX / timeline.scale, endTime: (event.offsetX + 80) / timeline.scale }); @@ -416,9 +416,9 @@ AnimationPanel.prototype.onDropGroup = function (event) { group.remove(animation); var timeline = UI.get('timeline', this.id); - var length = animation.endTime - animation.startTime; - animation.startTime = (event.offsetX - offsetX) / timeline.scale; - animation.endTime = animation.startTime + length; + var length = animation.endTime - animation.beginTime; + animation.beginTime = (event.offsetX - offsetX) / timeline.scale; + animation.endTime = animation.beginTime + length; if (event.target.data instanceof Animation) { // 拖动到其他动画上 event.target.parentElement.data.add(animation); diff --git a/ShadowEditor.Web/src/editor/window/SceneWindow.js b/ShadowEditor.Web/src/editor/window/SceneWindow.js index 774e3123..961bde9d 100644 --- a/ShadowEditor.Web/src/editor/window/SceneWindow.js +++ b/ShadowEditor.Web/src/editor/window/SceneWindow.js @@ -232,7 +232,7 @@ SceneWindow.prototype.loadScene = function (data) { name: m.name, target: m.target, type: m.type, - startTime: m.startTime, + beginTime: m.beginTime, endTime: m.endTime, // 补间动画 diff --git a/ShadowEditor.Web/src/player/Player.js b/ShadowEditor.Web/src/player/Player.js index ffb63ee8..982b8176 100644 --- a/ShadowEditor.Web/src/player/Player.js +++ b/ShadowEditor.Web/src/player/Player.js @@ -1,5 +1,6 @@ import UI from '../ui/UI'; import Converter from '../serialization/Converter'; +import Ease from '../animation/Ease'; /** * 播放器 @@ -15,7 +16,8 @@ function Player(options) { this.renderer = null; this.scripts = null; this.animation = null; - this.animationTime = 0; + this.maxAnimationTime = 0; + this.currentAnimationTime = 0; this.audioListener = null; @@ -170,11 +172,11 @@ Player.prototype.initPlayer = function (obj) { // 动画 this.animation = obj.animation; - this.animationTime = 0; + this.maxAnimationTime = 0; this.animation.forEach(n => { n.animations.forEach(m => { - if (m.endTime > this.animationTime) { - this.animationTime = m.endTime; + if (m.endTime > this.maxAnimationTime) { + this.maxAnimationTime = m.endTime; } }); }); @@ -309,6 +311,9 @@ Player.prototype.initScene = function () { // 动画 this.app.call(`resetAnimation`, this.id); this.app.call(`startAnimation`, this.id); + this.app.on(`animationTime.${this.id}`, (time) => { + this.currentAnimationTime = time; + }); }; Player.prototype.destroyScene = function () { @@ -317,6 +322,11 @@ Player.prototype.destroyScene = function () { n.stop(); } }); + + this.app.on(`animationTime.${this.id}`, null); + this.app.call(`resetAnimation`, this.id); + this.currentAnimationTime = 0; + this.maxAnimationTime = 0; }; /** @@ -325,6 +335,7 @@ Player.prototype.destroyScene = function () { Player.prototype.animate = function () { this.renderScene(); + // 脚本事件 var deltaTime = this.clock.getDelta(); this.events.forEach(n => { @@ -333,9 +344,75 @@ Player.prototype.animate = function () { } }); + // 动画 + this.animation.forEach(n => { + n.animations.forEach(m => { + this.tweenObject(m); // 补间动画 + }); + }); + + // 超过最大动画时间,重置动画 + if (this.currentAnimationTime > this.maxAnimationTime) { + this.app.call(`resetAnimation`, this.id); + this.app.call(`startAnimation`, this.id); + } + if (this.isPlaying) { requestAnimationFrame(this.animate.bind(this)); } }; +/** + * 补间动画处理 + * @param {*} animation + */ +Player.prototype.tweenObject = function (animation) { + var time = this.currentAnimationTime; + + // 条件判断 + if (animation.type !== 'Tween' || time < animation.beginTime || time > animation.endTime || animation.target == null) { + return; + } + + // 获取对象 + var target = this.scene.getObjectByProperty('uuid', animation.target); + if (target == null) { + console.warn(`Player: 场景中不存在uuid为${animation.target}的物体。`); + return; + } + + // 获取插值函数 + var ease = Ease[animation.ease]; + if (ease == null) { + console.warn(`Player: 不存在名称为${animation.ease}的插值函数。`); + return; + } + + var result = ease((time - animation.beginTime) / (animation.endTime - animation.beginTime)); + + var positionX = animation.beginPositionX + (animation.endPositionX - animation.beginPositionX) * result; + var positionY = animation.beginPositionY + (animation.endPositionY - animation.beginPositionY) * result; + var positionZ = animation.beginPositionZ + (animation.endPositionZ - animation.beginPositionZ) * result; + + var rotationX = animation.beginRotationX + (animation.endRotationX - animation.beginRotationX) * result; + var rotationY = animation.beginRotationY + (animation.endRotationY - animation.beginRotationY) * result; + var rotationZ = animation.beginRotationZ + (animation.endRotationZ - animation.beginRotationZ) * result; + + var scaleX = animation.beginScaleX + (animation.endScaleX - animation.beginScaleX) * result; + var scaleY = animation.beginScaleY + (animation.endScaleY - animation.beginScaleY) * result; + var scaleZ = animation.beginScaleZ + (animation.endScaleZ - animation.beginScaleZ) * result; + + target.position.x = positionX; + target.position.y = positionY; + target.position.z = positionZ; + + target.rotation.x = rotationX; + target.rotation.y = rotationY; + target.rotation.z = rotationZ; + + target.scale.x = scaleX; + target.scale.y = scaleY; + target.scale.z = scaleZ; +}; + export default Player; \ No newline at end of file