diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps.tsx index 7a88c5a2b..14bfa263e 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps.tsx @@ -2,20 +2,28 @@ import { useFrame, useLoader } from '@react-three/fiber'; import { clamp } from 'lodash-es'; import { useRef } from 'react'; import { + ArrowHelper, AxesHelper, Group, MeshStandardMaterial, TextureLoader, Vector2, + Vector3, } from 'three'; +import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions'; +import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits'; +import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform'; +import { Duel } from '../../../../../../stores/duel'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent'; import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants'; const emptyVector = new Vector2(); +const modelDefinitions = await awaitableModelDefinitions; export function SceneProps() { - const helper = useRef(null); + const shellTargetHelper = useRef(null); + const shellPathHelper = useRef(null); const show = TankopediaPersistent.use( (state) => state.showGrid && !state.showEnvironment, ); @@ -23,6 +31,44 @@ export function SceneProps() { const material = useRef(null); const display = TankopediaEphemeral.use((state) => state.display); const playground = useRef(null); + const protagonistTurret = Duel.use((state) => state.protagonist.turret); + const protagonistTrack = Duel.use((state) => state.protagonist.track); + const protagonistTank = Duel.use((state) => state.protagonist.tank); + const protagonistGun = Duel.use((state) => state.protagonist.gun); + const protagonistModelDefinition = + modelDefinitions.models[protagonistTank.id]; + const protagonistTrackModelDefinition = + modelDefinitions.models[protagonistTank.id].tracks[protagonistTrack.id]; + const protagonistGunModelDefinition = + protagonistModelDefinition.turrets[protagonistTurret.id].guns[ + protagonistGun.gun_type!.value.base.id + ]; + const protagonistTurretModelDefinition = + protagonistModelDefinition.turrets[protagonistTurret.id]; + const protagonistHullOrigin = new Vector3( + protagonistTrackModelDefinition.origin.x, + protagonistTrackModelDefinition.origin.y, + -protagonistTrackModelDefinition.origin.z, + ); + const protagonistTurretOrigin = new Vector3( + protagonistModelDefinition.turret_origin.x, + protagonistModelDefinition.turret_origin.y, + -protagonistModelDefinition.turret_origin.z, + ); + const protagonistGunOrigin = new Vector3( + protagonistTurretModelDefinition.gun_origin.x, + protagonistTurretModelDefinition.gun_origin.y, + -protagonistTurretModelDefinition.gun_origin.z, + ); + const protagonistGunOriginOnlyY = new Vector3( + 0, + protagonistTurretModelDefinition.gun_origin.y, + 0, + ); + const shellOrigin = new Vector3() + .add(protagonistHullOrigin) + .add(protagonistTurretOrigin) + .add(protagonistGunOriginOnlyY); useFrame(({ camera }) => { if (!material.current) return; @@ -31,11 +77,12 @@ export function SceneProps() { texture.anisotropy = 2; - useFrame(({ raycaster, scene, camera }) => { + useFrame(({ raycaster, camera, clock }) => { if ( display !== TankopediaDisplay.ShootingRange || !playground.current || - !helper.current + !shellTargetHelper.current || + !shellPathHelper.current ) { return; } @@ -49,7 +96,21 @@ export function SceneProps() { if (intersections.length === 0) return; - helper.current.position.copy(intersections[0].point); + const target = intersections[0].point; + const path = target.clone().sub(shellOrigin); + const direction = path.clone().normalize(); + + shellTargetHelper.current.position.copy(intersections[0].point); + shellPathHelper.current.setDirection(direction); + shellPathHelper.current.setLength(path.length()); + + const [pitch, yaw] = applyPitchYawLimits( + Math.asin(direction.y), + Math.atan2(-direction.x, -direction.z), + protagonistGunModelDefinition.pitch, + ); + + modelTransformEvent.emit({ pitch, yaw }); }); return ( @@ -63,7 +124,8 @@ export function SceneProps() { {display === TankopediaDisplay.ShootingRange && ( <> - + + @@ -80,6 +142,11 @@ export function SceneProps() { + + + + + )}