|
@@ -7,31 +7,51 @@ import {
|
|
|
} from "./use-stage";
|
|
|
import { OrbitControls } from "three/examples/jsm/Addons.js";
|
|
|
import { listener } from "@/utils/event";
|
|
|
-import { PerspectiveCamera, Vector3 } from "three";
|
|
|
-import { frameEebounce, frameInterval, mergeFuns } from "@/utils/shared";
|
|
|
+import { Vector3 } from "three";
|
|
|
+import { mergeFuns } from "@/utils/shared";
|
|
|
import { useMouseEventRegister } from "./use-event";
|
|
|
import { subgroupName } from "../container";
|
|
|
import { useCameraAnimation } from "./use-animation";
|
|
|
-import { getDownKeys } from "@/core/hook/use-global-vars";
|
|
|
-import { getMoveDirectrionByKeys } from "./use-downkeys";
|
|
|
-
|
|
|
-const getModelControls = (
|
|
|
- container: HTMLDivElement,
|
|
|
- camera: PerspectiveCamera,
|
|
|
- render: () => void
|
|
|
-) => {
|
|
|
- const controls = new OrbitControls(camera, container);
|
|
|
+import {
|
|
|
+ getMoveDirectrionByKeys,
|
|
|
+ useFigureMoveCollision,
|
|
|
+} from "./use-move";
|
|
|
+
|
|
|
+const useModelControls = () => {
|
|
|
+ const container = useContainer();
|
|
|
+ const camera = useCamera();
|
|
|
+ const _render = useRender();
|
|
|
+ const render = () => {
|
|
|
+ camera.bus.emit("change");
|
|
|
+ _render();
|
|
|
+ };
|
|
|
+
|
|
|
+ const controls = new OrbitControls(camera);
|
|
|
controls.target.set(0, 5, 0);
|
|
|
- controls.update();
|
|
|
+ controls.enabled = false;
|
|
|
|
|
|
const unListener = listener(controls as any, "change", render);
|
|
|
let prevOrigin: Vector3 | null = null;
|
|
|
let prevDire: Vector3 | null = null;
|
|
|
|
|
|
+ watch(
|
|
|
+ container,
|
|
|
+ (container, _, onCleanup) => {
|
|
|
+ if (container) {
|
|
|
+ controls.domElement = container;
|
|
|
+ controls.connect();
|
|
|
+ onCleanup(() => {
|
|
|
+ controls.disconnect();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+ );
|
|
|
+
|
|
|
return {
|
|
|
controls,
|
|
|
onDestory() {
|
|
|
- controls.dispose();
|
|
|
+ controls.domElement && controls.dispose();
|
|
|
unListener();
|
|
|
},
|
|
|
syncCamera() {
|
|
@@ -54,68 +74,66 @@ const getModelControls = (
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-const getRoamingControls = (
|
|
|
- container: HTMLDivElement,
|
|
|
- camera: PerspectiveCamera,
|
|
|
- render: () => void
|
|
|
-) => {
|
|
|
- const initDirection = camera.getWorldDirection(new Vector3());
|
|
|
- const controls = new OrbitControls(camera, container);
|
|
|
- controls.rotateSpeed = -0.3;
|
|
|
- controls.enableZoom = false;
|
|
|
-
|
|
|
+const roamingEysHeight = 120;
|
|
|
+const useRoamingControls = () => {
|
|
|
+ const container = useContainer();
|
|
|
+ const camera = useCamera();
|
|
|
+ const _render = useRender();
|
|
|
+ const render = () => {
|
|
|
+ camera.bus.emit("change");
|
|
|
+ _render();
|
|
|
+ };
|
|
|
+ const enabled = ref(false);
|
|
|
const syncCamera = (direction = camera.getWorldDirection(new Vector3())) => {
|
|
|
controls.target.copy(direction.add(camera.position));
|
|
|
controls.update();
|
|
|
};
|
|
|
- syncCamera(initDirection);
|
|
|
- render();
|
|
|
- let prevOrigin: Vector3 | null = null;
|
|
|
- let prevDire: Vector3 | null = null;
|
|
|
-
|
|
|
- const unListener = listener(controls as any, "change", render);
|
|
|
+
|
|
|
const { direction, onDestory: onDownDestory } = getMoveDirectrionByKeys();
|
|
|
- const stopWatchDirection = watch(direction, (dire, _, onCleanup) => {
|
|
|
- if (!controls.enabled || !dire) return;
|
|
|
- onCleanup(frameInterval(() => {
|
|
|
- const cameraDire = camera.getWorldDirection(new Vector3())
|
|
|
- cameraDire.y = 0
|
|
|
- cameraDire.normalize()
|
|
|
-
|
|
|
- const rightDire = new Vector3(0, 1, 0).cross(cameraDire)
|
|
|
- const moveDire = new Vector3()
|
|
|
- if (dire.y) {
|
|
|
- moveDire.addScaledVector(cameraDire, dire.y)
|
|
|
- }
|
|
|
+ const move = useFigureMoveCollision(camera, direction, syncCamera);
|
|
|
+ move.pause()
|
|
|
|
|
|
- if (dire.x) {
|
|
|
- moveDire.addScaledVector(rightDire, -dire.x)
|
|
|
- }
|
|
|
+ const controls = new OrbitControls(camera);
|
|
|
+ controls.rotateSpeed = -0.3;
|
|
|
+ controls.enableZoom = false;
|
|
|
|
|
|
- if (moveDire.length() > 0) {
|
|
|
- camera.position.addScaledVector(moveDire.normalize(), 2)
|
|
|
- syncCamera();
|
|
|
- render();
|
|
|
- }
|
|
|
- }));
|
|
|
- });
|
|
|
+ let prevOrigin: Vector3 | null = null;
|
|
|
+ let prevDire: Vector3 | null = null;
|
|
|
|
|
|
return {
|
|
|
controls,
|
|
|
- onDestory() {
|
|
|
- controls.dispose();
|
|
|
- unListener();
|
|
|
- onDownDestory();
|
|
|
- stopWatchDirection();
|
|
|
- },
|
|
|
+ onDestory: mergeFuns(
|
|
|
+ watchEffect(() => (controls.enabled = enabled.value)),
|
|
|
+ watch(
|
|
|
+ container,
|
|
|
+ (container, _, onCleanup) => {
|
|
|
+ if (container) {
|
|
|
+ controls.domElement = container;
|
|
|
+ controls.connect();
|
|
|
+ onCleanup(() => {
|
|
|
+ controls.disconnect();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+ ),
|
|
|
+ move.destory,
|
|
|
+ () => {
|
|
|
+ controls.domElement && controls.dispose();
|
|
|
+ },
|
|
|
+ listener(controls as any, "change", render),
|
|
|
+ onDownDestory
|
|
|
+ ),
|
|
|
syncCamera,
|
|
|
disable() {
|
|
|
prevOrigin = camera.position.clone();
|
|
|
prevDire = camera.getWorldDirection(new Vector3());
|
|
|
controls.enabled = false;
|
|
|
+ move.pause()
|
|
|
},
|
|
|
enable() {
|
|
|
controls.enabled = true;
|
|
|
+ move.continue()
|
|
|
render();
|
|
|
},
|
|
|
get current() {
|
|
@@ -128,41 +146,29 @@ const getRoamingControls = (
|
|
|
};
|
|
|
|
|
|
const controlsFactory = {
|
|
|
- model: getModelControls,
|
|
|
- roaming: getRoamingControls,
|
|
|
+ model: useModelControls,
|
|
|
+ roaming: useRoamingControls,
|
|
|
};
|
|
|
export type ControlsType = keyof typeof controlsFactory;
|
|
|
export type Controls = ReturnType<(typeof controlsFactory)[ControlsType]>;
|
|
|
|
|
|
export const useControls = installThreeGlobalVar(() => {
|
|
|
const container = useContainer();
|
|
|
- const camera = useCamera();
|
|
|
- const render = useRender();
|
|
|
const type = ref<ControlsType>();
|
|
|
const controls = ref<Controls>();
|
|
|
- let controlsMap: Partial<Record<ControlsType, Controls>> = {};
|
|
|
+ const controlsMap = {} as Record<ControlsType, Controls>;
|
|
|
+
|
|
|
+ for (const [type, factory] of Object.entries(controlsFactory)) {
|
|
|
+ controlsMap[type as ControlsType] = factory();
|
|
|
+ }
|
|
|
|
|
|
- const ctRender = () => {
|
|
|
- camera.bus.emit("change");
|
|
|
- render();
|
|
|
- };
|
|
|
const stopWatch = watch(
|
|
|
[container, type],
|
|
|
([container, type], _, onCleanup) => {
|
|
|
if (!(type && container)) return;
|
|
|
|
|
|
- let ct: Controls;
|
|
|
- if (type in controlsMap) {
|
|
|
- ct = controlsMap[type]!;
|
|
|
- ct.enable();
|
|
|
- } else {
|
|
|
- ct = controlsMap[type] = controlsFactory[type](
|
|
|
- container,
|
|
|
- camera,
|
|
|
- ctRender
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
+ const ct = controlsMap[type];
|
|
|
+ ct.enable();
|
|
|
controls.value = ct;
|
|
|
onCleanup(() => {
|
|
|
ct.disable();
|
|
@@ -179,7 +185,6 @@ export const useControls = installThreeGlobalVar(() => {
|
|
|
for (const controls of Object.values(controlsMap)) {
|
|
|
controls.onDestory();
|
|
|
}
|
|
|
- controlsMap = {};
|
|
|
},
|
|
|
};
|
|
|
});
|
|
@@ -191,7 +196,7 @@ export const useFlyRoaming = installThreeGlobalVar(() => {
|
|
|
|
|
|
return async (point: Vector3) => {
|
|
|
type.value = undefined;
|
|
|
- const position = point.clone().add({ x: 0, y: 100, z: 0 });
|
|
|
+ const position = point.clone().add({ x: 0, y: roamingEysHeight, z: 0 });
|
|
|
const direction = camera.getWorldDirection(new Vector3());
|
|
|
const target = position.clone().add(direction);
|
|
|
await cameraAnimation(position, target);
|
|
@@ -228,7 +233,6 @@ export const installAutoSwitchControls = installThreeGlobalVar(() => {
|
|
|
const flyRoaming = useFlyRoaming();
|
|
|
const flyModel = useFlyModel();
|
|
|
|
|
|
- type.value = "model";
|
|
|
const onDestroy = mergeFuns(
|
|
|
listener(document.documentElement, "keydown", (ev) => {
|
|
|
if (ev.key === "Escape" && type.value !== "model") {
|
|
@@ -237,6 +241,7 @@ export const installAutoSwitchControls = installThreeGlobalVar(() => {
|
|
|
}),
|
|
|
mouseRegister(subgroupName, "dblclick", ({ point }) => flyRoaming(point))
|
|
|
);
|
|
|
+ type.value = "model";
|
|
|
|
|
|
return { onDestroy };
|
|
|
});
|