feat: remove shooting range

This commit is contained in:
TrèsAbhi committed 2025-08-06 12:23:57 -05:00
1 parent b3046d8655
commit ea90ca21b1
10 files changed
+18 -262

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

@@ -15,7 +15,6 @@ import {
GearIcon,
} from '@radix-ui/react-icons';
import {
Box,
Button,
Checkbox,
Dialog,
@@ -36,10 +35,7 @@ import { useFullscreenAvailability } from '../../../../../hooks/useFullscreenAva
import { useLocale } from '../../../../../hooks/useLocale';
import { App } from '../../../../../stores/app';
import { Duel } from '../../../../../stores/duel';
import {
ShootingRangeZoom,
TankopediaEphemeral,
} from '../../../../../stores/tankopediaEphemeral';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
import type { MaybeSkeletonComponentProps } from '../../../../../types/maybeSkeletonComponentProps';
@@ -97,23 +93,6 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
<>
{disturbed && <QuickInputs />}
{display === TankopediaDisplay.ShootingRange && (
<Box
width="1rem"
height="1rem"
position="absolute"
top="50%"
left="50%"
style={{
zIndex: 2,
backgroundImage: 'url(/assets/images/icons/aim-caret.png)',
backgroundSize: 'contain',
transform: 'translateX(-50%)',
borderRadius: '50%',
}}
/>
)}
<Thicknesses skeleton={skeleton} thicknessRange={thicknessRange} />
<Flex
@@ -408,7 +387,6 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
mutateTankopediaEphemeral((draft) => {
draft.disturbed = true;
draft.display = Number(value);
draft.shootingRangeZoom = ShootingRangeZoom.Arcade;
});
}}
>
@@ -448,13 +426,6 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
</Flex>
</Tooltip>
</SegmentedControl.Item>
{/* <SegmentedControl.Item value={`${TankopediaDisplay.ShootingRange}`}>
<Tooltip content="Shooting range">
<Flex height="100%" align="center">
<img src="/assets/images/icons/tankopedia-shooting-range.png" style={{ height: '1.25em' }} />
</Flex>
</Tooltip>
</SegmentedControl.Item> */}
</SegmentedControl.Root>
{disturbed && (
@@ -1,7 +1,6 @@
import { I_HAT, J_HAT } from '@blitzkit/core';
import { OrbitControls } from '@react-three/drei';
import { invalidate, useThree } from '@react-three/fiber';
import { clamp } from 'lodash-es';
import { useEffect, useRef } from 'react';
import { PerspectiveCamera, Vector3 } from 'three';
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
@@ -11,13 +10,7 @@ import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawL
import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose';
import { Duel } from '../../../../../../stores/duel';
import {
SHOOTING_RANGE_ZOOM_COEFFICIENTS,
ShootingRangeZoom,
TankopediaEphemeral,
} from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
import { aimTarget } from './SceneProps/constants';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
const poseDistances: Record<Pose, number> = {
[Pose.HullDown]: 15,
@@ -254,36 +247,11 @@ export function Controls({
useEffect(() => {
let isInitialIteration = true;
function handleKeyDown(event: KeyboardEvent) {
if (display !== TankopediaDisplay.ShootingRange || event.repeat) return;
if (event.key === 'Shift') {
mutateTankopediaEphemeral((draft) => {
draft.shootingRangeZoom =
draft.shootingRangeZoom === ShootingRangeZoom.Arcade
? ShootingRangeZoom.Zoom0
: ShootingRangeZoom.Arcade;
});
}
}
function handleWheel(event: WheelEvent) {
if (display !== TankopediaDisplay.ShootingRange) return;
event.preventDefault();
mutateTankopediaEphemeral((draft) => {
draft.shootingRangeZoom = clamp(
draft.shootingRangeZoom - Math.sign(event.deltaY),
ShootingRangeZoom.Arcade,
ShootingRangeZoom.Zoom2,
);
});
}
function handleScroll(event: Event) {
if (display !== TankopediaDisplay.ShootingRange) return;
event.preventDefault();
}
@@ -295,7 +263,6 @@ export function Controls({
poseEvent.on(disturb);
canvas.addEventListener('pointerdown', disturb);
window.addEventListener('keydown', handleKeyDown);
canvas.addEventListener('wheel', handleWheel);
document.body.addEventListener('scroll', handleScroll);
@@ -304,80 +271,24 @@ export function Controls({
orbitControls.current.rotateSpeed = 0.25;
if (display === TankopediaDisplay.ShootingRange) {
const { shootingRangeZoom } = tankopediaEphemeralStore.getState();
orbitControls.current.enablePan = false;
orbitControls.current.enableZoom = false;
orbitControls.current.rotateSpeed *=
SHOOTING_RANGE_ZOOM_COEFFICIENTS[shootingRangeZoom];
camera.fov =
ARCADE_MODE_FOV * SHOOTING_RANGE_ZOOM_COEFFICIENTS[shootingRangeZoom];
if (shootingRangeZoom === ShootingRangeZoom.Arcade) {
orbitControls.current.target.set(0, gunHeight + 3, 0);
if (isInitialIteration) {
isInitialIteration = false;
camera.position.set(
0,
gunHeight + ARCADE_MODE_DISTANCE * Math.sin(ARCADE_MODE_ANGLE),
ARCADE_MODE_DISTANCE * Math.cos(ARCADE_MODE_ANGLE),
);
} else {
camera.position
.copy(aimTarget)
.sub(orbitControls.current.target)
.normalize()
.multiplyScalar(-ARCADE_MODE_DISTANCE)
.add(orbitControls.current.target);
}
} else {
orbitControls.current.target.copy(shellOrigin);
camera.position
.copy(aimTarget)
.sub(shellOrigin)
.normalize()
.multiplyScalar(-Number.EPSILON)
.add(shellOrigin);
}
} else {
camera.position.copy(inspectModeInitialPosition);
orbitControls.current.target.set(0, gunHeight / (naked ? 4 : 2), 0);
orbitControls.current.enablePan = true;
orbitControls.current.enableZoom = true;
camera.fov = naked ? 20 : 25;
}
camera.position.copy(inspectModeInitialPosition);
orbitControls.current.target.set(0, gunHeight / (naked ? 4 : 2), 0);
orbitControls.current.enablePan = true;
orbitControls.current.enableZoom = true;
camera.fov = naked ? 20 : 25;
camera.updateProjectionMatrix();
}
updateCamera();
const unsubscribeDisplay = tankopediaEphemeralStore.subscribe(
(state) => state.display === TankopediaDisplay.ShootingRange,
() => {
disturb();
updateCamera();
},
);
const unsubscribeShootingRangeZoom = tankopediaEphemeralStore.subscribe(
(state) => state.shootingRangeZoom,
updateCamera,
);
return () => {
canvas.removeEventListener('pointerdown', disturb);
poseEvent.off(disturb);
unsubscribeDisplay();
unsubscribeShootingRangeZoom();
window.removeEventListener('keydown', handleKeyDown);
canvas.removeEventListener('wheel', handleWheel);
document.body.removeEventListener('scroll', handleScroll);
};
}, [display === TankopediaDisplay.ShootingRange]);
}, []);
return (
<OrbitControls
@@ -1,5 +1,4 @@
import { Environment } from '@react-three/drei';
import { times } from 'lodash-es';
import { Euler } from 'three';
import { degToRad } from 'three/src/math/MathUtils.js';
import { useModel } from '../../../../../../hooks/useModel';
@@ -30,24 +29,6 @@ export function Lighting({ display }: LightingProps) {
{display === TankopediaDisplay.StaticArmor && (
<Environment preset="lobby" />
)}
{display === TankopediaDisplay.ShootingRange && (
<>
<directionalLight position={[0, -1, 0]} />
{times(LIGHTS_COUNT, (index) => (
<directionalLight
key={index}
castShadow
intensity={3 / LIGHTS_COUNT}
position={[
Math.sin(2 * Math.PI * (index / LIGHTS_COUNT)),
1,
Math.cos(2 * Math.PI * (index / LIGHTS_COUNT)),
]}
/>
))}
</>
)}
</>
);
}
@@ -1,5 +1,4 @@
import { asset, I_HAT, J_HAT } from '@blitzkit/core';
import { Html } from '@react-three/drei';
import { useFrame, useLoader } from '@react-three/fiber';
import { clamp } from 'lodash-es';
import { useRef } from 'react';
@@ -21,8 +20,6 @@ import { modelTransformEvent } from '../../../../../../../core/blitzkit/modelTra
import { tankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
import { Duel } from '../../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../../stores/tankopediaEphemeral';
import { TankopediaDisplay } from '../../../../../../../stores/tankopediaPersistent/constants';
import { TargetCircle } from './components/TargetCircle';
import { aimTarget } from './constants';
const [modelDefinitions, equipmentDefinitions, provisionDefinitions] =
@@ -121,7 +118,6 @@ export function SceneProps() {
useFrame(({ raycaster, camera, clock, gl }) => {
if (
display !== TankopediaDisplay.ShootingRange ||
!playground.current ||
!targetCircleWrapper.current ||
DEBUG_disable ||
@@ -241,45 +237,9 @@ export function SceneProps() {
if (!disturbed) return null;
return (
<>
{display !== TankopediaDisplay.ShootingRange && (
<mesh rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial ref={material} map={texture} transparent />
</mesh>
)}
{display === TankopediaDisplay.ShootingRange && (
<>
<group ref={targetCircleWrapper}>
<Html center occlude={false} zIndexRange={[0, 0]}>
<TargetCircle variant="client" ref={clientTargetCircle} />
<TargetCircle variant="server" ref={serverTargetCircle} />
</Html>
</group>
<group ref={playground}>
<mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
<planeGeometry args={[100, 100]} />
<meshStandardMaterial color={0x404040} />
</mesh>
<mesh
receiveShadow
castShadow
position={[10, 1.5, -10]}
rotation={[0, Math.PI / 4, 0]}
>
<boxGeometry args={[1, 3, 1]} />
<meshStandardMaterial color={0xff8040} />
</mesh>
<group position={[0, 0, -25]} rotation={[-Math.PI / 2, 0, Math.PI]}>
<primitive object={mockTank.scene} />
</group>
</group>
</>
)}
</>
<mesh rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial ref={material} map={texture} transparent />
</mesh>
);
}
@@ -1,6 +1,6 @@
import { normalizeAngleRad } from '@blitzkit/core';
import { invalidate, useThree, type ThreeEvent } from '@react-three/fiber';
import { useEffect, useRef } from 'react';
import { useRef } from 'react';
import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three';
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
@@ -10,10 +10,7 @@ import { useModel } from '../../../../../../hooks/useModel';
import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefinition';
import { useTankTransform } from '../../../../../../hooks/useTankTransform';
import { Duel } from '../../../../../../stores/duel';
import {
ShootingRangeZoom,
TankopediaEphemeral,
} from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
import { ModelTankWrapper } from '../../../../../Armor/components/ModelTankWrapper';
@@ -37,18 +34,6 @@ export function TankModel() {
const { gltf } = useModel(protagonist.tank.id);
const nodes = Object.values(gltf.nodes);
useEffect(() => {
const unsubscribeShootingRangeZoom = tankopediaEphemeralStore.subscribe(
(state) => state.shootingRangeZoom,
(zoom) => {
if (!hullContainer.current) return;
hullContainer.current.visible = zoom === ShootingRangeZoom.Arcade;
},
);
return unsubscribeShootingRangeZoom;
}, []);
useTankTransform(track, turret, turretContainer, gunContainer);
return (
@@ -163,12 +148,7 @@ export function TankModel() {
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
if (
!isTurret ||
tankopediaEphemeralStore.getState().display ===
TankopediaDisplay.ShootingRange
)
return;
if (!isTurret) return;
position.set(event.clientX, event.clientY);
yaw = protagonist.yaw;
@@ -277,12 +257,6 @@ export function TankModel() {
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
if (
tankopediaEphemeralStore.getState().display ===
TankopediaDisplay.ShootingRange
)
return;
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = false;
});
@@ -1,14 +1,11 @@
import { useEffect, useRef } from 'react';
import { useRef } from 'react';
import { Group, ShaderMaterial, UniformsLib, UniformsUtils } from 'three';
import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree';
import { useModel } from '../../../../../../../hooks/useModel';
import { useTankModelDefinition } from '../../../../../../../hooks/useTankModelDefinition';
import { useTankTransform } from '../../../../../../../hooks/useTankTransform';
import { Duel } from '../../../../../../../stores/duel';
import {
ShootingRangeZoom,
TankopediaEphemeral,
} from '../../../../../../../stores/tankopediaEphemeral';
import { TankopediaEphemeral } from '../../../../../../../stores/tankopediaEphemeral';
import { ModelTankWrapper } from '../../../../../../Armor/components/ModelTankWrapper';
import fragmentShader from './shaders/fragment.glsl?raw';
import vertexShader from './shaders/vertex.glsl?raw';
@@ -40,18 +37,6 @@ export function TransitionSkeleton() {
const nodes = Object.values(gltf.nodes);
const revealed = tankopediaEphemeralStore((state) => state.revealed);
useEffect(() => {
const unsubscribeShootingRangeZoom = tankopediaEphemeralStore.subscribe(
(state) => state.shootingRangeZoom,
(zoom) => {
if (!hullContainer.current) return;
hullContainer.current.visible = zoom === ShootingRangeZoom.Arcade;
},
);
return unsubscribeShootingRangeZoom;
}, []);
useTankTransform(track, turret, turretContainer, gunContainer);
return (
@@ -207,13 +207,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
<Canvas
ref={canvas}
scene={{ fog: naked ? undefined : fog.current }}
frameloop={
onScreen
? display === TankopediaDisplay.ShootingRange
? 'always'
: 'demand'
: 'never'
}
frameloop={onScreen ? 'demand' : 'never'}
gl={{
clippingPlanes: [],
localClippingEnabled: true,
@@ -78,28 +78,10 @@ export enum TankopediaRelativeAgainst {
All,
}
export enum ShootingRangeZoom {
Arcade,
Zoom0,
Zoom1,
Zoom2,
}
export const SHOOTING_RANGE_ZOOM_COEFFICIENTS: Record<
ShootingRangeZoom,
number
> = {
[ShootingRangeZoom.Arcade]: 1,
[ShootingRangeZoom.Zoom0]: 1 / 8,
[ShootingRangeZoom.Zoom1]: 1 / 16,
[ShootingRangeZoom.Zoom2]: 1 / 25,
};
interface TankopediaEphemeral {
disturbed: boolean;
revealed: boolean;
shot?: Shot;
shootingRangeZoom: ShootingRangeZoom;
skills: Record<string, number>;
relativeAgainst: TankopediaRelativeAgainst;
controlsEnabled: boolean;
@@ -133,7 +115,6 @@ export const TankopediaEphemeral = createContextualStore(
subscribeWithSelector<TankopediaEphemeral>(() => ({
disturbed: false,
revealed: false,
shootingRangeZoom: ShootingRangeZoom.Arcade,
relativeAgainst: TankopediaRelativeAgainst.Class,
editStatic: false,
skills: createDefaultSkills(skillDefinitions),
@@ -38,5 +38,4 @@ export enum TankopediaDisplay {
Model,
DynamicArmor,
StaticArmor,
ShootingRange,
}