Improve controls, add mobile joystick control

This commit is contained in:
Brian Beck 2026-02-11 22:29:09 -08:00
parent 0c6aa3b4dd
commit 5214a8556b
33 changed files with 381 additions and 68 deletions

View file

@ -7,6 +7,13 @@ export const metadata = {
description: "Tribes 2 forever.",
};
export const viewport = {
width: "device-width",
initialScale: 1,
maximumScale: 1,
userScalable: false,
};
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">

View file

@ -5,7 +5,13 @@ import { NoToneMapping, SRGBColorSpace, PCFShadowMap, Camera } from "three";
import { Mission } from "@/src/components/Mission";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ObserverControls } from "@/src/components/ObserverControls";
import {
TouchJoystick,
TouchCameraMovement,
type JoystickState,
} from "@/src/components/TouchControls";
import { InspectorControls } from "@/src/components/InspectorControls";
import { useTouchDevice } from "@/src/components/useTouchDevice";
import { SettingsProvider } from "@/src/components/SettingsProvider";
import { ObserverCamera } from "@/src/components/ObserverCamera";
import { AudioProvider } from "@/src/components/AudioContext";
@ -72,6 +78,7 @@ function MapInspector() {
[setCurrentMission],
);
const isTouch = useTouchDevice();
const { missionName, missionType } = currentMission;
const [loadingProgress, setLoadingProgress] = useState(0);
const [showLoadingIndicator, setShowLoadingIndicator] = useState(true);
@ -114,6 +121,8 @@ function MapInspector() {
);
const cameraRef = useRef<Camera | null>(null);
const joystickStateRef = useRef<JoystickState>({ angle: 0, force: 0 });
const joystickZoneRef = useRef<HTMLDivElement | null>(null);
return (
<QueryClientProvider client={queryClient}>
@ -134,6 +143,12 @@ function MapInspector() {
</div>
</div>
)}
{isTouch && (
<TouchJoystick
joystickState={joystickStateRef}
joystickZone={joystickZoneRef}
/>
)}
<Canvas
frameloop="always"
gl={glSettings}
@ -152,7 +167,14 @@ function MapInspector() {
/>
<ObserverCamera />
<DebugElements />
<ObserverControls />
{isTouch === null ? null : isTouch ? (
<TouchCameraMovement
joystickState={joystickStateRef}
joystickZone={joystickZoneRef}
/>
) : (
<ObserverControls />
)}
</AudioProvider>
</CamerasProvider>
</Canvas>

View file

@ -417,3 +417,33 @@ input[type="range"] {
opacity: 0.2;
}
}
.TouchJoystick {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
width: 140px;
height: 140px;
z-index: 10;
}
.TouchJoystick .back {
background: rgba(3, 79, 76, 0.6) !important;
border: 1px solid rgba(0, 219, 223, 0.5) !important;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.7) !important;
}
.TouchJoystick .front {
background: radial-gradient(
circle at 50% 50%,
rgba(23, 247, 198, 0.9) 0%,
rgba(9, 184, 170, 0.95) 100%
) !important;
border: 2px solid rgba(255, 255, 255, 0.4) !important;
box-shadow:
0 2px 4px rgba(0, 0, 0, 0.5),
0 1px 1px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.15),
inset 0 -1px 2px rgba(0, 0, 0, 0.3) !important;
}