@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
194 lines (159 loc) • 4.73 kB
JavaScript
import { combine_hash } from "../../../../../../../core/collection/array/combine_hash.js";
import { computeHashArray } from "../../../../../../../core/collection/array/computeHashArray.js";
import { isArrayEqual } from "../../../../../../../core/collection/array/isArrayEqual.js";
import { invokeObjectHash } from "../../../../../../../core/model/object/invokeObjectHash.js";
import { AnimationClip } from "../../AnimationClip.js";
import { AnimationClipDefinition } from "../../AnimationClipDefinition.js";
import { BlendStateMatrix } from "../../blending/BlendStateMatrix.js";
import { AnimationStateType } from "../AnimationStateType.js";
import { AnimationStateDefinition } from "./AnimationStateDefinition.js";
export class AnimationGraphDefinition {
/**
*
* @type {AnimationStateDefinition[]}
*/
states = [];
/**
*
* @type {AnimationTransitionDefinition[]}
*/
transitions = [];
/**
*
* @type {AnimationStateDefinition}
*/
startingSate = null;
/**
*
* @type {AnimationClipDefinition[]}
*/
clipIndex = [];
/**
*
* @param {AnimationGraphDefinition} other
* @returns {boolean}
*/
equals(other) {
if (this === other) {
return true;
}
return this.startingSate.equals(other.startingSate)
&& isArrayEqual(this.states, other.states)
&& isArrayEqual(this.transitions, other.transitions)
;
}
/**
* @returns {number}
*/
hash() {
return combine_hash(
this.startingSate.hash(),
computeHashArray(this.states, invokeObjectHash),
computeHashArray(this.transitions, invokeObjectHash)
);
}
/**
*
* @param {string[]} tags
* @returns {AnimationStateDefinition|undefined}
*/
matchStateWithMostTags(tags) {
let best_match_count = 0;
let best_match_tag_count = 0;
let best_match = undefined;
const states = this.states;
const n = states.length;
for (let i = 0; i < n; i++) {
const definition = states[i];
const matches = definition.countMatchingTags(tags);
if (matches < best_match_count) {
continue;
}
const tag_count = definition.tags.length;
if (matches > best_match_count || tag_count < best_match_tag_count) {
best_match = definition;
best_match_count = matches;
best_match_tag_count = tag_count;
}
}
return best_match;
}
/**
*
* @return {BlendStateMatrix}
*/
createBlendState() {
return new BlendStateMatrix(this.clipIndex.length);
}
/**
*
* @param {AnimationClipDefinition} def
* @returns {number}
*/
getClipIndex(def) {
return this.clipIndex.indexOf(def);
}
build() {
//construct clip index
this.clipIndex = [];
this.traverseClips(c => {
/**
*
* @type {AnimationClipDefinition}
*/
const clipDefinition = c.def;
if (this.clipIndex.indexOf(clipDefinition) === -1) {
this.clipIndex.push(clipDefinition);
}
});
}
/**
*
* @param {function(AnimationClip)} visitor
* @param {*} [thisArg]
*/
traverseClips(visitor, thisArg) {
this.states.forEach(state => {
if (state.type === AnimationStateType.Clip) {
visitor(state.motion);
} else {
throw new Error(`Unsupported stat type`);
}
});
}
/**
*
* @param {AnimationStateDefinition} state
*/
addState(state) {
if (this.containsState(state)) {
return false;
} else {
this.states.push(state);
}
if (this.startingSate === null) {
this.startingSate = state;
}
}
/**
*
* @param {AnimationStateDefinition} state
* @return {boolean}
*/
containsState(state) {
return this.states.indexOf(state) !== -1;
}
/**
*
* @param {AnimationStateDefinition} state
* @returns {boolean}
*/
removeState(state) {
const i = this.states.indexOf(state);
if (i === -1) {
return false;
}
this.states.splice(i, 1);
return true;
}
}