当前位置: 代码迷 >> 综合 >> 3D小游戏(three)-Bottle物体开始动画(Tween自实现)实现
  详细解决方案

3D小游戏(three)-Bottle物体开始动画(Tween自实现)实现

热度:43   发布时间:2024-03-08 02:33:42.0

Bottle开始动画

头部旋转

  1. bottle.js

updated() {

this.head.rotation.y += 0.06

}

  1. game-page.js

render中

this.bottle.updated()

下坠动画

  1. libs/animation.js

import Tween from './tween'

var animationId = -1

var killAnimationId = animationId - 1

 

var customAnimation = exports.customAnimation = {};//暴露对象集合

customAnimation.to = function (obj, duration, options) {

duration *= 1000;

var delay = options.delay || 0;

for (var name in options) {

if (name === 'delay') {

delay = options[name];

} else if (name === 'onComplete') {} else if (name === 'ease') {} else {

setTimeout(function (name) {

return function () {

//console.log("name", name, obj[name], options[name], duration, delay, obj)

TweenAnimation(obj[name], options[name], duration, options.ease || 'Linear', function (value, complete) {

obj[name] = value;

if (complete) {

options.onComplete && options.onComplete();

}

});

};

}(name), delay * 1000);

}

}

}

 

// 对运动方法进行封装

var TweenAnimation = exports.TweenAnimation = function TweenAnimation(from, to, duration, easing, callback) {

var selfAnimationId = ++animationId;

var isUndefined = function isUndefined(obj) {

return typeof obj == 'undefined';

};

var isFunction = function isFunction(obj) {

return typeof obj == 'function';

};

var isNumber = function isNumber(obj) {

return typeof obj == 'number';

};

var isString = function isString(obj) {

return typeof obj == 'string';

};

 

// 转换成毫秒

var toMillisecond = function toMillisecond(obj) {

if (isNumber(obj)) {

return obj;

} else if (isString(obj)) {

if (/\d+m?s$/.test(obj)) {

if (/ms/.test(obj)) {

return 1 * obj.replace('ms', '');

}

return 1000 * obj.replace('s', '');

} else if (/^\d+$/.test(obj)) {

return +obj;

}

}

return -1;

};

 

if (!isNumber(from) || !isNumber(to)) {

if (window.console) {

console.error('from和to两个参数必须且为数值');

}

return 0;

}

 

// 缓动算法

var tween = Tween

 

if (!tween) {

if (window.console) {

console.error('缓动算法函数缺失');

}

return 0;

}

 

// duration, easing, callback均为可选参数

// 而且顺序可以任意

var options = {

duration: 300,

easing: 'Linear',

callback: function callback() {}

};

 

var setOptions = function setOptions(obj) {

if (isFunction(obj)) {

options.callback = obj;

} else if (toMillisecond(obj) != -1) {

options.duration = toMillisecond(obj);

} else if (isString(obj)) {

options.easing = obj;

}

};

setOptions(duration);

setOptions(easing);

setOptions(callback);

 

// requestAnimationFrame的兼容处理

if (!window.requestAnimationFrame) {

requestAnimationFrame = function requestAnimationFrame(fn) {

setTimeout(fn, 17);

};

}

 

// 算法需要的几个变量

var start = -1;//当前渲染帧数

// during根据设置的总时间计算

var during = Math.ceil(options.duration / 17);

 

// 当前动画算法

// 确保首字母大写

options.easing = options.easing.slice(0, 1).toUpperCase() + options.easing.slice(1);

var arrKeyTween = options.easing.split('.');

var fnGetValue;

 

if (arrKeyTween.length == 1) {

fnGetValue = tween[arrKeyTween[0]];

} else if (arrKeyTween.length == 2) {

fnGetValue = tween[arrKeyTween[0]] && tween[arrKeyTween[0]][arrKeyTween[1]];

}

if (isFunction(fnGetValue) == false) {

console.error('没有找到名为"' + options.easing + '"的动画算法');

return;

}

 

var startTime = Date.now();

var lastTime = Date.now();

// 运动

var step = function step() {

var currentTime = Date.now();

var interval = currentTime - lastTime;

if (interval) {

var fps = Math.ceil(1000 / interval);

} else {

requestAnimationFrame(step);

return;

}

lastTime = currentTime;

if (interval > 100) { //大于100毫秒

requestAnimationFrame(step);

return;

}

 

if (fps >= 30) {

start++;

} else {

var _start = Math.floor((currentTime - startTime) / 17);

start = _start > start ? _start : start + 1;//跳帧

}

// 当前的运动位置

var value = fnGetValue(start, from, to - from, during);

// 如果还没有运动到位,继续

if (start <= during && selfAnimationId > killAnimationId) {

options.callback(value);

requestAnimationFrame(step);

} else if (start > during && selfAnimationId > killAnimationId) {

// 动画结束,这里可以插入回调...

options.callback(to, true);

} else {}

};

// 开始执行动画

step();

};

TweenAnimation.killAll = function () {

killAnimationId = animationId;

};

  1. libs/tween,js

var Tween = {

Linear: function Linear(t, b, c, d) {

return c * t / d + b;

},

Bounce: {

easeIn: function easeIn(t, b, c, d) {

return c - Tween.Bounce.easeOut(d - t, 0, c, d) + b;

},

easeOut: function easeOut(t, b, c, d) {

if ((t /= d) < 1 / 2.75) {

return c * (7.5625 * t * t) + b;

} else if (t < 2 / 2.75) {

return c * (7.5625 * (t -= 1.5 / 2.75) * t + .75) + b;

} else if (t < 2.5 / 2.75) {

return c * (7.5625 * (t -= 2.25 / 2.75) * t + .9375) + b;

} else {

return c * (7.5625 * (t -= 2.625 / 2.75) * t + .984375) + b;

}

},

easeInOut: function easeInOut(t, b, c, d) {

if (t < d / 2) {

return Tween.Bounce.easeIn(t * 2, 0, c, d) * .5 + b;

} else {

return Tween.Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;

}

}

}

}

export default Tween

  1. bottle.js

showup(){

//开始动画

customAnimation.to(this.obj.position, 0.5, { x: bottleConf.initPosition.x, y: bottleConf.initPosition.y + blockConf.height / 2, z: bottleConf.initPosition.z, ease: 'Bounce.easeOut' })

}

  1. game-page.js

addGround中

this.bottle.showup()