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
110 changes: 99 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 = '';
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 = 'color';
} 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 = '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 = 'vec2';
} else if (_t instanceof Vec3) {
if (prop.start == null) {
prop.start = new Vec3(); prop.current = new Vec3(); prop.end = new Vec3();
}
prop.type = 'vec3';
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
} else if (_t instanceof Vec4) {
if (prop.start == null) {
prop.start = new Vec4(); prop.current = new Vec4(); prop.end = new Vec4();
}
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 = '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
// 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,48 @@ 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 === '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 === '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 === '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 === '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 === '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 === '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 === 'quat') {
Quat.slerp(prop.current, start, end, time as number);
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
} 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
134 changes: 132 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,131 @@ test('destroySelf', function () {
game.step();
expect(onDestroy).toBeCalledTimes(1);
director.unregisterSystem(sys);
});

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});
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;
action.update(1.0);
zxx43 marked this conversation as resolved.
Show resolved Hide resolved
// @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
expect(Color.equals(prop.current, target)).toBeTruthy();
}
});

test('type quat', function () {
const node = new Node();
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 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 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 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 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 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();
}
});