UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

194 lines (159 loc) 4.73 kB
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; } }