From dadac83df5e04c1e376dcda468c67284f9119fc5 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 24 Aug 2023 15:00:54 +0800 Subject: [PATCH 01/12] fix tween color --- cocos/tween/tween-action.ts | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 4a5c80120d6..07a8b03d137 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -22,11 +22,15 @@ THE SOFTWARE. */ -import { warnID, warn, easing } from '../core'; +import { warnID, warn, easing, Color } from '../core'; import { ActionInterval } from './actions/action-interval'; import { ITweenOption } from './export-api'; import { VERSION } from '../core/global-exports'; +const colorStart: Color = new Color(); +const colorEnd: Color = new Color(); +const colorCur: Color = new Color(); + /** adapter */ function TweenEasingAdapter (easingName: string): string { const initialChar = easingName.charAt(0); @@ -134,6 +138,7 @@ export class TweenAction extends ActionInterval { value = value(); } if (value == null || typeof value === 'string') continue; + const valueType = value.constructor.name; // property may have custom easing or progress function let customEasing: any; let progress: any; if (value.value !== undefined && (value.easing || value.progress)) { @@ -149,6 +154,7 @@ export class TweenAction extends ActionInterval { const prop = Object.create(null); prop.value = value; + prop.valueType = valueType; prop.easing = customEasing; prop.progress = progress; this._props[name] = prop; @@ -218,7 +224,17 @@ export class TweenAction extends ActionInterval { const start = prop.start; const end = prop.end; if (typeof start === 'number') { - prop.current = interpolation(start, end, prop.current, time); + if (prop.valueType !== Color.name) { + prop.current = interpolation(start, end, prop.current, time); + } else { + colorStart.set(start); + colorEnd.set(end); + colorCur.r = interpolation(colorStart.r, colorEnd.r, colorCur.r, time); + colorCur.g = interpolation(colorStart.g, colorEnd.g, colorCur.g, time); + colorCur.b = interpolation(colorStart.b, colorEnd.b, colorCur.b, time); + colorCur.a = interpolation(colorStart.a, colorEnd.a, colorCur.a, time); + prop.current = colorCur._val; + } } else if (typeof start === 'object') { // const value = prop.value; for (const k in start) { @@ -228,7 +244,17 @@ export class TweenAction extends ActionInterval { // if (value[k].progress) { // interpolation = value[k].easing(t); // } - prop.current[k] = interpolation(start[k], end[k], prop.current[k], time); + if (prop.valueType !== Color.name) { + prop.current[k] = interpolation(start[k], end[k], prop.current[k], time); + } else { + colorStart.set(start[k]); + colorEnd.set(end[k]); + colorCur.r = interpolation(colorStart.r, colorEnd.r, colorCur.r, time); + colorCur.g = interpolation(colorStart.g, colorEnd.g, colorCur.g, time); + colorCur.b = interpolation(colorStart.b, colorEnd.b, colorCur.b, time); + colorCur.a = interpolation(colorStart.a, colorEnd.a, colorCur.a, time); + prop.current[k] = colorCur._val; + } } } From b7361bcc6cc2ebe0496db17bc12dcb04843eec24 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 24 Aug 2023 15:13:49 +0800 Subject: [PATCH 02/12] use instance of --- cocos/tween/tween-action.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 07a8b03d137..5686935f915 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -138,7 +138,7 @@ export class TweenAction extends ActionInterval { value = value(); } if (value == null || typeof value === 'string') continue; - const valueType = value.constructor.name; + const isColor = value instanceof Color; // property may have custom easing or progress function let customEasing: any; let progress: any; if (value.value !== undefined && (value.easing || value.progress)) { @@ -154,7 +154,7 @@ export class TweenAction extends ActionInterval { const prop = Object.create(null); prop.value = value; - prop.valueType = valueType; + prop.isColor = isColor; prop.easing = customEasing; prop.progress = progress; this._props[name] = prop; @@ -224,7 +224,7 @@ export class TweenAction extends ActionInterval { const start = prop.start; const end = prop.end; if (typeof start === 'number') { - if (prop.valueType !== Color.name) { + if (!prop.isColor) { prop.current = interpolation(start, end, prop.current, time); } else { colorStart.set(start); @@ -244,7 +244,7 @@ export class TweenAction extends ActionInterval { // if (value[k].progress) { // interpolation = value[k].easing(t); // } - if (prop.valueType !== Color.name) { + if (!prop.isColor) { prop.current[k] = interpolation(start[k], end[k], prop.current[k], time); } else { colorStart.set(start[k]); From 03d1009a5c149f034a1cf0c6b25870b0b5befbd3 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 24 Aug 2023 15:28:09 +0800 Subject: [PATCH 03/12] do not update color in loop --- cocos/tween/tween-action.ts | 40 ++++++++++++++----------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 5686935f915..52b70dcd7a5 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -224,36 +224,26 @@ export class TweenAction extends ActionInterval { const start = prop.start; const end = prop.end; if (typeof start === 'number') { - if (!prop.isColor) { - prop.current = interpolation(start, end, prop.current, time); - } else { - colorStart.set(start); - colorEnd.set(end); + prop.current = interpolation(start, end, prop.current, time); + } else if (typeof start === 'object') { + // const value = prop.value; + if (prop.isColor) { + colorStart.set(start._val); + colorEnd.set(end._val); colorCur.r = interpolation(colorStart.r, colorEnd.r, colorCur.r, time); colorCur.g = interpolation(colorStart.g, colorEnd.g, colorCur.g, time); colorCur.b = interpolation(colorStart.b, colorEnd.b, colorCur.b, time); colorCur.a = interpolation(colorStart.a, colorEnd.a, colorCur.a, time); - prop.current = colorCur._val; - } - } 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); - // } - if (!prop.isColor) { + prop.current._val = colorCur._val; + } else { + 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); - } else { - colorStart.set(start[k]); - colorEnd.set(end[k]); - colorCur.r = interpolation(colorStart.r, colorEnd.r, colorCur.r, time); - colorCur.g = interpolation(colorStart.g, colorEnd.g, colorCur.g, time); - colorCur.b = interpolation(colorStart.b, colorEnd.b, colorCur.b, time); - colorCur.a = interpolation(colorStart.a, colorEnd.a, colorCur.a, time); - prop.current[k] = colorCur._val; } } } From 0a2b682d9dab42be07199c0466bc116f2a5fbd90 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 24 Aug 2023 16:05:04 +0800 Subject: [PATCH 04/12] create color when start if input type is color --- cocos/tween/tween-action.ts | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 52b70dcd7a5..95116f628bb 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -27,10 +27,6 @@ import { ActionInterval } from './actions/action-interval'; import { ITweenOption } from './export-api'; import { VERSION } from '../core/global-exports'; -const colorStart: Color = new Color(); -const colorEnd: Color = new Color(); -const colorCur: Color = new Color(); - /** adapter */ function TweenEasingAdapter (easingName: string): string { const initialChar = easingName.charAt(0); @@ -186,6 +182,17 @@ export class TweenAction extends ActionInterval { prop.current = _t; // eslint-disable-next-line @typescript-eslint/restrict-plus-operands prop.end = relative ? _t + value : value; + } else if (_t instanceof Color) { + if (prop.start == null) { + prop.start = new Color(); prop.current = new Color(); prop.end = new Color(); + } + prop.start.set(_t); + prop.current.set(_t); + if (relative) { + Color.add(prop.end, _t, value); + } else { + prop.end.set(value); + } } else if (typeof _t === 'object') { if (prop.start == null) { prop.start = {}; prop.current = {}; prop.end = {}; @@ -223,18 +230,18 @@ export class TweenAction extends ActionInterval { const start = prop.start; const end = prop.end; + + console.log(prop.start, prop.end, prop.current); + if (typeof start === 'number') { prop.current = interpolation(start, end, prop.current, time); } else if (typeof start === 'object') { // const value = prop.value; if (prop.isColor) { - colorStart.set(start._val); - colorEnd.set(end._val); - colorCur.r = interpolation(colorStart.r, colorEnd.r, colorCur.r, time); - colorCur.g = interpolation(colorStart.g, colorEnd.g, colorCur.g, time); - colorCur.b = interpolation(colorStart.b, colorEnd.b, colorCur.b, time); - colorCur.a = interpolation(colorStart.a, colorEnd.a, colorCur.a, time); - prop.current._val = colorCur._val; + prop.current.r = interpolation(start.r, end.r, prop.current.r, time); + prop.current.g = interpolation(start.g, end.g, prop.current.g, time); + prop.current.b = interpolation(start.b, end.b, prop.current.b, time); + prop.current.a = interpolation(start.a, end.a, prop.current.a, time); } else { for (const k in start) { // if (value[k].easing) { From 5fc68cd1043eac18ce5f644a1fb1991059d7418e Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 24 Aug 2023 16:13:08 +0800 Subject: [PATCH 05/12] fix eslint --- cocos/tween/tween-action.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 95116f628bb..ac348e301bc 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -140,6 +140,7 @@ export class TweenAction extends ActionInterval { if (value.value !== undefined && (value.easing || value.progress)) { if (typeof value.easing === 'string') { customEasing = easing[value.easing]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument if (!customEasing) warnID(1031, value.easing); } else { customEasing = value.easing; @@ -161,6 +162,7 @@ export class TweenAction extends ActionInterval { } clone (): TweenAction { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const action = new TweenAction(this._duration, this._originProps, this._opts); this._cloneDecoration(action); return action; @@ -200,7 +202,7 @@ export class TweenAction extends ActionInterval { for (const k in value) { // filtering if it not a number - // eslint-disable-next-line no-restricted-globals + // eslint-disable-next-line no-restricted-globals, @typescript-eslint/no-unsafe-argument if (isNaN(_t[k])) continue; prop.start[k] = _t[k]; prop.current[k] = _t[k]; @@ -231,8 +233,6 @@ export class TweenAction extends ActionInterval { const start = prop.start; const end = prop.end; - console.log(prop.start, prop.end, prop.current); - if (typeof start === 'number') { prop.current = interpolation(start, end, prop.current, time); } else if (typeof start === 'object') { From 47b48ceca4601d653eff8bc80bbcad72fe7da29e Mon Sep 17 00:00:00 2001 From: zxx43 Date: Fri, 25 Aug 2023 17:11:29 +0800 Subject: [PATCH 06/12] tween other types --- cocos/tween/tween-action.ts | 78 ++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index ac348e301bc..96865fcc5ad 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -22,7 +22,7 @@ THE SOFTWARE. */ -import { warnID, warn, easing, Color } from '../core'; +import { warnID, warn, easing, Color, log, Vec2, Vec3, Vec4, Size, Quat, Rect } from '../core'; import { ActionInterval } from './actions/action-interval'; import { ITweenOption } from './export-api'; import { VERSION } from '../core/global-exports'; @@ -134,7 +134,6 @@ export class TweenAction extends ActionInterval { value = value(); } if (value == null || typeof value === 'string') continue; - const isColor = value instanceof Color; // property may have custom easing or progress function let customEasing: any; let progress: any; if (value.value !== undefined && (value.easing || value.progress)) { @@ -151,7 +150,7 @@ export class TweenAction extends ActionInterval { const prop = Object.create(null); prop.value = value; - prop.isColor = isColor; + prop.type = new Map(); prop.easing = customEasing; prop.progress = progress; this._props[name] = prop; @@ -195,8 +194,52 @@ export class TweenAction extends ActionInterval { } else { prop.end.set(value); } - } else if (typeof _t === 'object') { + prop.type.set('color', true); + } else if (_t instanceof Rect) { if (prop.start == null) { + prop.start = new Rect(); prop.current = new Rect(); prop.end = new Rect(); + } + prop.start.set(_t); + prop.current.set(_t); + if (relative) { + prop.end.xMin = _t.xMin + value.xMin; + prop.end.yMin = _t.yMin + value.yMin; + prop.end.z = _t.z + value.z; + prop.end.w = _t.w + value.w; + } else { + prop.end.xMin = value.xMin; + prop.end.yMin = value.yMin; + prop.end.z = value.z; + prop.end.w = value.w; + } + prop.type.set('rect', true); + } else if (typeof _t === 'object') { + if (_t instanceof Vec2) { + if (prop.start == null) { + prop.start = new Vec2(); prop.current = new Vec2(); prop.end = new Vec2(); + } + prop.type.set('vec2', true); + } else if (_t instanceof Vec3) { + if (prop.start == null) { + prop.start = new Vec3(); prop.current = new Vec3(); prop.end = new Vec3(); + } + prop.type.set('vec3', true); + } else if (_t instanceof Vec4) { + if (prop.start == null) { + prop.start = new Vec4(); prop.current = new Vec4(); prop.end = new Vec4(); + } + prop.type.set('vec4', true); + } else if (_t instanceof Size) { + if (prop.start == null) { + prop.start = new Size(); prop.current = new Size(); prop.end = new Size(); + } + prop.type.set('size', true); + } else if (_t instanceof Quat) { + if (prop.start == null) { + prop.start = new Quat(); prop.current = new Quat(); prop.end = new Quat(); + } + prop.type.set('quat', true); + } else if (prop.start == null) { prop.start = {}; prop.current = {}; prop.end = {}; } @@ -237,11 +280,36 @@ export class TweenAction extends ActionInterval { prop.current = interpolation(start, end, prop.current, time); } else if (typeof start === 'object') { // const value = prop.value; - if (prop.isColor) { + if (prop.type && prop.type.get('color')) { prop.current.r = interpolation(start.r, end.r, prop.current.r, time); prop.current.g = interpolation(start.g, end.g, prop.current.g, time); prop.current.b = interpolation(start.b, end.b, prop.current.b, time); prop.current.a = interpolation(start.a, end.a, prop.current.a, time); + } else if (prop.type && prop.type.get('rect')) { + prop.current.xMin = interpolation(start.xMin, end.xMin, prop.current.xMin, time); + prop.current.yMin = interpolation(start.yMin, end.yMin, prop.current.yMin, time); + prop.current.z = interpolation(start.z, end.z, prop.current.z, time); + prop.current.w = interpolation(start.w, end.w, prop.current.w, time); + } else if (prop.type && prop.type.get('vec2')) { + prop.current.x = interpolation(start.x, end.x, prop.current.x, time); + prop.current.y = interpolation(start.y, end.y, prop.current.y, time); + } else if (prop.type && prop.type.get('vec3')) { + prop.current.x = interpolation(start.x, end.x, prop.current.x, time); + prop.current.y = interpolation(start.y, end.y, prop.current.y, time); + prop.current.z = interpolation(start.z, end.z, prop.current.z, time); + } else if (prop.type && prop.type.get('vec4')) { + prop.current.x = interpolation(start.x, end.x, prop.current.x, time); + prop.current.y = interpolation(start.y, end.y, prop.current.y, time); + prop.current.z = interpolation(start.z, end.z, prop.current.z, time); + prop.current.w = interpolation(start.w, end.w, prop.current.w, time); + } else if (prop.type && prop.type.get('size')) { + prop.current.width = interpolation(start.width, end.width, prop.current.width, time); + prop.current.height = interpolation(start.height, end.height, prop.current.height, time); + } else if (prop.type && prop.type.get('quat')) { + prop.current.x = interpolation(start.x, end.x, prop.current.x, time); + prop.current.y = interpolation(start.y, end.y, prop.current.y, time); + prop.current.z = interpolation(start.z, end.z, prop.current.z, time); + prop.current.w = interpolation(start.w, end.w, prop.current.w, time); } else { for (const k in start) { // if (value[k].easing) { From 63a3fe2ca23bfb2ec7322ba5fdffcfe2f6960437 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Mon, 28 Aug 2023 17:05:31 +0800 Subject: [PATCH 07/12] add unit test --- tests/tween/tween.test.ts | 105 +++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/tests/tween/tween.test.ts b/tests/tween/tween.test.ts index 32e90d0048a..a1c457e619a 100644 --- a/tests/tween/tween.test.ts +++ b/tests/tween/tween.test.ts @@ -1,8 +1,11 @@ -import { Vec3, System } from "../../cocos/core"; -import { tween, Tween, TweenSystem } from "../../cocos/tween"; +import { Vec3, System, Color, Quat, Rect, Size, Vec2, Vec4 } from "../../cocos/core"; +import { tween, Tween, TweenAction, TweenSystem } from "../../cocos/tween"; import { Node, Scene } from "../../cocos/scene-graph"; import { Component } from "../../cocos/scene-graph/component"; import { game, director } from "../../cocos/game"; +import { CSMShadowLayer } from "../../cocos/rendering/shadow/csm-layers"; +import { Shadows } from "../../cocos/render-scene/scene"; +import { CameraComponent } from "../../cocos/misc"; test('remove actions by tag', function () { const scene = new Scene('test-tags'); @@ -38,4 +41,102 @@ test('destroySelf', function () { game.step(); expect(onDestroy).toBeCalledTimes(1); director.unregisterSystem(sys); +}); + +test('type color', function () { + const shadow = new Shadows(); + const tweenact = tween(shadow).to(1, {shadowColor: Color.TRANSPARENT}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Color).toBeTruthy(); + } +}); + +test('type quat', function () { + const node = new Node(); + const tweenact = tween(node).to(1, {rotation: new Quat(1, 1, 1, 1)}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Quat).toBeTruthy(); + } +}); + +test('type rect', function () { + const camera = new CameraComponent(); + const tweenact = tween(camera).to(1, {rect: new Rect(1, 1, 10, 20)}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Rect).toBeTruthy(); + } +}); + +test('type size', function () { + const rect = new Rect(); + const tweenact = tween(rect).to(1, {size: new Size(800, 600)}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Size).toBeTruthy(); + } +}); + +test('type vec2', function () { + const rect = new Rect(); + const tweenact = tween(rect).to(1, {origin: new Vec2(20, 10)}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Vec2).toBeTruthy(); + } +}); + +test('type vec3', function () { + const node = new Node(); + const tweenact = tween(node).to(1, {position: new Vec3(10, 20, 30)}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Vec3).toBeTruthy(); + } +}); + +test('type vec4', function () { + const shadowLayer = new CSMShadowLayer(4); + const tweenact = tween(shadowLayer).to(1, {csmAtlas: new Vec4(10, 20, 30, 40)}); + tweenact.start(); + // @ts-expect-error access private property + const action = tweenact._actions[0] as TweenAction; + // @ts-expect-error access private property + const props = action._props; + for (const property in props) { + const prop = props[property]; + expect(prop.current instanceof Vec4).toBeTruthy(); + } }); \ No newline at end of file From b2ae77941e403d5d8af397c85b4d7b140c972ed0 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Wed, 30 Aug 2023 18:16:49 +0800 Subject: [PATCH 08/12] use string to check tween type --- cocos/tween/tween-action.ts | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 96865fcc5ad..da6f06bf043 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -150,7 +150,7 @@ export class TweenAction extends ActionInterval { const prop = Object.create(null); prop.value = value; - prop.type = new Map(); + prop.type = ''; prop.easing = customEasing; prop.progress = progress; this._props[name] = prop; @@ -194,7 +194,7 @@ export class TweenAction extends ActionInterval { } else { prop.end.set(value); } - prop.type.set('color', true); + prop.type = 'color'; } else if (_t instanceof Rect) { if (prop.start == null) { prop.start = new Rect(); prop.current = new Rect(); prop.end = new Rect(); @@ -212,33 +212,33 @@ export class TweenAction extends ActionInterval { prop.end.z = value.z; prop.end.w = value.w; } - prop.type.set('rect', true); + prop.type = 'rect'; } else if (typeof _t === 'object') { if (_t instanceof Vec2) { if (prop.start == null) { prop.start = new Vec2(); prop.current = new Vec2(); prop.end = new Vec2(); } - prop.type.set('vec2', true); + prop.type = 'vec2'; } else if (_t instanceof Vec3) { if (prop.start == null) { prop.start = new Vec3(); prop.current = new Vec3(); prop.end = new Vec3(); } - prop.type.set('vec3', true); + prop.type = 'vec3'; } else if (_t instanceof Vec4) { if (prop.start == null) { prop.start = new Vec4(); prop.current = new Vec4(); prop.end = new Vec4(); } - prop.type.set('vec4', true); + prop.type = 'vec4'; } else if (_t instanceof Size) { if (prop.start == null) { prop.start = new Size(); prop.current = new Size(); prop.end = new Size(); } - prop.type.set('size', true); + prop.type = 'size'; } else if (_t instanceof Quat) { if (prop.start == null) { prop.start = new Quat(); prop.current = new Quat(); prop.end = new Quat(); } - prop.type.set('quat', true); + prop.type = 'quat'; } else if (prop.start == null) { prop.start = {}; prop.current = {}; prop.end = {}; } @@ -280,36 +280,33 @@ export class TweenAction extends ActionInterval { prop.current = interpolation(start, end, prop.current, time); } else if (typeof start === 'object') { // const value = prop.value; - if (prop.type && prop.type.get('color')) { + if (prop.type && prop.type === 'color') { prop.current.r = interpolation(start.r, end.r, prop.current.r, time); prop.current.g = interpolation(start.g, end.g, prop.current.g, time); prop.current.b = interpolation(start.b, end.b, prop.current.b, time); prop.current.a = interpolation(start.a, end.a, prop.current.a, time); - } else if (prop.type && prop.type.get('rect')) { + } else if (prop.type && prop.type === 'rect') { prop.current.xMin = interpolation(start.xMin, end.xMin, prop.current.xMin, time); prop.current.yMin = interpolation(start.yMin, end.yMin, prop.current.yMin, time); prop.current.z = interpolation(start.z, end.z, prop.current.z, time); prop.current.w = interpolation(start.w, end.w, prop.current.w, time); - } else if (prop.type && prop.type.get('vec2')) { + } else if (prop.type && prop.type === 'vec2') { prop.current.x = interpolation(start.x, end.x, prop.current.x, time); prop.current.y = interpolation(start.y, end.y, prop.current.y, time); - } else if (prop.type && prop.type.get('vec3')) { + } else if (prop.type && prop.type === 'vec3') { prop.current.x = interpolation(start.x, end.x, prop.current.x, time); prop.current.y = interpolation(start.y, end.y, prop.current.y, time); prop.current.z = interpolation(start.z, end.z, prop.current.z, time); - } else if (prop.type && prop.type.get('vec4')) { + } else if (prop.type && prop.type === 'vec4') { prop.current.x = interpolation(start.x, end.x, prop.current.x, time); prop.current.y = interpolation(start.y, end.y, prop.current.y, time); prop.current.z = interpolation(start.z, end.z, prop.current.z, time); prop.current.w = interpolation(start.w, end.w, prop.current.w, time); - } else if (prop.type && prop.type.get('size')) { + } else if (prop.type && prop.type === 'size') { prop.current.width = interpolation(start.width, end.width, prop.current.width, time); prop.current.height = interpolation(start.height, end.height, prop.current.height, time); - } else if (prop.type && prop.type.get('quat')) { - prop.current.x = interpolation(start.x, end.x, prop.current.x, time); - prop.current.y = interpolation(start.y, end.y, prop.current.y, time); - prop.current.z = interpolation(start.z, end.z, prop.current.z, time); - prop.current.w = interpolation(start.w, end.w, prop.current.w, time); + } else if (prop.type && prop.type === 'quat') { + Quat.slerp(prop.current, start, end, time as number); } else { for (const k in start) { // if (value[k].easing) { From 97d6c658eb4ce7e194b5b9408914690d76c3f64f Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 31 Aug 2023 14:46:42 +0800 Subject: [PATCH 09/12] add tween result compare case --- tests/tween/tween.test.ts | 45 ++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/tests/tween/tween.test.ts b/tests/tween/tween.test.ts index a1c457e619a..6bf67c57aed 100644 --- a/tests/tween/tween.test.ts +++ b/tests/tween/tween.test.ts @@ -45,98 +45,127 @@ test('destroySelf', function () { test('type color', function () { const shadow = new Shadows(); - const tweenact = tween(shadow).to(1, {shadowColor: Color.TRANSPARENT}); + shadow.shadowColor.set(200, 100, 50, 250); + const target = Color.TRANSPARENT; + const tweenact = tween(shadow).to(1, {shadowColor: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Color).toBeTruthy(); + expect(Color.equals(prop.current, target)).toBeTruthy(); } }); test('type quat', function () { const node = new Node(); - const tweenact = tween(node).to(1, {rotation: new Quat(1, 1, 1, 1)}); + const target = new Quat(1, 1, 1, 1); + const tweenact = tween(node).to(1, {rotation: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Quat).toBeTruthy(); + expect(Quat.equals(prop.current, target)).toBeTruthy(); } }); test('type rect', function () { const camera = new CameraComponent(); - const tweenact = tween(camera).to(1, {rect: new Rect(1, 1, 10, 20)}); + const target = new Rect(1, 1, 10, 20); + const tweenact = tween(camera).to(1, {rect: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Rect).toBeTruthy(); + expect(Rect.equals(prop.current, target)).toBeTruthy(); } }); test('type size', function () { const rect = new Rect(); - const tweenact = tween(rect).to(1, {size: new Size(800, 600)}); + const target = new Size(800, 600); + const tweenact = tween(rect).to(1, {size: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Size).toBeTruthy(); + expect(Rect.equals(prop.current, target)).toBeTruthy(); } }); test('type vec2', function () { const rect = new Rect(); - const tweenact = tween(rect).to(1, {origin: new Vec2(20, 10)}); + const target = new Vec2(20, 10); + const tweenact = tween(rect).to(1, {origin: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Vec2).toBeTruthy(); + expect(Vec2.equals(prop.current, target)).toBeTruthy(); } }); test('type vec3', function () { const node = new Node(); - const tweenact = tween(node).to(1, {position: new Vec3(10, 20, 30)}); + const target = new Vec3(10, 20, 30); + const tweenact = tween(node).to(1, {position: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Vec3).toBeTruthy(); - } + expect(Vec3.equals(prop.current, target)).toBeTruthy(); + } }); test('type vec4', function () { const shadowLayer = new CSMShadowLayer(4); - const tweenact = tween(shadowLayer).to(1, {csmAtlas: new Vec4(10, 20, 30, 40)}); + const target = new Vec4(10, 20, 30, 40); + const tweenact = tween(shadowLayer).to(1, {csmAtlas: target}); tweenact.start(); + // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; + action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Vec4).toBeTruthy(); + expect(Vec4.equals(prop.current, target)).toBeTruthy(); } }); \ No newline at end of file From decd41297c9bec5ee7bd4fc9e5a1f385596e870c Mon Sep 17 00:00:00 2001 From: zxx43 Date: Wed, 13 Sep 2023 17:01:52 +0800 Subject: [PATCH 10/12] modify unit test --- cocos/tween/tween-action.ts | 28 ++++++++------- tests/tween/tween.test.ts | 71 +++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index da6f06bf043..7d1595c1ca7 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -213,6 +213,19 @@ export class TweenAction extends ActionInterval { prop.end.w = value.w; } prop.type = 'rect'; + } else if (_t instanceof Quat) { + if (prop.start == null) { + prop.start = new Quat(); prop.current = new Quat(); prop.end = new Quat(); + } + prop.start.set(_t); + prop.current.set(_t); + if (relative) { + Quat.multiply(prop.end, _t, value); + } else { + prop.end.set(value); + } + prop.type = 'quat'; + warn('Quaternion only support slerp interpolation method.'); } else if (typeof _t === 'object') { if (_t instanceof Vec2) { if (prop.start == null) { @@ -234,19 +247,14 @@ export class TweenAction extends ActionInterval { prop.start = new Size(); prop.current = new Size(); prop.end = new Size(); } prop.type = 'size'; - } else if (_t instanceof Quat) { - if (prop.start == null) { - prop.start = new Quat(); prop.current = new Quat(); prop.end = new Quat(); - } - prop.type = 'quat'; } else 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-globals, @typescript-eslint/no-unsafe-argument - if (isNaN(_t[k])) continue; + // eslint-disable-next-line no-restricted-globals + if (isNaN(_t[k] as number)) continue; prop.start[k] = _t[k]; prop.current[k] = _t[k]; // eslint-disable-next-line @typescript-eslint/restrict-plus-operands @@ -309,12 +317,6 @@ export class TweenAction extends ActionInterval { Quat.slerp(prop.current, start, end, time as number); } else { 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); } } diff --git a/tests/tween/tween.test.ts b/tests/tween/tween.test.ts index 6bf67c57aed..995d059c8f3 100644 --- a/tests/tween/tween.test.ts +++ b/tests/tween/tween.test.ts @@ -44,15 +44,21 @@ test('destroySelf', function () { }); test('type color', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const shadow = new Shadows(); shadow.shadowColor.set(200, 100, 50, 250); const target = Color.TRANSPARENT; const tweenact = tween(shadow).to(1, {shadowColor: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { @@ -60,17 +66,24 @@ test('type color', function () { expect(prop.current instanceof Color).toBeTruthy(); expect(Color.equals(prop.current, target)).toBeTruthy(); } + director.unregisterSystem(sys); }); test('type quat', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const node = new Node(); const target = new Quat(1, 1, 1, 1); const tweenact = tween(node).to(1, {rotation: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { @@ -78,71 +91,99 @@ test('type quat', function () { expect(prop.current instanceof Quat).toBeTruthy(); expect(Quat.equals(prop.current, target)).toBeTruthy(); } + director.unregisterSystem(sys); }); test('type rect', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const camera = new CameraComponent(); const target = new Rect(1, 1, 10, 20); const tweenact = tween(camera).to(1, {rect: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Rect).toBeTruthy(); expect(Rect.equals(prop.current, target)).toBeTruthy(); - } + } + director.unregisterSystem(sys); }); test('type size', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const rect = new Rect(); const target = new Size(800, 600); const tweenact = tween(rect).to(1, {size: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Size).toBeTruthy(); expect(Rect.equals(prop.current, target)).toBeTruthy(); - } + } + director.unregisterSystem(sys); }); test('type vec2', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const rect = new Rect(); const target = new Vec2(20, 10); const tweenact = tween(rect).to(1, {origin: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Vec2).toBeTruthy(); expect(Vec2.equals(prop.current, target)).toBeTruthy(); - } + } + director.unregisterSystem(sys); }); test('type vec3', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const node = new Node(); const target = new Vec3(10, 20, 30); const tweenact = tween(node).to(1, {position: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { @@ -150,22 +191,30 @@ test('type vec3', function () { expect(prop.current instanceof Vec3).toBeTruthy(); expect(Vec3.equals(prop.current, target)).toBeTruthy(); } + director.unregisterSystem(sys); }); test('type vec4', function () { + const sys = new TweenSystem(); + (TweenSystem.instance as any) = sys; + director.registerSystem(TweenSystem.ID, sys, System.Priority.MEDIUM); + const shadowLayer = new CSMShadowLayer(4); const target = new Vec4(10, 20, 30, 40); const tweenact = tween(shadowLayer).to(1, {csmAtlas: target}); tweenact.start(); + for (let i = 0; i < 100; ++i) { + game.step(); + } // @ts-expect-error access private property const action = tweenact._actions[0] as TweenAction; - action.update(1.0); // @ts-expect-error access private property const props = action._props; for (const property in props) { const prop = props[property]; expect(prop.current instanceof Vec4).toBeTruthy(); expect(Vec4.equals(prop.current, target)).toBeTruthy(); - } + } + director.unregisterSystem(sys); }); \ No newline at end of file From c6e922c4c899270934aa378f8d59f1f9d40bedd6 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Wed, 13 Sep 2023 17:38:05 +0800 Subject: [PATCH 11/12] add quat warning when not use default interpolation function --- cocos/tween/tween-action.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cocos/tween/tween-action.ts b/cocos/tween/tween-action.ts index 7d1595c1ca7..40b0a067481 100644 --- a/cocos/tween/tween-action.ts +++ b/cocos/tween/tween-action.ts @@ -225,7 +225,6 @@ export class TweenAction extends ActionInterval { prop.end.set(value); } prop.type = 'quat'; - warn('Quaternion only support slerp interpolation method.'); } else if (typeof _t === 'object') { if (_t instanceof Vec2) { if (prop.start == null) { @@ -315,6 +314,9 @@ export class TweenAction extends ActionInterval { prop.current.height = interpolation(start.height, end.height, prop.current.height, time); } else if (prop.type && prop.type === 'quat') { Quat.slerp(prop.current, start, end, time as number); + if (prop.progress) { + warn('Quaternion only support slerp interpolation method.'); + } } else { for (const k in start) { prop.current[k] = interpolation(start[k], end[k], prop.current[k], time); From 60efff12ea44954f99aeedc617c18ec461fda325 Mon Sep 17 00:00:00 2001 From: zxx43 Date: Thu, 14 Sep 2023 17:38:32 +0800 Subject: [PATCH 12/12] add easing in unit test --- tests/tween/tween.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/tween/tween.test.ts b/tests/tween/tween.test.ts index 995d059c8f3..70019041dd2 100644 --- a/tests/tween/tween.test.ts +++ b/tests/tween/tween.test.ts @@ -51,7 +51,7 @@ test('type color', function () { const shadow = new Shadows(); shadow.shadowColor.set(200, 100, 50, 250); const target = Color.TRANSPARENT; - const tweenact = tween(shadow).to(1, {shadowColor: target}); + const tweenact = tween(shadow).to(1, {shadowColor: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) { @@ -76,7 +76,7 @@ test('type quat', function () { const node = new Node(); const target = new Quat(1, 1, 1, 1); - const tweenact = tween(node).to(1, {rotation: target}); + const tweenact = tween(node).to(1, {rotation: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) { @@ -101,7 +101,7 @@ test('type rect', function () { const camera = new CameraComponent(); const target = new Rect(1, 1, 10, 20); - const tweenact = tween(camera).to(1, {rect: target}); + const tweenact = tween(camera).to(1, {rect: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) { @@ -126,7 +126,7 @@ test('type size', function () { const rect = new Rect(); const target = new Size(800, 600); - const tweenact = tween(rect).to(1, {size: target}); + const tweenact = tween(rect).to(1, {size: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) { @@ -151,7 +151,7 @@ test('type vec2', function () { const rect = new Rect(); const target = new Vec2(20, 10); - const tweenact = tween(rect).to(1, {origin: target}); + const tweenact = tween(rect).to(1, {origin: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) { @@ -176,7 +176,7 @@ test('type vec3', function () { const node = new Node(); const target = new Vec3(10, 20, 30); - const tweenact = tween(node).to(1, {position: target}); + const tweenact = tween(node).to(1, {position: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) { @@ -201,7 +201,7 @@ test('type vec4', function () { const shadowLayer = new CSMShadowLayer(4); const target = new Vec4(10, 20, 30, 40); - const tweenact = tween(shadowLayer).to(1, {csmAtlas: target}); + const tweenact = tween(shadowLayer).to(1, {csmAtlas: target}, { easing: "bounceOut" }); tweenact.start(); for (let i = 0; i < 100; ++i) {