diff --git a/webclient/src/components/layers/LayeredThreeView.tsx b/webclient/src/components/layers/LayeredThreeView.tsx index 96e2f7b..eaf80d8 100644 --- a/webclient/src/components/layers/LayeredThreeView.tsx +++ b/webclient/src/components/layers/LayeredThreeView.tsx @@ -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 <> - {/* */} + - + ; }); diff --git a/webclient/src/components/layers/PlayButtonsLayer.tsx b/webclient/src/components/layers/PlayButtons.tsx similarity index 95% rename from webclient/src/components/layers/PlayButtonsLayer.tsx rename to webclient/src/components/layers/PlayButtons.tsx index 30339b5..edb8ada 100644 --- a/webclient/src/components/layers/PlayButtonsLayer.tsx +++ b/webclient/src/components/layers/PlayButtons.tsx @@ -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
{ state.game diff --git a/webclient/src/components/layers/SceneEditor/SceneEditorPlayerGizmosLayer.tsx b/webclient/src/components/layers/SceneEditor/SceneEditorPlayerGizmosLayer.tsx new file mode 100644 index 0000000..514358e --- /dev/null +++ b/webclient/src/components/layers/SceneEditor/SceneEditorPlayerGizmosLayer.tsx @@ -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(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; +}); diff --git a/webclient/src/state/viewLayers/player.ts b/webclient/src/state/viewLayers/player.ts new file mode 100644 index 0000000..3e7dc59 --- /dev/null +++ b/webclient/src/state/viewLayers/player.ts @@ -0,0 +1,7 @@ +import { ViewItem } from "./base"; + +export class PlayerViewItem extends ViewItem { + constructor() { + super(); + } +}