Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix tween color #16090

Closed
wants to merge 12 commits into from
113 changes: 102 additions & 11 deletions cocos/tween/tween-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
THE SOFTWARE.
*/

import { warnID, warn, easing } 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';
Expand Down Expand Up @@ -139,6 +139,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;
Expand All @@ -149,6 +150,7 @@ export class TweenAction extends ActionInterval {

const prop = Object.create(null);
prop.value = value;
prop.type = new Map<string, boolean>();
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
prop.easing = customEasing;
prop.progress = progress;
this._props[name] = prop;
Expand All @@ -159,6 +161,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;
Expand All @@ -180,14 +183,69 @@ 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 (typeof _t === 'object') {
} 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);
}
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 = {};
}

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];
Expand Down Expand Up @@ -217,18 +275,51 @@ 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);
} 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);
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);
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
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) {
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
// 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);
}
}
}

Expand Down
105 changes: 103 additions & 2 deletions tests/tween/tween.test.ts
Original file line number Diff line number Diff line change
@@ -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');
Expand Down Expand Up @@ -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();
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
// @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();
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
}
});

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();
}
});