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

Add hasExitTime and fix error when set state startTime and transition duration is 0 #2359

Merged
merged 27 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0a2b927
fix: animation error when set state startTime and transition duration…
luzhuang Aug 16, 2024
3f8e950
test: add ut
luzhuang Aug 16, 2024
58f4e03
feat: opt comment
luzhuang Aug 16, 2024
4bff236
feat: add hasExitTime, fixedDuration, setTrigger
luzhuang Aug 21, 2024
c4ba1e3
feat: opt code
luzhuang Aug 21, 2024
9e9d6da
Merge commit refs/pull/2337/head of github.com:oasis-engine/engine in…
luzhuang Aug 21, 2024
5a4243b
feat: opt code
luzhuang Aug 21, 2024
2618b14
test: add ut
luzhuang Aug 21, 2024
0dce44f
feat: opt code
luzhuang Aug 21, 2024
bcca797
feat: update animatorController loader
luzhuang Aug 21, 2024
e127b27
feat: add hasExitTime and fix error when set state startTime and tran…
luzhuang Aug 26, 2024
8e7e20a
feat: opt code
luzhuang Aug 26, 2024
2dfed41
feat: opt code
luzhuang Aug 26, 2024
b4712af
feat: opt code
luzhuang Aug 26, 2024
562b900
feat: opt code
luzhuang Aug 28, 2024
64d825e
fix: stateMachine transition index error and solo check error
luzhuang Aug 28, 2024
5ddc513
feat: opt code
luzhuang Aug 28, 2024
66bc753
feat: opt code
luzhuang Aug 28, 2024
9f59d49
feat: opt code
luzhuang Aug 29, 2024
e3ef464
feat: opt code
GuoLei1990 Sep 10, 2024
69ee2c4
feat: opt code
GuoLei1990 Sep 10, 2024
2e63e45
refactor: opt code
GuoLei1990 Sep 10, 2024
c7cc55a
refactor: opt code
GuoLei1990 Sep 10, 2024
0027bbe
refactor: opt code
luzhuang Sep 11, 2024
ee324ad
refactor: opt code
GuoLei1990 Sep 11, 2024
e7f3805
refactor: opt code
GuoLei1990 Sep 11, 2024
e684bd1
refactor: opt code
GuoLei1990 Sep 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 123 additions & 51 deletions packages/core/src/animation/Animator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AnimatorController } from "./AnimatorController";
import { AnimatorControllerLayer } from "./AnimatorControllerLayer";
import { AnimatorControllerParameter, AnimatorControllerParameterValue } from "./AnimatorControllerParameter";
import { AnimatorState } from "./AnimatorState";
import { AnimatorStateMachine } from "./AnimatorStateMachine";
import { AnimatorStateTransition } from "./AnimatorStateTransition";
import { KeyframeValueType } from "./Keyframe";
import { AnimatorConditionMode } from "./enums/AnimatorConditionMode";
Expand Down Expand Up @@ -553,7 +554,19 @@ export class Animator extends Component {

const transition =
(anyStateTransitions.length &&
this._applyTransitionsByCondition(layerIndex, layerData, layer, state, anyStateTransitions, aniUpdate)) ||
this._applyStateTransitions(
layerIndex,
layerData,
layer,
isForwards,
srcPlayData,
anyStateTransitions,
lastClipTime,
clipTime,
playDeltaTime,
true,
aniUpdate
)) ||
(transitions.length &&
this._applyStateTransitions(
layerIndex,
Expand All @@ -565,29 +578,35 @@ export class Animator extends Component {
lastClipTime,
clipTime,
playDeltaTime,
false,
aniUpdate
));

let playCostTime: number;
if (transition) {
const clipDuration = state.clip.length;
const clipEndTime = state.clipEndTime * clipDuration;
const exitTime = transition.exitTime * state._getDuration();

if (isForwards) {
if (exitTime < lastClipTime) {
playCostTime = exitTime + clipEndTime - lastClipTime;
if (transition.hasExitTime) {
const exitTime = transition.exitTime * state._getDuration();

if (isForwards) {
if (exitTime < lastClipTime) {
playCostTime = exitTime + clipEndTime - lastClipTime;
} else {
playCostTime = exitTime - lastClipTime;
}
} else {
playCostTime = exitTime - lastClipTime;
const startTime = state.clipStartTime * clipDuration;
if (lastClipTime < exitTime) {
playCostTime = clipEndTime - exitTime + lastClipTime - startTime;
} else {
playCostTime = lastClipTime - exitTime;
}
playCostTime = -playCostTime;
}
} else {
const startTime = state.clipStartTime * clipDuration;
if (lastClipTime < exitTime) {
playCostTime = clipEndTime - exitTime + lastClipTime - startTime;
} else {
playCostTime = lastClipTime - exitTime;
}
playCostTime = -playCostTime;
playCostTime = 0;
}
// Revert actualDeltaTime and update playCostTime
srcPlayData.update(playCostTime - playDeltaTime);
Expand Down Expand Up @@ -667,15 +686,15 @@ export class Animator extends Component {

let dstPlayCostTime: number;
if (destPlayData.isForwards) {
// The time that has been played
const playedTime = lastDestClipTime - destState.clipStartTime * destState.clip.length;
dstPlayCostTime =
lastDestClipTime + dstPlayDeltaTime > transitionDuration
? transitionDuration - lastDestClipTime
: dstPlayDeltaTime;
playedTime + dstPlayDeltaTime > transitionDuration ? transitionDuration - playedTime : dstPlayDeltaTime;
} else {
// The time that has been played
const playedTime = destStateDuration - lastDestClipTime;
const playedTime = destState.clipEndTime * destState.clip.length - lastDestClipTime;
dstPlayCostTime =
// -actualDestDeltaTime: The time that will be played, negative are meant to make ite be a periods
// -dstPlayDeltaTime: The time that will be played, negative are meant to make it be a periods
// > transition: The time that will be played is enough to finish the transition
playedTime - dstPlayDeltaTime > transitionDuration
? // Negative number is used to convert a time period into a reverse deltaTime.
Expand Down Expand Up @@ -800,7 +819,7 @@ export class Animator extends Component {
// The time that has been played
const playedTime = stateDuration - lastDestClipTime;
dstPlayCostTime =
// -actualDestDeltaTime: The time that will be played, negative are meant to make ite be a periods
// -playDeltaTime: The time that will be played, negative are meant to make it be a periods
// > transition: The time that will be played is enough to finish the transition
playedTime - playDeltaTime > transitionDuration
? // Negative number is used to convert a time period into a reverse deltaTime.
Expand Down Expand Up @@ -889,7 +908,6 @@ export class Animator extends Component {
deltaTime: number,
aniUpdate: boolean
): void {
const { stateMachine } = layer;
const playData = layerData.srcPlayData;
const { state } = playData;
const actualSpeed = state.speed * this.speed;
Expand All @@ -903,7 +921,7 @@ export class Animator extends Component {

const transition =
(anyStateTransitions.length &&
this._applyTransitionsByCondition(layerIndex, layerData, layer, state, anyStateTransitions, aniUpdate)) ||
this._applyTransitionsByCondition(layerIndex, layerData, layer, state, anyStateTransitions, true, aniUpdate)) ||
(transitions.length &&
this._applyStateTransitions(
layerIndex,
Expand All @@ -915,6 +933,7 @@ export class Animator extends Component {
clipTime,
clipTime,
actualDeltaTime,
false,
aniUpdate
));

Expand Down Expand Up @@ -983,14 +1002,15 @@ export class Animator extends Component {
layerData: AnimatorLayerData,
layer: AnimatorControllerLayer,
isForwards: boolean,
playState: AnimatorStatePlayData,
playData: AnimatorStatePlayData,
transitions: Readonly<AnimatorStateTransition[]>,
lastClipTime: number,
clipTime: number,
deltaTime: number,
checkStateMachineTransition: boolean,
aniUpdate: boolean
): AnimatorStateTransition {
const { state } = playState;
const { state } = playData;
const clipDuration = state.clip.length;
let targetTransition: AnimatorStateTransition = null;
const startTime = state.clipStartTime * clipDuration;
Expand All @@ -1001,22 +1021,28 @@ export class Animator extends Component {
layerIndex,
layerData,
layer,
playState,
playData,
transitions,
lastClipTime,
endTime,
checkStateMachineTransition,
aniUpdate
);
if (!targetTransition) {
playState.currentTransitionIndex = 0;
if (checkStateMachineTransition) {
layerData.anyTransitionIndex = 0;
} else {
playData.currentTransitionIndex = 0;
}
targetTransition = this._checkSubTransition(
layerIndex,
layerData,
layer,
playState,
playData,
transitions,
startTime,
clipTime,
checkStateMachineTransition,
aniUpdate
);
}
Expand All @@ -1025,35 +1051,43 @@ export class Animator extends Component {
layerIndex,
layerData,
layer,
playState,
playData,
transitions,
lastClipTime,
clipTime,
checkStateMachineTransition,
aniUpdate
);
}
} else {
//@todo backwards play currentIndex should not be 0
if (lastClipTime + deltaTime <= startTime) {
targetTransition = this._checkBackwardsSubTransition(
layerIndex,
layerData,
layer,
playState,
playData,
transitions,
lastClipTime,
startTime,
checkStateMachineTransition,
aniUpdate
);
if (!targetTransition) {
playState.currentTransitionIndex = transitions.length - 1;
if (checkStateMachineTransition) {
layerData.anyTransitionIndex = transitions.length - 1;
} else {
playData.currentTransitionIndex = transitions.length - 1;
}
targetTransition = this._checkBackwardsSubTransition(
layerIndex,
layerData,
layer,
playState,
playData,
transitions,
clipTime,
endTime,
checkStateMachineTransition,
aniUpdate
);
}
Expand All @@ -1062,10 +1096,11 @@ export class Animator extends Component {
layerIndex,
layerData,
layer,
playState,
playData,
transitions,
lastClipTime,
clipTime,
checkStateMachineTransition,
aniUpdate
);
}
Expand All @@ -1078,25 +1113,39 @@ export class Animator extends Component {
layerIndex: number,
layerData: AnimatorLayerData,
layer: AnimatorControllerLayer,
playState: AnimatorStatePlayData,
playData: AnimatorStatePlayData,
transitions: Readonly<AnimatorStateTransition[]>,
lastClipTime: number,
curClipTime: number,
checkStateMachineTransition: boolean,
aniUpdate: boolean
): AnimatorStateTransition {
const { state } = playState;
let transitionIndex = playState.currentTransitionIndex;
const { state } = playData;
let transitionIndex = checkStateMachineTransition ? layerData.anyTransitionIndex : playData.currentTransitionIndex;
const duration = state._getDuration();
for (let n = transitions.length; transitionIndex < n; transitionIndex++) {
const transition = transitions[transitionIndex];
const hasExitTime = transition.hasExitTime;
const exitTime = transition.exitTime * duration;
if (exitTime > curClipTime) {
if (hasExitTime && exitTime > curClipTime) {
break;
}

if (exitTime >= lastClipTime) {
playState.currentTransitionIndex = Math.min(transitionIndex + 1, n - 1);
if (this._checkConditions(state, transition)) {
if (exitTime >= lastClipTime || !hasExitTime) {
if (checkStateMachineTransition) {
layerData.anyTransitionIndex = Math.min(transitionIndex + 1, n - 1);
} else {
playData.currentTransitionIndex = Math.min(transitionIndex + 1, n - 1);
}

if (transition.mute) continue;

const hasSolo = checkStateMachineTransition
? (<AnimatorStateMachine>transition._source)._anyHasSolo
: state._hasSoloTransition;
if (hasSolo && !transition.solo) continue;

if (this._checkConditions(transition)) {
if (this._applyTransition(layerIndex, layerData, layer, transition, aniUpdate)) {
return transition;
} else {
Expand All @@ -1116,21 +1165,35 @@ export class Animator extends Component {
transitions: Readonly<AnimatorStateTransition[]>,
lastClipTime: number,
curClipTime: number,
checkStateMachineTransition: boolean,
aniUpdate: boolean
): AnimatorStateTransition {
const { state } = playState;
let transitionIndex = playState.currentTransitionIndex;
let transitionIndex = checkStateMachineTransition ? layerData.anyTransitionIndex : playState.currentTransitionIndex;
const duration = playState.state._getDuration();
for (; transitionIndex >= 0; transitionIndex--) {
const transition = transitions[transitionIndex];
const hasExitTime = transition.hasExitTime;
const exitTime = transition.exitTime * duration;
if (exitTime < curClipTime) {
if (hasExitTime && exitTime < curClipTime) {
break;
}

if (exitTime <= lastClipTime) {
playState.currentTransitionIndex = Math.max(transitionIndex - 1, 0);
if (this._checkConditions(state, transition)) {
if (exitTime <= lastClipTime || !hasExitTime) {
if (checkStateMachineTransition) {
layerData.anyTransitionIndex = Math.max(transitionIndex - 1, 0);
} else {
playState.currentTransitionIndex = Math.max(transitionIndex - 1, 0);
}

if (transition.mute) continue;

const hasSolo = checkStateMachineTransition
? (<AnimatorStateMachine>transition._source)._anyHasSolo
: state._hasSoloTransition;
if (hasSolo && !transition.solo) continue;

if (this._checkConditions(transition)) {
if (this._applyTransition(layerIndex, layerData, layer, transition, aniUpdate)) {
return transition;
} else {
Expand All @@ -1148,11 +1211,24 @@ export class Animator extends Component {
layer: AnimatorControllerLayer,
state: AnimatorState,
transitions: Readonly<AnimatorStateTransition[]>,
checkStateMachineTransition: boolean,
aniUpdate: boolean
): AnimatorStateTransition {
for (let i = 0, n = transitions.length; i < n; i++) {
const transition = transitions[i];
if (this._checkConditions(state, transition)) {

if (transition.mute) continue;

const source = transition._source;
const isAnyTransition = transition._isAny;
const hasSolo = checkStateMachineTransition
? isAnyTransition
? (<AnimatorStateMachine>source)._anyHasSolo
: (<AnimatorStateMachine>source)._entryHasSolo
: (<AnimatorState>source)._hasSoloTransition;
if (hasSolo && !transition.solo) continue;

if (this._checkConditions(transition)) {
if (this._applyTransition(layerIndex, layerData, layer, transition, aniUpdate)) {
return transition;
} else {
Expand Down Expand Up @@ -1196,11 +1272,7 @@ export class Animator extends Component {
return success;
}

private _checkConditions(state: AnimatorState, transition: AnimatorStateTransition): boolean {
if (transition.mute) return false;

if (state?._hasSoloTransition && !transition.solo) return false;

private _checkConditions(transition: AnimatorStateTransition): boolean {
const { conditions } = transition;

let allPass = true;
Expand Down Expand Up @@ -1410,12 +1482,12 @@ export class Animator extends Component {

transition =
anyStateTransitions.length &&
this._applyTransitionsByCondition(layerIndex, layerData, layer, null, anyStateTransitions, aniUpdate);
this._applyTransitionsByCondition(layerIndex, layerData, layer, null, anyStateTransitions, true, aniUpdate);

if (!transition) {
transition =
entryTransitions.length &&
this._applyTransitionsByCondition(layerIndex, layerData, layer, null, entryTransitions, aniUpdate);
this._applyTransitionsByCondition(layerIndex, layerData, layer, null, entryTransitions, true, aniUpdate);
}

if (transition) {
Expand Down
Loading
Loading