mylingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
137 lines • 4.97 kB
JavaScript
import { Reactive } from "@lincode/reactivity";
import { Object3D } from "three";
import Cylinder from "./primitives/Cylinder";
import Sphere from "./primitives/Sphere";
import getActualScale from "./utils/getActualScale";
import getWorldPosition from "./utils/getWorldPosition";
import { scaleDown } from "../engine/constants";
import { timer } from "../engine/eventLoop";
import mainCamera from "../engine/mainCamera";
import scene from "../engine/scene";
import { emitSelectionTarget, onSelectionTarget } from "../events/onSelectionTarget";
import { triggerDefaults, triggerSchema } from "../interface/ITrigger";
import { appendableRoot } from "../api/core/Appendable";
import PositionedItem from "../api/core/PositionedItem";
import { getCameraRendered } from "../states/useCameraRendered";
import { idMap } from "./core/StaticObjectManager";
const getTargets = (id) => idMap.get(id) ?? [];
export default class Trigger extends PositionedItem {
static componentName = "trigger";
static defaults = triggerDefaults;
static schema = triggerSchema;
refresh = new Reactive({});
onEnter;
onExit;
_pad = false;
get pad() {
return this._pad;
}
set pad(val) {
this._pad = val;
this.refresh.set({});
}
_radius = 50;
get radius() {
return this._radius;
}
set radius(val) {
this._radius = val;
this.refresh.set({});
}
_interval = 300;
get interval() {
return this._interval;
}
set interval(val) {
this._interval = val;
this.refresh.set({});
}
_helper = true;
get helper() {
return this._helper;
}
set helper(val) {
this._helper = val;
this.refresh.set({});
}
_targetIds;
get targetIds() {
return this._targetIds;
}
set targetIds(val) {
this._targetIds = val;
this.refresh.set({});
}
constructor() {
const outerObject3d = new Object3D();
super(outerObject3d);
scene.add(outerObject3d);
let helper;
this.createEffect(() => {
const { _radius, _interval, _targetIds, _pad } = this;
if (!_targetIds)
return;
const r = _radius * scaleDown;
const pr = r * 0.2;
let hitOld = false;
const handle = timer(_interval, -1, () => {
const { x, y, z } = getWorldPosition(outerObject3d);
const targets = typeof _targetIds === "string"
? getTargets(_targetIds)
: _targetIds.map((id) => [...getTargets(id)]).flat();
let hit = false;
let targetHit;
for (const target of targets) {
const { x: tx, y: ty, z: tz } = getWorldPosition(target.nativeObject3d);
if (_pad) {
const { y: sy } = getActualScale(target);
hit =
Math.abs(x - tx) < r &&
Math.abs(y - (ty - sy * 0.5)) < pr &&
Math.abs(z - tz) < r;
}
else
hit =
Math.abs(x - tx) < r &&
Math.abs(y - ty) < r &&
Math.abs(z - tz) < r;
if (hit) {
targetHit = target;
break;
}
}
if (hitOld !== hit)
if (hit && targetHit) {
this.onEnter?.(targetHit);
helper && (helper.color = "blue");
}
else {
this.onExit?.();
helper && (helper.color = "white");
}
hitOld = hit;
});
return () => {
handle.cancel();
};
}, [this.refresh.get]);
this.createEffect(() => {
const { _radius, _helper, _pad } = this;
if (!_helper || getCameraRendered() !== mainCamera)
return;
const h = (helper = _pad ? new Cylinder() : new Sphere());
appendableRoot.delete(h);
outerObject3d.add(h.outerObject3d);
h.scale = _radius * scaleDown * 2;
h.opacity = 0.5;
h.height = _pad ? 10 : 100;
const handle = onSelectionTarget(({ target }) => target === h && emitSelectionTarget(this));
return () => {
h.dispose();
helper = undefined;
handle.cancel();
};
}, [this.refresh.get, getCameraRendered]);
}
}
//# sourceMappingURL=Trigger.js.map