Skip to content

Commit

Permalink
fixed #18000: [v3.8.5][bug] Nested tween with different target in par…
Browse files Browse the repository at this point in the history
…allel action could not work correctly.
  • Loading branch information
dumganhar committed Dec 4, 2024
1 parent b4a5a7c commit c1d5f01
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 75 deletions.
10 changes: 5 additions & 5 deletions cocos/tween/actions/action-instant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export abstract class ActionInstant extends FiniteTimeAction {
*/
export class Show<T extends Node> extends ActionInstant {
update (_dt: number): void {
const target = (this.workerTarget ?? this.target) as T;
const target = this._getWorkerTarget<T>();
if (!target) return;
const _renderComps = target.getComponentsInChildren(Renderer);
for (let i = 0; i < _renderComps.length; ++i) {
Expand Down Expand Up @@ -112,7 +112,7 @@ export function show<T extends Node> (): Show<T> {
*/
export class Hide<T extends Node> extends ActionInstant {
update (_dt: number): void {
const target = (this.workerTarget ?? this.target) as T;
const target = this._getWorkerTarget<T>();
if (!target) return;
const _renderComps = target.getComponentsInChildren(Renderer);
for (let i = 0; i < _renderComps.length; ++i) {
Expand Down Expand Up @@ -152,7 +152,7 @@ export function hide<T extends Node> (): Hide<T> {
*/
export class ToggleVisibility<T extends Node> extends ActionInstant {
update (_dt: number): void {
const target = (this.workerTarget ?? this.target) as T;
const target = this._getWorkerTarget<T>();
if (!target) return;
const _renderComps = target.getComponentsInChildren(Renderer);
for (let i = 0; i < _renderComps.length; ++i) {
Expand Down Expand Up @@ -204,7 +204,7 @@ export class RemoveSelf<T extends Node> extends ActionInstant {
}

update (_dt: number): void {
const target = (this.workerTarget ?? this.target) as T;
const target = this._getWorkerTarget<T>();
if (!target) return;
target.removeFromParent();
if (this._isNeedCleanUp) {
Expand Down Expand Up @@ -302,7 +302,7 @@ export class CallFunc<CallbackThis, Target, Data> extends ActionInstant {
*/
execute (): void {
if (this._callback) {
const target = (this.workerTarget ?? this.target) as Target;
const target = this._getWorkerTarget() as Target;
this._callback.call(this._callbackThis, target, this._data);
}
}
Expand Down
22 changes: 11 additions & 11 deletions cocos/tween/actions/action-interval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import { FiniteTimeAction } from './action';
import { macro, logID, errorID } from '../../core';
import { ActionInstant } from './action-instant';
import type { TweenUpdateCallback } from '../tween';
import type { Tween, TweenUpdateCallback } from '../tween';

// Extra action for making a Sequence or Spawn when only adding one action to it.
class DummyAction extends FiniteTimeAction {
Expand Down Expand Up @@ -351,16 +351,16 @@ export class Sequence extends ActionInterval {
return action;
}

updateWorkerTarget<T> (workerTarget: T): void {
updateOwner<T extends object> (owner: Tween<T>): void {
if (this._actions.length < 2) {
return;
}
this._actions[1].workerTarget = workerTarget;
this._actions[1]._owner = owner;
const actionOne = this._actions[0];
if (actionOne instanceof Sequence || actionOne instanceof Spawn) {
actionOne.updateWorkerTarget(workerTarget);
} else {
actionOne.workerTarget = workerTarget;
actionOne.updateOwner(owner);
} else if (!actionOne._owner) { // action's owner should never be changed, so only set owner when it's not set yet.
actionOne._owner = owner;
}
}

Expand Down Expand Up @@ -833,16 +833,16 @@ export class Spawn extends ActionInterval {
return this;
}

updateWorkerTarget<T> (workerTarget: T): void {
updateOwner<T extends object> (owner: Tween<T>): void {
if (!this._one || !this._two) {
return;
}
this._two.workerTarget = workerTarget;
this._two._owner = owner;
const one = this._one;
if (one instanceof Spawn || one instanceof Sequence) {
one.updateWorkerTarget(workerTarget);
} else {
one.workerTarget = workerTarget;
one.updateOwner(owner);
} else if (!one._owner) { // action's owner should never be changed, so only set owner when it's not set yet.
one._owner = owner;
}
}

Expand Down
83 changes: 46 additions & 37 deletions cocos/tween/actions/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
THE SOFTWARE.
*/

import type { Tween } from '../tween';

export enum ActionEnum {
/**
* @en Default Action tag.
Expand Down Expand Up @@ -54,44 +56,9 @@ export abstract class Action {
protected target: unknown = null;

/**
* The `workerTarget` was added from Cocos Creator 3.8.4 and it's used for nest `Tween` functionality.
* It stores the target of sub-tween and its value may be different from `target`.
*
* Example 1:
* ```ts
* tween(node).to(1, { scale: new Vec3(2, 2, 2) }).start();
* // target and original target are both `node`, workerTarget is `null`.
* ```
*
* Example 2:
* ```ts
* tween(node).parallel( // ----- Root tween
* tween(node).to(1, { scale: new Vec3(2, 2, 2) }), // ----- Sub tween 1
* tween(node).to(1, { position: new Vec3(10, 10, 10) }) // ----- Sub Tween 2
* ).start();
* // Note that only root tween is started here. We call tweens in `parallel`/`sequence` sub tweens.
* // The `target` and `originalTarget` of all internal actions are `node`.
* // Actions in root tween: workerTarget = null
* // Actions in sub tween 1: workerTarget = node
* // Actions in sub tween 2: workerTarget = node
* ```
*
* Example 3:
* ```ts
* tween(node).parallel( // ----- Root tween
* tween(node).to(1, { scale: new Vec3(2, 2, 2) }), // ----- Sub tween 1
* tween(node.getComponent(UITransform)).to(1, { // ----- Sub Tween 2
* contentSize: new Size(10, 10)
* })
* ).start();
* // Note that only root tween is started here. We call tweens in `parallel`/`sequence` sub tweens.
* // The `target` and `originalTarget` of all internal actions are `node`.
* // Actions in root tween: workerTarget = null
* // Actions in sub tween 1: workerTarget = node
* // Actions in sub tween 2: workerTarget = node's UITransform component
* ```
* The tween who owns this action.
*/
public workerTarget: unknown = null;
public _owner: Tween | null = null;

protected tag = ActionEnum.TAG_INVALID;

Expand Down Expand Up @@ -177,6 +144,48 @@ export abstract class Action {
this.originalTarget = originalTarget;
}

/**
* Return the worker target of the current action applys on.
*
* Example 1:
* ```ts
* tween(node).to(1, { scale: new Vec3(2, 2, 2) }).start();
* // target and original target are both `node`, _getWorkerTarget returns `null`.
* ```
*
* Example 2:
* ```ts
* tween(node).parallel( // ----- Root tween
* tween(node).to(1, { scale: new Vec3(2, 2, 2) }), // ----- Sub tween 1
* tween(node).to(1, { position: new Vec3(10, 10, 10) }) // ----- Sub Tween 2
* ).start();
* // Note that only root tween is started here. We call tweens in `parallel`/`sequence` sub tweens.
* // The `target` and `originalTarget` of all internal actions are `node`.
* // Actions in root tween: _getWorkerTarget returns `node`,
* // Actions in sub tween 1: _getWorkerTarget returns `node`,
* // Actions in sub tween 2: _getWorkerTarget returns `node`.
* ```
*
* Example 3:
* ```ts
* tween(node).parallel( // ----- Root tween
* tween(node).to(1, { scale: new Vec3(2, 2, 2) }), // ----- Sub tween 1
* tween(node.getComponent(UITransform)).to(1, { // ----- Sub Tween 2
* contentSize: new Size(10, 10)
* })
* ).start();
* // Note that only root tween is started here. We call tweens in `parallel`/`sequence` sub tweens.
* // The `target` and `originalTarget` of all internal actions are `node`.
* // Actions in root tween: workerTarget = `node`,
* // Actions in sub tween 1: workerTarget = `node`,
* // Actions in sub tween 2: workerTarget = `node`'s UITransform component.
* ```
*/
protected _getWorkerTarget<T> (): T | null {
const workerTarget: T | null = this._owner?.getTarget();
return (workerTarget ?? this.target) as T;
}

/**
* @en get tag number.
* @zh 获取用于识别动作的标签。
Expand Down
8 changes: 4 additions & 4 deletions cocos/tween/tween-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export class TweenAction<T extends object> extends ActionInterval {
clone (): TweenAction<T> {
const action = new TweenAction(this._duration, this._originProps, this._opts);
action._reversed = this._reversed;
action.workerTarget = this.workerTarget;
action._owner = this._owner;
action._id = this._id;
this._cloneDecoration(action);
return action;
Expand All @@ -220,7 +220,7 @@ export class TweenAction<T extends object> extends ActionInterval {
const action = new TweenAction(this._duration, this._originProps, this._opts);
this._cloneDecoration(action);
action._reversed = !this._reversed;
action.workerTarget = this.workerTarget;
action._owner = this._owner;
return action;
}

Expand All @@ -229,7 +229,7 @@ export class TweenAction<T extends object> extends ActionInterval {
if (!isEqual) return;
super.startWithTarget(target);

const workerTarget = (this.workerTarget ?? this.target) as T;
const workerTarget = this._getWorkerTarget<T>();
if (!workerTarget) return;
const relative = !!this._opts.relative;
const props = this._props;
Expand Down Expand Up @@ -355,7 +355,7 @@ export class TweenAction<T extends object> extends ActionInterval {
}

update (t: number): void {
const workerTarget = (this.workerTarget ?? this.target) as T;
const workerTarget = this._getWorkerTarget<T>();
if (!workerTarget) return;

if (!this._opts) return;
Expand Down
24 changes: 9 additions & 15 deletions cocos/tween/tween.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export class Tween<T extends object = any> {

if (action) {
reversedAction = action.reverse();
reversedAction.workerTarget = t._target;
reversedAction._owner = t;
} else {
warnID(16391, `${actionId}`);
}
Expand All @@ -259,17 +259,17 @@ export class Tween<T extends object = any> {
*/
private insertAction (other: FiniteTimeAction): Tween<T> {
const action = other.clone();
this.updateWorkerTargetForAction(action);
this.updateOwnerForAction(action);
this._actions.push(action);
return this;
}

private updateWorkerTargetForAction (action: Action | null): void {
private updateOwnerForAction (action: Action | null): void {
if (!action) return;
if (action instanceof Sequence || action instanceof Spawn) {
action.updateWorkerTarget(this._target);
} else {
action.workerTarget = this._target;
action.updateOwner(this);
} else if (!action._owner) { // action's owner should never be changed, so only set owner when it's not set yet.
action._owner = this;
}
}

Expand All @@ -284,12 +284,6 @@ export class Tween<T extends object = any> {
*/
target<U extends object = any> (target: U): Tween<U> {
(this as unknown as Tween<U>)._target = target;

for (let i = 0, len = this._actions.length; i < len; ++i) {
const action = this._actions[i];
this.updateWorkerTargetForAction(action);
}

return this as unknown as Tween<U>;
}

Expand Down Expand Up @@ -834,12 +828,12 @@ export class Tween<T extends object = any> {
TweenSystem.instance.ActionManager.resumeTarget(target);
}

private _union (updateWorkerTarget: boolean): Sequence | null {
private _union (needUpdateOwner: boolean): Sequence | null {
const actions = this._actions;
if (actions.length === 0) return null;
const action = sequence(actions);
if (updateWorkerTarget) {
this.updateWorkerTargetForAction(action);
if (needUpdateOwner) {
this.updateOwnerForAction(action);
}
return action;
}
Expand Down
Loading

0 comments on commit c1d5f01

Please sign in to comment.