feat: aiming caster

This commit is contained in:
tresabhi committed 2024-12-01 22:11:38 -06:00
1 parent 5a34a35638
commit 65c52c2e82
3 files changed
+45 -21

No files matched your search

@@ -1,7 +1,7 @@
import { OrbitControls } from '@react-three/drei'; import { OrbitControls } from '@react-three/drei';
import { invalidate, useThree } from '@react-three/fiber'; import { invalidate, useThree } from '@react-three/fiber';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { PerspectiveCamera, Vector3 } from 'three'; import { AxesHelper, PerspectiveCamera, Vector2, Vector3 } from 'three';
import { OrbitControls as OrbitControlsClass } from 'three-stdlib'; import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
import { degToRad } from 'three/src/math/MathUtils.js'; import { degToRad } from 'three/src/math/MathUtils.js';
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
@@ -22,11 +22,13 @@ const modelDefinitions = await awaitableModelDefinitions;
const ARCADE_MODE_DISTANCE = 16; const ARCADE_MODE_DISTANCE = 16;
const ARCADE_MODE_ANGLE = Math.PI / 8; const ARCADE_MODE_ANGLE = Math.PI / 8;
export const ARCADE_MODE_FOV = 54; export const ARCADE_MODE_FOV = 54;
export const INSPECT_MODE_FOV = 25; export const INSPECT_MODE_FOV = 25;
const emptyVector = new Vector2();
export function Controls() { export function Controls() {
const helper = useRef<AxesHelper>(null);
const display = TankopediaEphemeral.use((state) => state.display); const display = TankopediaEphemeral.use((state) => state.display);
const duelStore = Duel.useStore(); const duelStore = Duel.useStore();
const tankopediaEphemeralStore = TankopediaEphemeral.useStore(); const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
@@ -79,6 +81,8 @@ export function Controls() {
protagonistTurretOrigin.y + protagonistTurretOrigin.y +
protagonistGunOrigin.y; protagonistGunOrigin.y;
const initialPosition = [-8, gunHeight + 4, -13] as const; const initialPosition = [-8, gunHeight + 4, -13] as const;
const raycaster = useThree((state) => state.raycaster);
const scene = useThree((state) => state.scene);
useEffect(() => { useEffect(() => {
if (!orbitControls.current) return; if (!orbitControls.current) return;
@@ -232,19 +236,39 @@ export function Controls() {
}; };
}, []); }, []);
useEffect(() => {}, [display]);
return ( return (
<OrbitControls <>
maxDistance={20} <axesHelper ref={helper} />
minDistance={5} <OrbitControls
ref={orbitControls} maxDistance={20}
enabled={tankopediaEphemeralStore.getState().controlsEnabled} minDistance={5}
rotateSpeed={0.25} ref={orbitControls}
enableDamping={false} enabled={tankopediaEphemeralStore.getState().controlsEnabled}
maxPolarAngle={degToRad(100)} rotateSpeed={0.25}
autoRotate={autoRotate} enableDamping={false}
autoRotateSpeed={1 / 4} maxPolarAngle={degToRad(100)}
/> autoRotate={autoRotate}
autoRotateSpeed={1 / 4}
onChange={() => {
if (display !== TankopediaDisplay.ShootingRange || !helper.current) {
return;
}
raycaster.setFromCamera(emptyVector, camera);
const intersections = raycaster.intersectObjects(
scene.children,
true,
);
const first = intersections.find(
(intersection) => intersection.object !== helper.current,
);
if (first === undefined) return;
helper.current.position.copy(first.point);
}}
/>
</>
); );
} }
@@ -34,6 +34,7 @@ export function Lighting() {
{times(LIGHTS_COUNT, (index) => ( {times(LIGHTS_COUNT, (index) => (
<directionalLight <directionalLight
key={index}
castShadow castShadow
position={[ position={[
Math.sin(2 * Math.PI * (index / LIGHTS_COUNT)), Math.sin(2 * Math.PI * (index / LIGHTS_COUNT)),
@@ -14,7 +14,6 @@ import { useOnScreen } from '../../../../../hooks/useOnScreen';
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition'; import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
import { Duel } from '../../../../../stores/duel'; import { Duel } from '../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants'; import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
import { Armor } from '../../../../Armor'; import { Armor } from '../../../../Armor';
import { ArmorPlateDisplay } from '../../../../Armor/components/ArmorPlateDisplay'; import { ArmorPlateDisplay } from '../../../../Armor/components/ArmorPlateDisplay';
@@ -39,15 +38,15 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
const canvas = useRef<HTMLCanvasElement>(null); const canvas = useRef<HTMLCanvasElement>(null);
const hasImprovedVerticalStabilizer = useEquipment(122); const hasImprovedVerticalStabilizer = useEquipment(122);
const protagonist = Duel.use((state) => state.protagonist); const protagonistGun = Duel.use((state) => state.protagonist.gun);
const protagonistTurret = Duel.use((state) => state.protagonist.turret);
const mutateDuel = Duel.useMutation(); const mutateDuel = Duel.useMutation();
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const turretModelDefinition = const turretModelDefinition =
tankModelDefinition.turrets[protagonist.turret.id]; tankModelDefinition.turrets[protagonistTurret.id];
const gunModelDefinition = const gunModelDefinition =
turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id]; turretModelDefinition.guns[protagonistGun.gun_type!.value.base.id];
const display = TankopediaEphemeral.use((state) => state.display); const display = TankopediaEphemeral.use((state) => state.display);
const tankopediaPersistentStore = TankopediaPersistent.useStore();
const onScreen = useOnScreen(canvas); const onScreen = useOnScreen(canvas);
useImperativeHandle(ref, () => canvas.current!, []); useImperativeHandle(ref, () => canvas.current!, []);
@@ -141,7 +140,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
hasImprovedVerticalStabilizer, hasImprovedVerticalStabilizer,
); );
}); });
}, [protagonist.gun, protagonist.turret]); }, [protagonistGun, protagonistTurret]);
useEffect(() => { useEffect(() => {
if (display !== TankopediaDisplay.DynamicArmor) { if (display !== TankopediaDisplay.DynamicArmor) {