Skip to content

Commit

Permalink
Merge branch 'main' into dev/1.1
Browse files Browse the repository at this point in the history
* main:
  Fixed an issue where animation playback skipped the first frame (#1734)
  Fix the bug when user change speed direction in event handler (#1692)
  test(PrimitiveMesh): update unit test case of `PrimitiveMesh` (#1684)
  test(BufferMesh): update unit test case of (#1691)

# Conflicts:
#	packages/core/src/ComponentsManager.ts
#	packages/core/src/animation/Animator.ts
  • Loading branch information
GuoLei1990 committed Sep 7, 2023
2 parents 5f42181 + 17ec723 commit c4cbb2c
Show file tree
Hide file tree
Showing 5 changed files with 403 additions and 37 deletions.
16 changes: 6 additions & 10 deletions packages/core/src/ComponentsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Component } from "./Component";
import { DisorderedArray } from "./DisorderedArray";
import { Renderer } from "./Renderer";
import { Script } from "./Script";
import { Animator } from "./animation";

/**
* The manager of the components.
Expand All @@ -21,7 +22,7 @@ export class ComponentsManager {
private _disposeDestroyScripts: Script[] = [];

// Animation
private _onUpdateAnimations: DisorderedArray<Component> = new DisorderedArray();
private _onUpdateAnimations: DisorderedArray<Animator> = new DisorderedArray();

// Render
private _onUpdateRenderers: DisorderedArray<Renderer> = new DisorderedArray();
Expand Down Expand Up @@ -84,18 +85,14 @@ export class ComponentsManager {
script._onPhysicsUpdateIndex = -1;
}

addOnUpdateAnimations(animation: Component): void {
//@ts-ignore
addOnUpdateAnimations(animation: Animator): void {
animation._onUpdateIndex = this._onUpdateAnimations.length;
this._onUpdateAnimations.add(animation);
}

removeOnUpdateAnimations(animation: Component): void {
//@ts-ignore
removeOnUpdateAnimations(animation: Animator): void {
const replaced = this._onUpdateAnimations.deleteByIndex(animation._onUpdateIndex);
//@ts-ignore
replaced && (replaced._onUpdateIndex = animation._onUpdateIndex);
//@ts-ignore
animation._onUpdateIndex = -1;
}

Expand Down Expand Up @@ -151,9 +148,8 @@ export class ComponentsManager {
}

callAnimationUpdate(deltaTime: number): void {
this._onUpdateAnimations.forEach((element: Component) => {
//@ts-ignore
element.update(deltaTime);
this._onUpdateAnimations.forEach((element: Animator) => {
element.engine.time.frameCount > element._playFrameCount && element.update(deltaTime);
});
}

Expand Down
65 changes: 42 additions & 23 deletions packages/core/src/animation/Animator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export class Animator extends Component {
@assignmentClone
speed: number = 1.0;

/** @internal */
_playFrameCount: number;
/** @internal */
_onUpdateIndex: number = -1;

protected _animatorController: AnimatorController;

@ignoreClone
Expand Down Expand Up @@ -85,6 +90,8 @@ export class Animator extends Component {
this._reset();
}

this._playFrameCount = this.engine.time.frameCount;

const stateInfo = this._getAnimatorStateInfo(stateName, layerIndex);
const { state, layerIndex: playLayerIndex } = stateInfo;

Expand All @@ -103,6 +110,8 @@ export class Animator extends Component {

animatorLayerData.layerState = LayerState.Playing;
animatorLayerData.srcPlayData.reset(state, animatorStateData, state._getDuration() * normalizedTimeOffset);

this.update(0);
}

/**
Expand All @@ -122,12 +131,16 @@ export class Animator extends Component {
this._reset();
}

this._playFrameCount = this.engine.time.frameCount;

const { state, layerIndex: playLayerIndex } = this._getAnimatorStateInfo(stateName, layerIndex);
const { manuallyTransition } = this._getAnimatorLayerData(playLayerIndex);
manuallyTransition.duration = normalizedTransitionDuration;
manuallyTransition.offset = normalizedTimeOffset;
manuallyTransition.destinationState = state;
this._crossFadeByTransition(manuallyTransition, layerIndex);
if (this._crossFadeByTransition(manuallyTransition, layerIndex)) {
this.update(0);
}
}

/**
Expand Down Expand Up @@ -158,8 +171,6 @@ export class Animator extends Component {
return;
}

deltaTime *= this.speed;

this._updateMark++;

for (let i = 0, n = animatorController.layers.length; i < n; i++) {
Expand Down Expand Up @@ -448,7 +459,10 @@ export class Animator extends Component {
const { state, playState: lastPlayState, clipTime: lastClipTime } = playData;
const { _curveBindings: curveBindings } = state.clip;

playData.update(this.speed < 0);
const speed = state.speed * this.speed;
playData.frameTime += speed * delta;

playData.update(speed < 0);

const { clipTime, playState } = playData;
const finished = playState === AnimatorStatePlayState.Finished;
Expand All @@ -471,12 +485,9 @@ export class Animator extends Component {
}
}

playData.frameTime += state.speed * delta;

if (playState === AnimatorStatePlayState.Finished) {
layerData.layerState = LayerState.Finished;
}

eventHandlers.length && this._fireAnimationEvents(playData, eventHandlers, lastClipTime, clipTime);

if (lastPlayState === AnimatorStatePlayState.UnStarted) {
Expand All @@ -499,6 +510,7 @@ export class Animator extends Component {
additive: boolean,
aniUpdate: boolean
) {
const { speed } = this;
const { crossLayerOwnerCollection } = layerData;
const { _curveBindings: srcCurves } = srcPlayData.state.clip;
const { state: srcState, stateData: srcStateData, playState: lastSrcPlayState } = srcPlayData;
Expand All @@ -513,8 +525,14 @@ export class Animator extends Component {
let crossWeight = Math.abs(destPlayData.frameTime) / duration;
(crossWeight >= 1.0 || duration === 0) && (crossWeight = 1.0);

srcPlayData.update(this.speed < 0);
destPlayData.update(this.speed < 0);
const srcSpeed = srcState.speed * speed;
const destSpeed = destState.speed * speed;

srcPlayData.frameTime += srcSpeed * delta;
destPlayData.frameTime += destSpeed * delta;

srcPlayData.update(srcSpeed < 0);
destPlayData.update(destSpeed < 0);

const { clipTime: srcClipTime, playState: srcPlayState } = srcPlayData;
const { clipTime: destClipTime, playState: destPlayState } = destPlayData;
Expand Down Expand Up @@ -545,7 +563,7 @@ export class Animator extends Component {
}
}

this._updateCrossFadeData(layerData, crossWeight, delta, false);
this._updateCrossFadeData(layerData, crossWeight);

srcEventHandlers.length && this._fireAnimationEvents(srcPlayData, srcEventHandlers, lastSrcClipTime, srcClipTime);
destEventHandlers.length &&
Expand Down Expand Up @@ -589,13 +607,12 @@ export class Animator extends Component {
let crossWeight = Math.abs(destPlayData.frameTime) / duration;
(crossWeight >= 1.0 || duration === 0) && (crossWeight = 1.0);

destPlayData.update(this.speed < 0);

const { playState } = destPlayData;
const speed = state.speed * this.speed;

this._updateCrossFadeData(layerData, crossWeight, delta, true);
destPlayData.frameTime += speed * delta;
destPlayData.update(speed < 0);

const { clipTime: destClipTime } = destPlayData;
const { clipTime: destClipTime, playState } = destPlayData;
const finished = playState === AnimatorStatePlayState.Finished;

// When the animator is culled (aniUpdate=false), if the play state has finished, the final value needs to be calculated and saved to be applied directly.
Expand All @@ -621,6 +638,8 @@ export class Animator extends Component {
}
}

this._updateCrossFadeData(layerData, crossWeight);

//@todo: srcState is missing the judgment of the most recent period."
eventHandlers.length && this._fireAnimationEvents(destPlayData, eventHandlers, lastDestClipTime, destClipTime);

Expand Down Expand Up @@ -659,9 +678,8 @@ export class Animator extends Component {
}
}

private _updateCrossFadeData(layerData: AnimatorLayerData, crossWeight: number, delta: number, fixed: boolean): void {
private _updateCrossFadeData(layerData: AnimatorLayerData, crossWeight: number): void {
const { destPlayData } = layerData;
destPlayData.frameTime += destPlayData.state.speed * delta;
if (crossWeight === 1.0) {
if (destPlayData.playState === AnimatorStatePlayState.Finished) {
layerData.layerState = LayerState.Finished;
Expand All @@ -670,8 +688,6 @@ export class Animator extends Component {
}
layerData.switchPlayData();
layerData.crossFadeTransition = null;
} else {
fixed || (layerData.srcPlayData.frameTime += layerData.srcPlayData.state.speed * delta);
}
}

Expand Down Expand Up @@ -709,16 +725,16 @@ export class Animator extends Component {
}
}

private _crossFadeByTransition(transition: AnimatorStateTransition, layerIndex: number): void {
private _crossFadeByTransition(transition: AnimatorStateTransition, layerIndex: number): boolean {
const { name } = transition.destinationState;
const stateInfo = this._getAnimatorStateInfo(name, layerIndex);
const { state: crossState, layerIndex: playLayerIndex } = stateInfo;
if (!crossState) {
return;
return false;
}
if (!crossState.clip) {
Logger.warn(`The state named ${name} has no AnimationClip data.`);
return;
return false;
}

const animatorLayerData = this._getAnimatorLayerData(playLayerIndex);
Expand Down Expand Up @@ -752,6 +768,8 @@ export class Animator extends Component {
}

animatorLayerData.crossFadeTransition = transition;

return true;
}

private _fireAnimationEvents(
Expand All @@ -762,7 +780,8 @@ export class Animator extends Component {
): void {
const { state } = playState;
const clipDuration = state.clip.length;
if (this.speed >= 0) {

if (this.speed * state.speed >= 0) {
if (clipTime < lastClipTime) {
this._fireSubAnimationEvents(playState, eventHandlers, lastClipTime, state.clipEndTime * clipDuration);
playState.currentEventIndex = 0;
Expand Down
7 changes: 3 additions & 4 deletions tests/src/core/Animator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,17 @@ describe("Animator test", function () {
renderer._renderFrameCount = Infinity;
});

animator.cullingMode = 1;
expect(animator.cullingMode).to.eq(1);

animator.play("Run");

let animatorLayerData = animator["_animatorLayersData"];
const srcPlayData = animatorLayerData[0]?.srcPlayData;

animator.cullingMode = 1;
expect(animator.cullingMode).to.eq(1);
animator.update(5);
const curveOwner = srcPlayData.stateData.curveLayerOwner[0].curveOwner;
const initValue = curveOwner.defaultValue;
const currentValue = curveOwner.referenceTargetValue;

expect(Quaternion.equals(initValue, currentValue)).to.eq(true);

animator.cullingMode = 0;
Expand Down
Loading

0 comments on commit c4cbb2c

Please sign in to comment.