mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: turret rotation
This commit is contained in:
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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -33,7 +33,7 @@ export interface TurretDefinition {
|
||||
}
|
||||
export type GunDefinition = GunDefinitionBase &
|
||||
(GunDefinitionRegular | GunDefinitionAutoLoader | GunDefinitionAutoReloader);
|
||||
interface GunDefinitionBase {
|
||||
interface GunDefinitionBase {
|
||||
id: number;
|
||||
name: string;
|
||||
tier: Tier;
|
||||
|
||||
Reference in new issue
Block a user