player camera gizmo in editor

This commit is contained in:
azykov@mail.ru
2026-07-01 10:31:35 +03:00
parent 7ce9e6dca6
commit ea8f251599
4 changed files with 84 additions and 4 deletions
@@ -6,21 +6,22 @@ import { SceneEditorObjectSelectionLayer } from "./SceneEditor/SceneEditorObject
import { LightsLayer } from "./LighsLayer";
import { StatsLayer } from './StatsLayer';
import { SceneEditorObjectGizmosLayer } from "./SceneEditor/SceneEditorObjectGizmosLayer";
import { PlayButtonsLayer } from "./PlayButtonsLayer";
import { PlayButtons } from "./PlayButtons";
import { SceneEditorPlayerGizmosLayer } from "./SceneEditor/SceneEditorPlayerGizmosLayer";
export const LayeredThreeView = observer(function () {
return <>
<Canvas>
<LightsLayer />
{/* <Perf position="bottom-right" /> */}
<SceneEditorCameraLayer />
<ObjectGeometriesLayer>
<SceneEditorObjectSelectionLayer />
<SceneEditorObjectGizmosLayer />
</ObjectGeometriesLayer>
<SceneEditorPlayerGizmosLayer />
<StatsLayer />
</Canvas>
<PlayButtonsLayer />
<PlayButtons />
</>;
});
@@ -2,7 +2,7 @@ import { observer } from "mobx-react-lite";
import { state } from "../../state";
import { IconPlayerPlayFilled, IconPlayerPauseFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled } from '@tabler/icons-react';
export const PlayButtonsLayer = observer(function () {
export const PlayButtons = observer(function () {
return <div style={{ position: 'absolute', top: 8, right: 8, display: 'flex', gap: 4, fontSize: 14 }}>
{
state.game
@@ -0,0 +1,72 @@
import { useEffect, useMemo, useRef } from "react";
import * as THREE from "three";
import { useThree, useFrame } from "@react-three/fiber";
import { observer } from "mobx-react-lite";
import { state } from "../../../state";
import { computeBoundingBox } from "../../../utils/runtime";
const _offset = new THREE.Vector3();
const _lookAt = new THREE.Vector3();
const _euler = new THREE.Euler(0, 0, 0, 'YXZ');
export const SceneEditorPlayerGizmosLayer = observer(function () {
const scene = useThree(s => s.scene);
const helperRef = useRef<THREE.CameraHelper | null>(null);
const playerCam = useMemo(() => new THREE.PerspectiveCamera(75, 16 / 9, 0.1, 1000), []);
const playerObjectId = state.world.data.initialScene.playerObjectId;
const playerObject = playerObjectId
? state.world.data.initialScene.objects[playerObjectId]
: undefined;
const playerType = playerObject
? state.world.data.objectTypes[playerObject.typeId]
: undefined;
useEffect(() => {
if (!playerObject || !playerType)
return;
const helper = new THREE.CameraHelper(playerCam);
scene.add(helper);
helperRef.current = helper;
return () => {
scene.remove(helper);
helper.dispose();
helperRef.current = null;
};
}, [playerObject, playerType, playerCam, scene]);
useFrame(() => {
if (!playerObject || !playerType || !helperRef.current)
return;
const bb = computeBoundingBox(playerType);
const W = bb.max[0] - bb.min[0];
const H = bb.max[1] - bb.min[1];
const D = bb.max[2] - bb.min[2];
const radius = Math.sqrt(W * W + H * H + D * D);
const centerY = (bb.min[1] + bb.max[1]) / 2;
const yaw = playerObject.rotation[1];
_offset.set(W * 0.1, centerY + H * 0.3, bb.max[2] + radius);
_offset.applyEuler(_euler.set(0, yaw, 0, 'YXZ'));
playerCam.position.set(
playerObject.position[0] + _offset.x,
playerObject.position[1] + _offset.y,
playerObject.position[2] + _offset.z,
);
_lookAt.set(
playerObject.position[0],
playerObject.position[1] + centerY,
playerObject.position[2],
);
playerCam.lookAt(_lookAt);
playerCam.updateMatrixWorld(true);
helperRef.current.update();
});
return null;
});
+7
View File
@@ -0,0 +1,7 @@
import { ViewItem } from "./base";
export class PlayerViewItem extends ViewItem {
constructor() {
super();
}
}