feat: turret rotation

This commit is contained in:
TrèsAbhi committed 2024-01-01 20:45:23 -06:00
1 parent c9d5b46ae8
commit 73f7e84192
3 files changed
+163 -32

No files matched your search

@@ -14,8 +14,7 @@ export function TankAlignment({ model }: TankAlignmentProps) {
const diameter = Math.max(box.max.x - box.min.x, box.max.z - box.min.z);
const radius = diameter / 2;
model.current?.position.set(0, -(box.min.y + box.max.y) / 2, 0);
// camera.position.set(radius * -0.25, radius * 0.1, radius * -1.5);
camera.position.set(0, (box.min.y + box.max.y) / 2, -10);
}, []);
return null;
+161 -29
View File
@@ -21,13 +21,13 @@ import {
Tooltip,
} from '@radix-ui/themes';
import { Environment, OrbitControls } from '@react-three/drei';
import { Canvas, useLoader } from '@react-three/fiber';
import { Canvas, ThreeEvent, useLoader } from '@react-three/fiber';
import { EffectComposer, SSAO } from '@react-three/postprocessing';
import { go } from 'fuzzysort';
import { debounce } from 'lodash';
import Link from 'next/link';
import { use, useEffect, useRef, useState } from 'react';
import { Group, Mesh } from 'three';
import { Group, Mesh, Vector3 } from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { Flag } from '../../../../components/Flag';
import { ModuleButtons } from '../../../../components/ModuleButton';
@@ -60,7 +60,19 @@ export default function Page({ params }: { params: { id: string } }) {
const [versusTurret, setVersusTurret] = useState(versusTank.turrets.at(-1)!);
const [versusGun, setVersusGun] = useState(versusTurret.guns.at(-1)!);
const [versusTankTab, setVersusTankTab] = useState('search');
const turretObject3D = useRef<Mesh>(null);
const mantletObject3D = useRef<Mesh>(null);
const gunObject3D = useRef<Mesh>(null);
const canvas = useRef<HTMLCanvasElement>(null);
const gltf = useLoader(GLTFLoader, '/test/5137.glb');
const turretOrigin = new Vector3(
tank.turretOrigin[0],
tank.turretOrigin[1],
-tank.turretOrigin[2],
).applyAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);
const gunOrigin = new Vector3(...turret.gunOrigin);
const [turretRotation, setTurretRotation] = useState(0);
const [orbitControlsEnabled, setOrbitControlsEnabled] = useState(true);
useEffect(() => {
if (!turret.guns.some(({ id }) => gun.id === id)) {
@@ -110,11 +122,13 @@ export default function Page({ params }: { params: { id: string } }) {
<div style={{ height: '50vh', maxHeight: 576 }}>
<Canvas
ref={canvas}
onPointerDown={(event) => event.preventDefault()}
camera={{ fov: 20, position: [4, 0, -16] }}
>
<TankAlignment model={model} />
<OrbitControls />
<OrbitControls enabled={orbitControlsEnabled} />
<gridHelper />
{/* I really like apartment, dawn, and sunset */}
<Environment preset="apartment" />
@@ -132,34 +146,152 @@ export default function Page({ params }: { params: { id: string } }) {
</EffectComposer>
<group ref={model} rotation={[-Math.PI / 2, 0, 0]}>
{gltf.scene.children[0].children.map((child) => (
<mesh
visible={
child.name === 'hull' ||
child.name.startsWith('chassis_track_') ||
child.name.startsWith('chassis_wheel_') ||
(child.name.startsWith('turret_') &&
child.name ===
`turret_${turret.model
.toString()
.padStart(2, '0')}`) ||
(child.name.startsWith('gun_') &&
child.name ===
`gun_${gun.model.toString().padStart(2, '0')}`) ||
{gltf.scene.children[0].children.map((child) => {
const isHull = child.name === 'hull';
const isTurret = child.name.startsWith('turret_');
const isMantlet =
child.name.startsWith('gun_') &&
child.name.endsWith('_mask');
const isGun = child.name.startsWith('gun_') && !isMantlet;
const isVisible =
isHull ||
child.name.startsWith('chassis_track_') ||
child.name.startsWith('chassis_wheel_') ||
(child.name.startsWith('turret_') &&
child.name ===
`gun_${gun.model.toString().padStart(2, '0')}_mask`
`turret_${turret.model
.toString()
.padStart(2, '0')}`) ||
(child.name.startsWith('gun_') &&
child.name ===
`gun_${gun.model.toString().padStart(2, '0')}`) ||
child.name ===
`gun_${gun.model.toString().padStart(2, '0')}_mask`;
let draftTurretRotation = 0;
const position = child.position.clone();
const rotation = new Vector3().setFromEuler(
child.rotation,
);
if (!isVisible) return null;
if (isTurret || isMantlet) {
position
.sub(turretOrigin)
.applyAxisAngle(new Vector3(0, 0, 1), turretRotation)
.add(turretOrigin);
rotation.add(new Vector3(0, 0, turretRotation));
} else if (isGun) {
position
.sub(turretOrigin)
.applyAxisAngle(new Vector3(0, 0, 1), turretRotation)
.add(turretOrigin);
rotation.add(new Vector3(0, 0, turretRotation));
}
function handlePointerDown(
event: ThreeEvent<PointerEvent>,
) {
if (isTurret) {
event.stopPropagation();
draftTurretRotation = turretRotation;
setOrbitControlsEnabled(false);
window.addEventListener(
'pointermove',
handlePointerMove,
);
window.addEventListener('pointerup', handlePointerUp);
}
children={resolveJsxTree(child as Mesh)}
key={child.uuid}
castShadow
receiveShadow
geometry={(child as Mesh).geometry}
material={(child as Mesh).material}
position={child.position}
rotation={child.rotation}
scale={child.scale}
/>
))}
}
function handlePointerMove(event: PointerEvent) {
event.stopPropagation();
event.preventDefault();
const rotationSpeed =
(2 * Math.PI) / canvas.current!.width;
const deltaTurretRotation =
event.movementX * rotationSpeed;
draftTurretRotation += deltaTurretRotation;
if (isTurret) {
if (turretObject3D.current) {
turretObject3D.current.position
.sub(turretOrigin)
.applyAxisAngle(
new Vector3(0, 0, 1),
deltaTurretRotation,
)
.add(turretOrigin);
turretObject3D.current.rotation.z =
draftTurretRotation;
}
if (mantletObject3D.current) {
mantletObject3D.current.position
.sub(turretOrigin)
.applyAxisAngle(
new Vector3(0, 0, 1),
deltaTurretRotation,
)
.add(turretOrigin);
mantletObject3D.current.rotation.z =
draftTurretRotation;
}
if (gunObject3D.current) {
gunObject3D.current.position
.sub(turretOrigin)
.applyAxisAngle(
new Vector3(0, 0, 1),
deltaTurretRotation,
)
.add(turretOrigin);
gunObject3D.current.rotation.z =
draftTurretRotation;
}
}
}
function handlePointerUp(event: PointerEvent) {
setOrbitControlsEnabled(true);
setTurretRotation(draftTurretRotation);
window.removeEventListener(
'pointermove',
handlePointerMove,
);
window.removeEventListener(
'pointerup',
handlePointerUp,
);
}
return (
<mesh
visible={isVisible}
onPointerDown={handlePointerDown}
children={resolveJsxTree(child as Mesh)}
key={child.uuid}
castShadow
receiveShadow
geometry={(child as Mesh).geometry}
material={(child as Mesh).material}
position={position}
rotation={rotation.toArray()}
scale={child.scale}
ref={
isTurret
? turretObject3D
: isGun
? gunObject3D
: isMantlet
? mantletObject3D
: undefined
}
/>
);
})}
</group>
</Canvas>
</div>
+1 -1
View File
@@ -33,7 +33,7 @@ export interface TurretDefinition {
}
export type GunDefinition = GunDefinitionBase &
(GunDefinitionRegular | GunDefinitionAutoLoader | GunDefinitionAutoReloader);
interface GunDefinitionBase {
interface GunDefinitionBase {
id: number;
name: string;
tier: Tier;