少儿编程免费网站,企业网怎么拉,网页制作公司网站,如何制作假网页在 Cocos Creator 3.x 版本中#xff0c; Tween系统代替了原来的Action系统。很多朋友不明白Tween到底是什么#xff0c;Tween原理是什么#xff1f;怎么使用Tween#xff1f; 今天就来详细了解一下#xff0c;希望能帮助到大家加深对Tween的了解#xff0c;并快速掌握Tw…
在 Cocos Creator 3.x 版本中 Tween系统代替了原来的Action系统。很多朋友不明白Tween到底是什么Tween原理是什么怎么使用Tween 今天就来详细了解一下希望能帮助到大家加深对Tween的了解并快速掌握Tween的使用方法。 一、Tween到底是什么 Tween 又称为缓动系统可以用于变换位置、旋转、缩放和颜色等常规动画信息也支持延迟队列并行等动作行为。 首先我们来看一段案例代码
tween(this.node)//to,在第1秒的时候放大为2倍位置为(50,50),角度变化到90
.to(1,{scale:2,position:cc.v2(50,50),rotation:90})//by,在第2秒时缩放变化了2倍现在是原始大小的4倍位置变化了(50,50)现在位置为(100,100)
.by(1,{scale:2, position:cc.v2(100,100)})//在第3秒时缩放为原始大小位置设置为(0,0)然后加了一个缓动效果 backOut
.to(1,{scale:1,position:cc.v2(0,0)},{easing:backOut}).start(); 通过上面演示的代码我们可以知道Tween可以同时设置多个属性 在调用 start 时会将之前生成的 action 队列重新组合生成一个 cc.sequence 队列依次执行。 Tween的特点 支持以链式结构的方式创建一个动画序列 不局限于节点上的属性 Tween有2种设置方式 to 改变到某个值(绝对值) by 变化值(相对值) 二、Tween 缓动系统原理
为了加深理解来看一张UML图  此UML图中Node目标节点、Action动作 、ActionManager动作管理 类 相信大家都比较熟悉了这里就不作介绍。
这里还涉及到一些比较新的内容Tween 、TweenAction、props 、ITweenOption下面分别介绍。 1、Tween类是干嘛的
通过上面UML 图的接口我们可以清晰地看到Tween其实有两个主要功能
Action创建器负责Action的创建
在使用的时候可以添加一个或者多个Action到内部缓冲也可添加多个Action组合的串行Action或者并行Action。
内部维护一个最终Action可控制这个Action的启动与停止 Tween类重要成员属性
_target: 目标对象比如节点。_actions: 类型为Action[]创建过程中的一组Action缓冲。_finalAction: 创建完成之后的最终使用的Action。 Tween类重要接口 target: 设置目标对象 delay: 添加一个DelayAction to: 添加一个TweenAction来指定每个属性变换到多少-目标值 by: 添加一个TweenAction来指定每个属性变换多少-变化值 union: 将缓冲中的多个Action变成一个串行Action sequence: 将指定的多个Action或者Tween变成一个串行Action后添加到缓冲中 parallel: 将指定的多个Action或者Tween变成一个并行Action后添加到缓冲中 start: 开始运行此时会创建最终的Action并且启动此Action stop: 停止Action的运行 2、TweenAction是做什么的
TweenAction类从ActionInterval派生UML图中简化成从Action派生能够针对目标对象的多个任意属性以指定缓动方式进行变换。
只要目标对象的属性能够直接赋值和取值这个TweenAction就能够胜任。
前面的Tween类by接口和to接口就是用TweenAction实现。
它的灵活和强大之处在于不用像以前那样每个属性都要实现重复代码的Action类。 3、props是什么
props是TweenAction需要进行变换的属性。
props 本质就是一个键值对数据结构键为对象的属性名称值为进行变换的值。
例如
{ angle: 90, position: v3(200, 200, 0)}4、ITweenOption接口
ITweenOption接口其实就是进行变换的缓动方式以及变换过程中的回调从UML 图中我们也可以看到
可以指定如下属性 easing: 缓动方式 progress: 插值函数用来自定义缓动方式 onStart: 缓动动作启动时的回调函数 onUpdate: 缓动动作更新时的回调函数 onComplete: 缓动动作完成时的回调函数 三、Tween 的使用 明白了Tween 的原理和重要的接口后使用就比较简单了。 使用步骤可以简单分为三步
Step1:创建一个针对目标的Tween对象
let tween new Tween(this.node);Step2:添加执行过程
tween.to(1.0, {angle:90,position:v3(100,100,0) });Step3:开始执行tween对象
tween.start();四、Tween的源码实现 如果想深入了解Tween的朋友这里我贴了官方tween.ts和tween-action.ts 源码建议花点时间完整的看一下这样用起来会更加得心应手。 官方tween.ts源码
/*Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.https://www.cocos.com/Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the Software), to dealin the Software without restriction, including without limitation the rights touse, copy, modify, merge, publish, distribute, sublicense, and/or sell copiesof the Software, and to permit persons to whom the Software is furnished to do so,subject to the following conditions:The above copyright notice and this permission notice shall be included inall copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INTHE SOFTWARE.
*/import { warn } from base/debug;
import { cclegacy } from base/global;
import { TweenSystem } from ./tween-system;
import { ActionInterval, sequence, repeat, repeatForever, reverseTime, delayTime, spawn } from ./actions/action-interval;
import { removeSelf, show, hide, callFunc } from ./actions/action-instant;
import { Action, FiniteTimeAction } from ./actions/action;
import { ITweenOption } from ./export-api;
import { TweenAction } from ./tween-action;
import { SetAction } from ./set-action;// https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c
type FlagExcludedTypeBase, Type { [Key in keyof Base]: Base[Key] extends Type ? never : Key };
type AllowedNamesBase, Type FlagExcludedTypeBase, Type[keyof Base];
type KeyPartialT, K extends keyof T { [P in K]?: T[P] };
type OmitTypeBase, Type KeyPartialBase, AllowedNamesBase, Type;
// eslint-disable-next-line typescript-eslint/ban-types
type ConstructorTypeT OmitTypeT, Function;/*** en* Tween provide a simple and flexible way to action, Its transplanted from cocos creator。* zh* Tween 提供了一个简单灵活的方法来缓动目标从 creator 移植而来。* class Tween* param [target]* example* tween(this.node)* .to(1, {scale: new Vec3(2, 2, 2), position: new Vec3(5, 5, 5)})* .call(() { log(This is a callback); })* .by(1, {scale: new Vec3(-1, -1, -1), position: new Vec3(-5, -5, -5)}, {easing: sineOutIn})* .start()*/
export class TweenT {private _actions: Action[] [];private _finalAction: Action | null null;private _target: T | null null;private _tag Action.TAG_INVALID;constructor (target?: T | null) {this._target target undefined ? null : target;}/*** en Sets tween tag* zh 设置缓动的标签* method tag* param tag en The tag set for this tween zh 为当前缓动设置的标签*/tag (tag: number): TweenT {this._tag tag;return this;}/*** en* Insert an action or tween to this sequence.* zh* 插入一个 tween 到队列中。* method then* param other en The rear tween of this tween zh 当前缓动的后置缓动*/then (other: TweenT): TweenT {if (other instanceof Action) {this._actions.push(other.clone());} else {this._actions.push(other._union());}return this;}/*** en* Sets tween target.* zh* 设置 tween 的 target。* method target* param target en The target of this tween zh 当前缓动的目标对象*/target (target: T): TweenT | undefined {this._target target;return this;}/*** en* Start this tween.* zh* 运行当前 tween。*/start (): TweenT {if (!this._target) {warn(Please set target to tween first);return this;}if (this._finalAction) {TweenSystem.instance.ActionManager.removeAction(this._finalAction);}this._finalAction this._union();this._finalAction.setTag(this._tag);TweenSystem.instance.ActionManager.addAction(this._finalAction, this._target as any, false);return this;}/*** en* Stop this tween.* zh* 停止当前 tween。*/stop (): TweenT {if (this._finalAction) {TweenSystem.instance.ActionManager.removeAction(this._finalAction);}return this;}/*** en* Clone a tween.* zh* 克隆当前 tween。* method clone* param target en The target of clone tween zh 克隆缓动的目标对象*/clone (target: T): TweenT {const action this._union();return tween(target).then(action.clone() as any);}/*** en* Integrate all previous actions to an action.* zh* 将之前所有的 action 整合为一个 action。*/union (): TweenT {const action this._union();this._actions.length 0;this._actions.push(action);return this;}/*** en* Add an action which calculates with absolute value.* zh* 添加一个对属性进行绝对值计算的 action。* method to* param duration en Tween time, in seconds zh 缓动时间单位为秒* param props en List of properties of tween zh 缓动的属性列表* param opts en Optional functions of tween zh 可选的缓动功能* param opts.progress en Interpolation function zh 缓动的速度插值函数* param opts.easing en Tween function or a lambda zh 缓动的曲线函数或lambda表达式*/to (duration: number, props: ConstructorTypeT, opts?: ITweenOption): TweenT {opts opts || Object.create(null);(opts as any).relative false;const action new TweenAction(duration, props, opts);this._actions.push(action);return this;}/*** en* Add an action which calculates with relative value.* zh* 添加一个对属性进行相对值计算的 action。* method by* param duration en Tween time, in seconds zh 缓动时间单位为秒* param props en List of properties of tween zh 缓动的属性列表* param opts en Optional functions of tween zh 可选的缓动功能* param [opts.progress]* param [opts.easing]* return {Tween}*/by (duration: number, props: ConstructorTypeT, opts?: ITweenOption): TweenT {opts opts || Object.create(null);(opts as any).relative true;const action new TweenAction(duration, props, opts);this._actions.push(action);return this;}/*** en* Directly set target properties.* zh* 直接设置 target 的属性。* method set* param props en List of properties of tween zh 缓动的属性列表* return {Tween}*/set (props: ConstructorTypeT): TweenT {const action new SetAction(props);this._actions.push(action);return this;}/*** en* Add a delay action.* zh* 添加一个延时 action。* method delay* param duration en Delay time of this tween zh 当前缓动的延迟时间* return {Tween}*/delay (duration: number): TweenT {const action delayTime(duration);this._actions.push(action);return this;}/*** en* Add a callback action.* zh* 添加一个回调 action。* method call* param callback en Callback function at the end of this tween zh 当前缓动结束时的回调函数* return {Tween}*/// eslint-disable-next-line typescript-eslint/ban-typescall (callback: Function): TweenT {const action callFunc(callback);this._actions.push(action);return this;}/*** en* Add a sequence action.* zh* 添加一个队列 action。* method sequence* param args en All tween that make up the sequence zh 组成队列的所有缓动*/sequence (...args: TweenT[]): TweenT {const action Tween._wrappedSequence(...args);this._actions.push(action);return this;}/*** en* Add a parallel action.* zh* 添加一个并行 action。* method parallel* param args en The tween parallel to this tween zh 与当前缓动并行的缓动*/parallel (...args: TweenT[]): TweenT {const action Tween._wrappedParallel(...args);this._actions.push(action);return this;}/*** en* Add a repeat action.* This action will integrate before actions to a sequence action as their parameters.* zh* 添加一个重复 action这个 action 会将前一个动作作为他的参数。* param repeatTimes en The repeat times of this tween zh 重复次数* param embedTween en Optional, embedded tween of this tween zh 可选嵌入缓动*/repeat (repeatTimes: number, embedTween?: TweenT): TweenT {/** adapter */if (repeatTimes Infinity) {return this.repeatForever(embedTween);}const actions this._actions;let action: any;if (embedTween instanceof Tween) {action embedTween._union();} else {action actions.pop();}actions.push(repeat(action, repeatTimes));return this;}/*** en* Add a repeat forever action.* This action will integrate before actions to a sequence action as their parameters.* zh* 添加一个永久重复 action这个 action 会将前一个动作作为他的参数。* method repeatForever* param embedTween en Optional, embedded tween of this tween zh 可选嵌入缓动*/repeatForever (embedTween?: TweenT): TweenT {const actions this._actions;let action: any;if (embedTween instanceof Tween) {action embedTween._union();} else {action actions.pop();}actions.push(repeatForever(action as ActionInterval));return this;}/*** en* Add a reverse time action.* This action will integrate before actions to a sequence action as their parameters.* zh* 添加一个倒置时间 action这个 action 会将前一个动作作为他的参数。* method reverseTime* param embedTween en Optional, embedded tween of this tween zh 可选嵌入缓动*/reverseTime (embedTween?: TweenT): TweenT {const actions this._actions;let action: any;if (embedTween instanceof Tween) {action embedTween._union();} else {action actions.pop();}actions.push(reverseTime(action as ActionInterval));return this;}/*** en* Add a hide action, only for node target.* zh* 添加一个隐藏 action只适用于 target 是节点类型的。*/hide (): TweenT {const action hide();this._actions.push(action);return this;}/*** en* Add a show action, only for node target.* zh* 添加一个显示 action只适用于 target 是节点类型的。*/show (): TweenT {const action show();this._actions.push(action);return this;}/*** en* Add a removeSelf action, only for node target.* zh* 添加一个移除自己 action只适用于 target 是节点类型的。*/removeSelf (): TweenT {const action removeSelf(false);this._actions.push(action);return this;}/*** en* Add a destroySelf action, only for node target.* zh* 添加一个移除并销毁自己 action只适用于 target 是节点类型的。*/destroySelf (): TweenT {const action removeSelf(true);this._actions.push(action);return this;}/*** en* Stop all tweens* zh* 停止所有缓动*/static stopAll (): void {TweenSystem.instance.ActionManager.removeAllActions();}/*** en* Stop all tweens by tag* zh* 停止所有指定标签的缓动*/// eslint-disable-next-line typescript-eslint/ban-typesstatic stopAllByTag (tag: number, target?: object): void {TweenSystem.instance.ActionManager.removeAllActionsByTag(tag, target as any);}/*** en* Stop all tweens by target* zh* 停止所有指定对象的缓动*/// eslint-disable-next-line typescript-eslint/ban-typesstatic stopAllByTarget (target?: object): void {TweenSystem.instance.ActionManager.removeAllActionsFromTarget(target as any);}private _union (): Action {const actions this._actions;let action: Action;if (actions.length 1) {action actions[0];} else {action sequence(actions);}return action;}private _destroy (): void {this.stop();}private static readonly _tmp_args: Tweenany[] | Action[] [];private static _wrappedSequence (...args: Action[] | Tweenany[]): ActionInterval {const tmp_args Tween._tmp_args;tmp_args.length 0;for (let l args.length, i 0; i l; i) {const arg tmp_args[i] args[i];if (arg instanceof Tween) {tmp_args[i] arg._union();}}return sequence.apply(sequence, tmp_args as any);}private static _wrappedParallel (...args: Action[] | Tweenany[]): FiniteTimeAction {const tmp_args Tween._tmp_args;tmp_args.length 0;for (let l args.length, i 0; i l; i) {const arg tmp_args[i] args[i];if (arg instanceof Tween) {tmp_args[i] arg._union();}}return spawn.apply(spawn, tmp_args as any);}
}
cclegacy.Tween Tween;/*** en* tween is a utility function that helps instantiate Tween instances.* zh* tween 是一个工具函数帮助实例化 Tween 实例。* param target en The target of the result tween zh 缓动的目标* returns Tween 实例* example* tween(this.node)* .to(1, {scale: new Vec3(2, 2, 2), position: new Vec3(5, 5, 5)})* .call(() { log(This is a callback); })* .by(1, {scale: new Vec3(-1, -1, -1)}, {easing: sineOutIn})* .start()*/
export function tweenT (target?: T): TweenT {return new TweenT(target);
}
cclegacy.tween tween;/*** en* tweenUtil is a utility function that helps instantiate Tween instances.* zh* tweenUtil 是一个工具函数帮助实例化 Tween 实例。* deprecated please use tween instead.*/
export function tweenUtilT (target?: T): TweenT {warn(tweenUtil\ is deprecated, please use \tween\ instead );return new TweenT(target);
}
cclegacy.tweenUtil tweenUtil;
官方tween-action.ts源码:
/*Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.https://www.cocos.com/Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the Software), to dealin the Software without restriction, including without limitation the rights touse, copy, modify, merge, publish, distribute, sublicense, and/or sell copiesof the Software, and to permit persons to whom the Software is furnished to do so,subject to the following conditions:The above copyright notice and this permission notice shall be included inall copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INTHE SOFTWARE.
*/import { warnID, warn } from base/debug;
import { VERSION } from base/global;
import { easing } from ../core;
import { ActionInterval } from ./actions/action-interval;
import { ITweenOption } from ./export-api;/** adapter */
function TweenEasingAdapter (easingName: string): string {const initialChar easingName.charAt(0);if (/[A-Z]/.test(initialChar)) {easingName easingName.replace(initialChar, initialChar.toLowerCase());const arr easingName.split(-);if (arr.length 2) {const str0 arr[0];if (str0 linear) {easingName linear;} else {const str1 arr[1];switch (str0) {case quadratic:easingName quad${str1};break;case quartic:easingName quart${str1};break;case quintic:easingName quint${str1};break;case sinusoidal:easingName sine${str1};break;case exponential:easingName expo${str1};break;case circular:easingName circ${str1};break;default:easingName str0 str1;break;}}}}return easingName;
}/** checker */
function TweenOptionChecker (opts: ITweenOption): void {const header [Tween:] ;const message option is not support in v ${VERSION};const _opts opts as unknown as any;if (_opts.delay) {warn(${header}delay${message});}if (_opts.repeat) {warn(${header}repeat${message});}if (_opts.repeatDelay) {warn(${header}repeatDelay${message});}if (_opts.interpolation) {warn(${header}interpolation${message});}if (_opts.onStop) {warn(${header}onStop${message});}
}export class TweenAction extends ActionInterval {private _opts: any;private _props: any;private _originProps: any;constructor (duration: number, props: any, opts?: ITweenOption) {super();if (opts null) {opts Object.create(null);} else {/** checker */TweenOptionChecker(opts);/** adapter */if (opts.easing typeof opts.easing string) {opts.easing TweenEasingAdapter(opts.easing) as any;}// global easing or progress used for this actionif (!opts.progress) {opts.progress this.progress;}if (opts.easing typeof opts.easing string) {const easingName opts.easing as string;opts.easing easing[easingName];if (!opts.easing) { warnID(1031, easingName); }}}this._opts opts;this._props Object.create(null);for (const name in props) {// filtering if// - it was not own property// - types was function / string// - it was undefined / null// eslint-disable-next-line no-prototype-builtinsif (!props.hasOwnProperty(name)) continue;let value props[name];if (typeof value function) {value value();}if (value null || typeof value string) continue;// property may have custom easing or progress functionlet customEasing: any; let progress: any;if (value.value ! undefined (value.easing || value.progress)) {if (typeof value.easing string) {customEasing easing[value.easing];if (!customEasing) warnID(1031, value.easing);} else {customEasing value.easing;}progress value.progress;value value.value;}const prop Object.create(null);prop.value value;prop.easing customEasing;prop.progress progress;this._props[name] prop;}this._originProps props;this.initWithDuration(duration);}clone (): TweenAction {const action new TweenAction(this._duration, this._originProps, this._opts);this._cloneDecoration(action);return action;}startWithTarget (target: Recordstring, unknown): void {ActionInterval.prototype.startWithTarget.call(this, target);const relative !!this._opts.relative;const props this._props;for (const property in props) {const _t: any target[property];if (_t undefined) { continue; }const prop: any props[property];const value prop.value;if (typeof _t number) {prop.start _t;prop.current _t;// eslint-disable-next-line typescript-eslint/restrict-plus-operandsprop.end relative ? _t value : value;} else if (typeof _t object) {if (prop.start null) {prop.start {}; prop.current {}; prop.end {};}for (const k in value) {// filtering if it not a number// eslint-disable-next-line no-restricted-globalsif (isNaN(_t[k])) continue;prop.start[k] _t[k];prop.current[k] _t[k];// eslint-disable-next-line typescript-eslint/restrict-plus-operandsprop.end[k] relative ? _t[k] value[k] : value[k];}}}if (this._opts.onStart) { this._opts.onStart(this.target); }}update (t: number): void {const target this.target;if (!target) return;const props this._props;const opts this._opts;let easingTime t;if (opts.easing) easingTime opts.easing(t);const progress opts.progress;for (const name in props) {const prop props[name];const time prop.easing ? prop.easing(t) : easingTime;const interpolation prop.progress ? prop.progress : progress;const start prop.start;const end prop.end;if (typeof start number) {prop.current interpolation(start, end, prop.current, time);} else if (typeof start object) {// const value prop.value;for (const k in start) {// if (value[k].easing) {// time value[k].easing(t);// }// if (value[k].progress) {// interpolation value[k].easing(t);// }prop.current[k] interpolation(start[k], end[k], prop.current[k], time);}}target[name] prop.current;}if (opts.onUpdate) { opts.onUpdate(this.target, t); }if (t 1 opts.onComplete) { opts.onComplete(this.target); }}progress (start: number, end: number, current: number, t: number): number {return current start (end - start) * t;}
}