Files
blitzkit/src/app/tools/tankopedia/[id]/components/Control.tsx
T

162 lines
5.3 KiB
TypeScript
Raw Normal View History

2024-01-03 12:21:30 -06:00
import { OrbitControls } from '@react-three/drei';
import { useThree } from '@react-three/fiber';
2024-01-04 13:37:36 -06:00
import { useEffect, useRef } from 'react';
2024-01-19 22:46:10 -06:00
import { Vector3 } from 'three';
2024-01-03 12:21:30 -06:00
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
2024-01-19 22:46:10 -06:00
import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimits';
import { modelDefinitions } from '../../../../../core/blitzkrieg/modelDefinitions';
import { Pose, poseEvent } from '../../../../../core/blitzkrieg/pose';
2024-01-21 22:11:01 -06:00
import { useAwait } from '../../../../../hooks/useAwait';
2024-01-22 18:04:13 -06:00
import { useDuel } from '../../../../../stores/duel';
2024-01-22 16:54:07 -06:00
import { useTankopediaPersistent } from '../../../../../stores/tankopedia';
2024-01-03 12:21:30 -06:00
2024-01-20 16:59:18 -06:00
const poseDistances: Record<Pose, number> = {
[Pose.HullDown]: 15,
[Pose.FaceHug]: 5,
[Pose.Default]: -1,
};
2024-01-19 22:46:10 -06:00
2024-01-22 18:04:13 -06:00
export function Controls() {
2024-01-03 12:21:30 -06:00
const camera = useThree((state) => state.camera);
const orbitControls = useRef<OrbitControlsClass>(null);
2024-01-21 22:11:01 -06:00
const awaitedModelDefinitions = useAwait(modelDefinitions);
2024-01-22 18:04:13 -06:00
const protagonist = useDuel((state) => state.protagonist!);
const antagonist = useDuel((state) => state.antagonist!);
2024-01-20 16:59:18 -06:00
const protagonistModelDefinition =
2024-01-22 18:04:13 -06:00
awaitedModelDefinitions[protagonist.tank.id];
2024-02-08 11:08:22 -06:00
const protagonistTrackModelDefinition =
awaitedModelDefinitions[protagonist.tank.id].tracks[protagonist.track.id];
2024-01-22 18:04:13 -06:00
const antagonistModelDefinition = awaitedModelDefinitions[antagonist.tank.id];
2024-01-20 16:59:18 -06:00
const protagonistTurretModelDefinition =
2024-01-22 18:04:13 -06:00
protagonistModelDefinition.turrets[protagonist.turret.id];
2024-01-20 16:59:18 -06:00
const antagonistTurretModelDefinition =
2024-01-22 18:04:13 -06:00
antagonistModelDefinition.turrets[antagonist.turret.id];
2024-01-20 16:59:18 -06:00
const protagonistGunModelDefinition =
2024-01-22 18:04:13 -06:00
protagonistTurretModelDefinition.guns[protagonist.gun.id];
2024-01-22 16:54:07 -06:00
const protagonistHullOrigin = new Vector3(
2024-02-08 11:08:22 -06:00
protagonistTrackModelDefinition.origin[0],
protagonistTrackModelDefinition.origin[1],
-protagonistTrackModelDefinition.origin[2],
2024-01-22 16:54:07 -06:00
);
2024-01-20 16:59:18 -06:00
const protagonistTurretOrigin = new Vector3(
protagonistModelDefinition.turretOrigin[0],
protagonistModelDefinition.turretOrigin[1],
-protagonistModelDefinition.turretOrigin[2],
2024-01-19 22:46:10 -06:00
);
2024-01-20 16:59:18 -06:00
const protagonistGunOrigin = new Vector3(
protagonistTurretModelDefinition.gunOrigin[0],
protagonistTurretModelDefinition.gunOrigin[1],
-protagonistTurretModelDefinition.gunOrigin[2],
2024-01-19 22:46:10 -06:00
);
2024-01-20 16:59:18 -06:00
const antagonistGunHeight =
2024-02-08 11:08:22 -06:00
protagonistTrackModelDefinition.origin[1] +
2024-01-20 16:59:18 -06:00
antagonistModelDefinition.turretOrigin[1] +
antagonistTurretModelDefinition.gunOrigin[1];
2024-01-03 12:21:30 -06:00
useEffect(() => {
2024-01-20 16:59:18 -06:00
camera.position.set(-4, 4, -16);
orbitControls.current?.target.set(0, antagonistGunHeight / 2, 0);
2024-01-13 16:48:20 -06:00
2024-01-22 16:54:07 -06:00
const unsubscribeTankopedia = useTankopediaPersistent.subscribe(
2024-01-13 16:48:20 -06:00
(state) => state.model.visual.controlsEnabled,
(enabled) => {
if (orbitControls.current) orbitControls.current.enabled = enabled;
},
);
2024-01-19 22:46:10 -06:00
function handlePoseEvent(event: Pose) {
switch (event) {
case Pose.HullDown: {
2024-01-20 16:59:18 -06:00
const [pitch] = applyPitchYawLimits(
-Infinity,
0,
protagonistGunModelDefinition.pitch,
protagonistTurretModelDefinition.yaw,
);
2024-01-19 22:46:10 -06:00
camera.position
.set(0, 0, 0)
2024-01-22 16:54:07 -06:00
.add(protagonistHullOrigin)
2024-01-20 16:59:18 -06:00
.add(protagonistTurretOrigin)
.add(protagonistGunOrigin)
2024-01-19 22:46:10 -06:00
.add(
new Vector3(
0,
2024-01-20 16:59:18 -06:00
poseDistances[event] * Math.sin(pitch),
poseDistances[event] * -Math.cos(pitch),
2024-01-19 22:46:10 -06:00
),
);
2024-01-20 16:59:18 -06:00
camera.lookAt(
2024-01-22 16:54:07 -06:00
protagonistHullOrigin
.clone()
.add(protagonistTurretOrigin)
.add(protagonistGunOrigin),
2024-01-20 16:59:18 -06:00
);
orbitControls.current?.target.set(0, antagonistGunHeight, 0);
break;
}
case Pose.FaceHug: {
const [pitch] = applyPitchYawLimits(
0,
0,
protagonistGunModelDefinition.pitch,
protagonistTurretModelDefinition.yaw,
);
camera.position
.set(0, 0, 0)
2024-01-22 16:54:07 -06:00
.add(protagonistHullOrigin)
2024-01-20 16:59:18 -06:00
.add(protagonistTurretOrigin)
.add(protagonistGunOrigin)
.add(
new Vector3(
0,
poseDistances[event] * Math.sin(pitch),
poseDistances[event] * -Math.cos(pitch),
),
);
orbitControls.current?.target
.set(0, 0, 0)
2024-01-22 16:54:07 -06:00
.add(protagonistHullOrigin)
2024-01-20 16:59:18 -06:00
.add(protagonistTurretOrigin)
.add(protagonistGunOrigin)
.add(
new Vector3(
0,
0.5 * poseDistances[event] * Math.sin(pitch),
0.5 * poseDistances[event] * -Math.cos(pitch),
),
);
break;
}
case Pose.Default: {
camera.position.set(-4, 4, -16);
orbitControls.current?.target.set(0, antagonistGunHeight / 2, 0);
break;
2024-01-19 22:46:10 -06:00
}
}
}
poseEvent.on(handlePoseEvent);
return () => {
unsubscribeTankopedia();
poseEvent.off(handlePoseEvent);
};
2024-01-22 18:04:13 -06:00
}, [camera, protagonist.tank.id, antagonist.tank.id]);
2024-01-03 12:21:30 -06:00
2024-01-06 18:17:04 -06:00
return (
2024-01-12 20:22:53 -06:00
<OrbitControls
2024-01-24 15:28:14 -06:00
maxDistance={20}
minDistance={5}
2024-01-12 20:22:53 -06:00
ref={orbitControls}
2024-01-22 16:54:07 -06:00
enabled={useTankopediaPersistent.getState().model.visual.controlsEnabled}
2024-01-12 20:22:53 -06:00
rotateSpeed={0.25}
enableDamping={false}
/>
2024-01-06 18:17:04 -06:00
);
2024-01-03 12:21:30 -06:00
}