mylingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
75 lines (65 loc) • 2.45 kB
text/typescript
import { Reactive } from "@lincode/reactivity"
import { debounceInstance } from "@lincode/utils"
import { PerspectiveCamera } from "three"
import Appendable from "../../api/core/Appendable"
import PositionedItem from "../../api/core/PositionedItem"
import { onSceneGraphChange } from "../../events/onSceneGraphChange"
import ICameraBase from "../../interface/ICameraBase"
import CameraBase from "./CameraBase"
import MeshItem, { isMeshItem } from "./MeshItem"
const attachSet = new WeakSet<Appendable>()
export default class OrbitCameraBase
extends CameraBase<PerspectiveCamera>
implements ICameraBase
{
public constructor(camera: PerspectiveCamera) {
super(camera)
this.createEffect(() => {
const target = this.targetState.get()
if (!target) return
const handle = onSceneGraphChange(
() => target.parent !== this && this.retarget()
)
return () => {
handle.cancel()
}
}, [this.targetState.get])
}
protected manualTarget?: MeshItem
protected targetState = new Reactive<MeshItem | undefined>(undefined)
private static retaget = debounceInstance(
(instance: OrbitCameraBase) => {
let target = instance.manualTarget
for (const child of instance.children ?? [])
if (target) {
if (child.outerObject3d.parent !== instance.camera)
instance.camera[
attachSet.has(child) ? "attach" : "add"
](child.outerObject3d)
} else if (isMeshItem(child)) {
target = child
const { parent } = instance.outerObject3d
if (parent && child.outerObject3d.parent !== parent)
parent[attachSet.has(target) ? "attach" : "add"](
target.outerObject3d
)
}
instance.targetState.set(target)
},
0,
"trailing"
)
private retarget() {
OrbitCameraBase.retaget(this, this)
}
public override append(object: PositionedItem) {
this._append(object)
attachSet.delete(object)
this.retarget()
}
public override attach(object: PositionedItem) {
this._append(object)
attachSet.add(object)
this.retarget()
}
}