UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

148 lines (107 loc) 3.86 kB
import { System } from "../System.js"; import { InverseKinematics } from "./InverseKinematics.js"; import Mesh, { MeshFlags } from "../../graphics/ecs/mesh/Mesh.js"; import { TwoBoneInverseKinematicsSolver } from "./TwoBoneInverseKinematicsSolver.js"; import { extractSkeletonFromMeshComponent } from "../../graphics/ecs/mesh/SkeletonUtils.js"; import { OneBoneSurfaceAlignmentSolver } from "./OneBoneSurfaceAlignmentSolver.js"; import { IKProblem } from "./IKProblem.js"; import { obtainTerrain } from "../terrain/util/obtainTerrain.js"; import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js"; import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js"; export class InverseKinematicsSystem extends System { dependencies = [InverseKinematics, Mesh]; components_used = [ ResourceAccessSpecification.from(Mesh, ResourceAccessKind.Read | ResourceAccessSpecification.Write) ]; /** * * @type {{"2BIK": TwoBoneInverseKinematicsSolver}} */ solvers = { "2BIK": new TwoBoneInverseKinematicsSolver(), "1BSA": new OneBoneSurfaceAlignmentSolver() }; problems = {}; /** * * @type {Terrain} */ __terrain = null; get componentClass() { return InverseKinematics; } /** * * @param {InverseKinematics} ik * @param {Mesh} mesh */ recordEntityProblems(ik, mesh) { if (!mesh.getFlag(MeshFlags.InView)) { //not visible return; } const skeleton = extractSkeletonFromMeshComponent(mesh); if (skeleton === undefined) { return; } const ikConstraints = ik.constraints; const n = ikConstraints.length; for (let i = 0; i < n; i++) { /** * * @type {IKConstraint} */ const c = ikConstraints[i]; const solverID = c.solver; //define problem const problem = IKProblem.pool.create(); problem.constraint = c; problem.skeleton = skeleton; problem.terrain = this.__terrain; const problemSet = this.problems[solverID]; if (problemSet === undefined) { this.problems[solverID] = [problem]; } else { problemSet.push(problem); } } } update(timeDelta) { const em = this.entityManager; const ecd = em.dataset; if (ecd == null) { return; } this.__terrain = obtainTerrain(ecd); if (this.__terrain === null) { return; } ecd.traverseEntities([InverseKinematics, Mesh], this.recordEntityProblems, this); //solve problems for (const solverID in this.solvers) { const problemSet = this.problems[solverID]; if (problemSet === undefined) { continue; } const n = problemSet.length; if (n === 0) { continue; } const solver = this.solvers[solverID]; for (let i = 0; i < n; i++) { const problem = problemSet[i]; try { solver.solve(problem); } catch (e) { console.error("Solution failed:", e); } IKProblem.pool.release(problem); } } //clear problem set for (const solverID in this.problems) { const problemSet = this.problems[solverID]; problemSet.splice(0, problemSet.length); } } }