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();
+ }
+}