@soonspacejs/plugin-pathfinding
Version:
Pathfinding plugin for SoonSpace.js
100 lines (99 loc) • 4.25 kB
JavaScript
import { Matrix4 as u, Mesh as p, InstancedMesh as l, MeshStandardMaterial as w } from "three";
import { Crowd as m } from "@recast-navigation/core";
import { generateSoloNavMesh as v, generateTiledNavMesh as f } from "@recast-navigation/generators";
import { DebugDrawer as g, CrowdHelper as M } from "@recast-navigation/three";
import b from "soonspacejs";
import { StaticGeometryGenerator as D } from "three-mesh-bvh";
function H(o) {
const e = o.name, i = o.geometry, n = o.material, a = o.count, r = [];
for (let h = 0; h < a; h++) {
const s = new u();
o.getMatrixAt(h, s);
const d = new p(i, n);
d.name = `${e}_${h}`, r.push(d), s.premultiply(o.matrixWorld), d.matrix.copy(s), d.matrixWorld.copy(s), s.decompose(d.position, d.quaternion, d.scale);
}
return r;
}
function c(o) {
const e = [];
o.forEach((h) => {
h.traverse((s) => {
s instanceof p && s.geometry.index && (s instanceof l ? e.push(...H(s)) : e.push(s));
});
});
const i = new D(e);
i.applyWorldTransforms = !0, i.attributes = ["position", "index"];
const n = i.generate(), a = n.attributes.position.array, r = n.index && n.index.array;
return { positions: a, indices: r };
}
const { warn: t } = b.utils;
class G {
constructor(e) {
this.ssp = e;
}
navMesh = null;
crowd = null;
debugDrawer = null;
crowdHelper = null;
// solo navmesh
createSoloNavMesh(e, i = {}) {
if (this.navMesh)
return t("navmesh 已经存在,请先调用 disposeNavMesh()"), this.navMesh;
const { positions: n, indices: a } = c(e);
if (!a)
return t("生成 navmesh 失败,几何体不包含索引信息"), null;
const r = v(n, a, i);
return r.success ? (this.navMesh = r.navMesh, this.navMesh) : null;
}
// create tiled navmesh
createTiledNavMesh(e, i = {}) {
if (this.navMesh)
return t("navmesh 已经存在,请先调用 disposeNavMesh()"), this.navMesh;
const { positions: n, indices: a } = c(e);
if (!a)
return t("生成 navmesh 失败,几何体不包含索引信息"), null;
const r = f(n, a, i);
return r.success ? (this.navMesh = r.navMesh, this.navMesh) : null;
}
/**
* @deprecated use disposeNavMesh() instead
*/
disposeSoloNavMesh() {
this.disposeNavMesh();
}
disposeNavMesh() {
this.navMesh?.destroy(), this.navMesh = null;
}
// crowd
_crowdUpdate = () => {
this.crowd && (this.crowd.update(this.ssp.viewport.state.delta), this.crowdHelper?.update(), this.crowd.getActiveAgentCount() > 0 && this.ssp.render());
};
createCrowd(e) {
return this.crowd ? (t("crowd 已经存在,请先调用 disposeCrowd()"), this.crowd) : this.navMesh ? (this.crowd = new m(this.navMesh, e), this.ssp.signals.beforeRender.add(this._crowdUpdate), this.crowd) : (t("navmesh 不存在,请先调用 createSoloNavMesh()"), null);
}
disposeCrowd() {
this.crowd?.destroy(), this.crowd = null, this.ssp.signals.beforeRender.remove(this._crowdUpdate);
}
createDebugDrawer() {
return this.debugDrawer ? (t("debug drawer 已经存在,请先调用 disposeDebugDrawer()"), this.debugDrawer) : this.navMesh ? (this.debugDrawer = new g(), this.debugDrawer.drawNavMesh(this.navMesh, 0), this.ssp.addObject(this.debugDrawer), this.debugDrawer) : (t("navmesh 不存在,请先调用 createSoloNavMesh()"), null);
}
disposeDebugDrawer() {
this.debugDrawer && (this.debugDrawer.dispose(), this.ssp.removeObject(this.debugDrawer), this.debugDrawer = null);
}
createCrowdHelper(e = { agentMaterial: new w({ color: 65280 }) }) {
return this.crowdHelper ? (t("crowd helper 已经存在,请先调用 disposeCrowdHelper()"), this.crowdHelper) : this.crowd ? (this.crowdHelper = new M(this.crowd, e), this.ssp.addObject(this.crowdHelper), this.crowdHelper) : (t("crowd 不存在,请先调用 createCrowd()"), null);
}
disposeCrowdHelper() {
this.crowdHelper && (this.crowdHelper.agentMeshes.forEach((e) => {
e.geometry.dispose(), e.material.dispose();
}), this.ssp.removeObject(this.crowdHelper));
}
dispose() {
this.disposeNavMesh(), this.disposeCrowd(), this.disposeDebugDrawer(), this.disposeCrowdHelper();
}
}
export {
H as deInstancingMesh,
G as default,
c as getVertices
};