feat: some turret traverse penalties

This commit is contained in:
tresabhi committed 2024-12-08 21:51:39 -06:00
1 parent 631af6205e
commit 31a61c8a6b
4 files changed
+74 -35

No files matched your search

@@ -20,7 +20,7 @@ const poseDistances: Record<Pose, number> = {
const modelDefinitions = await awaitableModelDefinitions; const modelDefinitions = await awaitableModelDefinitions;
const ARCADE_MODE_DISTANCE = 12; const ARCADE_MODE_DISTANCE = 19;
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;
@@ -1,40 +1,54 @@
import { imgur } from '@blitzkit/core'; import { imgur } from '@blitzkit/core';
import { Box, type BoxProps } from '@radix-ui/themes'; import { Box, type BoxProps } from '@radix-ui/themes';
import { times } from 'lodash-es';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import { Var } from '../../../../../../../../core/radix/var'; import { Var } from '../../../../../../../../core/radix/var';
const DOTS = 32; const DOTS = 32;
export const TargetCircle = forwardRef<HTMLDivElement, BoxProps>( type TargetCircleProps = BoxProps & {
({ ...props }, ref) => { variant: 'client' | 'server';
};
export const TargetCircle = forwardRef<HTMLDivElement, TargetCircleProps>(
({ style, variant, ...props }, ref) => {
return ( return (
<Box <Box
ref={ref} ref={ref}
position="relative" position="absolute"
top="50%"
left="50%"
minWidth={variant === 'client' ? '23px' : undefined}
minHeight={variant === 'client' ? '23px' : undefined}
style={{
transform: 'translate(-50%, -50%)',
borderRadius: '50%',
outline: `${variant === 'client' ? 2 : 1}px solid ${variant === 'client' ? Var('grass-11') : Var('gray-11')}`,
outlineOffset: `-${variant === 'client' ? 1 : 0.5}px`,
...style,
}}
{...props} {...props}
minWidth="23px"
minHeight="23px"
> >
{times(DOTS, (index) => { {/* {variant === 'client' &&
const angle = 2 * Math.PI * (index / DOTS); times(DOTS, (index) => {
const angle = 2 * Math.PI * (index / DOTS);
return (
<Box
key={index}
style={{
borderRadius: '50%',
background: Var('grass-11'),
transform: `translate(-50%, -50%)`,
position: 'absolute',
}}
top={`${(0.5 * Math.sin(angle) + 0.5) * 100}%`}
left={`${(0.5 * Math.cos(angle) + 0.5) * 100}%`}
width={'calc(1rem / 6)'}
height={'calc(1rem / 6)'}
/>
);
})} */}
return (
<Box
key={index}
style={{
borderRadius: '50%',
background: Var('grass-11'),
transform: `translate(-50%, -50%)`,
position: 'absolute',
}}
top={`${(0.5 * Math.sin(angle) + 0.5) * 100}%`}
left={`${(0.5 * Math.cos(angle) + 0.5) * 100}%`}
width={`${1 / 6}rem`}
height={`${1 / 6}rem`}
/>
);
})}
<Box <Box
width="1rem" width="1rem"
height="1rem" height="1rem"
@@ -12,7 +12,7 @@ import {
Vector3, Vector3,
} from 'three'; } from 'three';
import { GLTFLoader } from 'three/examples/jsm/Addons.js'; import { GLTFLoader } from 'three/examples/jsm/Addons.js';
import { degToRad } from 'three/src/math/MathUtils.js'; import { degToRad, radToDeg } from 'three/src/math/MathUtils.js';
import { awaitableEquipmentDefinitions } from '../../../../../../../core/awaitables/equipmentDefinitions'; import { awaitableEquipmentDefinitions } from '../../../../../../../core/awaitables/equipmentDefinitions';
import { awaitableModelDefinitions } from '../../../../../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../../../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../../../../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../../../../../../core/awaitables/provisionDefinitions';
@@ -40,7 +40,8 @@ export function SceneProps() {
(state) => state.showGrid && !state.showEnvironment, (state) => state.showGrid && !state.showEnvironment,
); );
const targetCircleWrapper = useRef<Group>(null); const targetCircleWrapper = useRef<Group>(null);
const targetCircle = useRef<HTMLDivElement>(null); const clientTargetCircle = useRef<HTMLDivElement>(null);
const serverTargetCircle = useRef<HTMLDivElement>(null);
const material = useRef<MeshStandardMaterial>(null); const material = useRef<MeshStandardMaterial>(null);
const playground = useRef<Group>(null); const playground = useRef<Group>(null);
@@ -70,8 +71,6 @@ export function SceneProps() {
-tankModelDefinition.turret_origin.z, -tankModelDefinition.turret_origin.z,
); );
const gunOriginOnlyY = new Vector3(0, turretModelDefinition.gun_origin.y, 0); const gunOriginOnlyY = new Vector3(0, turretModelDefinition.gun_origin.y, 0);
const turretRotationSpeed = degToRad(turret.traverse_speed);
const gunRotationSpeed = degToRad(gun.gun_type!.value.base.rotation_speed);
const shellOrigin = new Vector3() const shellOrigin = new Vector3()
.add(hullOrigin) .add(hullOrigin)
.add(turretOrigin) .add(turretOrigin)
@@ -106,6 +105,9 @@ export function SceneProps() {
}, },
{ equipmentDefinitions, provisionDefinitions, tankModelDefinition }, { equipmentDefinitions, provisionDefinitions, tankModelDefinition },
); );
let { dispersion } = characteristics;
const turretRotationSpeed = degToRad(characteristics.turretTraverseSpeed);
const gunRotationSpeed = degToRad(characteristics.gunTraverseSpeed);
const mockTank = useLoader(GLTFLoader, asset(`3d/tanks/models/12305.glb`)); const mockTank = useLoader(GLTFLoader, asset(`3d/tanks/models/12305.glb`));
const texture = useLoader(TextureLoader, imgur('C28Z8nU')); const texture = useLoader(TextureLoader, imgur('C28Z8nU'));
@@ -125,7 +127,8 @@ export function SceneProps() {
!playground.current || !playground.current ||
!targetCircleWrapper.current || !targetCircleWrapper.current ||
DEBUG_disable || DEBUG_disable ||
!targetCircle.current !clientTargetCircle.current ||
!serverTargetCircle.current
) { ) {
return; return;
} }
@@ -152,6 +155,7 @@ export function SceneProps() {
const deltaT = clock.elapsedTime - lastTime; const deltaT = clock.elapsedTime - lastTime;
lastTime = clock.elapsedTime; lastTime = clock.elapsedTime;
const desiredPitch = Math.asin(direction.y); const desiredPitch = Math.asin(direction.y);
const desiredYaw = Math.atan2(-direction.x, -direction.z); const desiredYaw = Math.atan2(-direction.x, -direction.z);
const deltaPitch = desiredPitch - lastPitch; const deltaPitch = desiredPitch - lastPitch;
@@ -170,6 +174,22 @@ export function SceneProps() {
turretModelDefinition.yaw, turretModelDefinition.yaw,
); );
const deltaRotation = Math.abs(maxDeltaPitch) + Math.abs(maxDeltaYaw);
const rotationSpeed = deltaRotation;
const turretTraversePenalty =
characteristics.dispersionTurretTraversing * radToDeg(rotationSpeed);
const penalty = turretTraversePenalty;
const dispersionMod = dispersion - characteristics.dispersion;
const dispersionModDischarged =
dispersionMod * Math.exp(-deltaT / characteristics.aimTime) -
dispersionMod;
dispersion += penalty + dispersionModDischarged;
document.title = `${dispersion.toFixed(3)} (${penalty.toFixed(3)})`;
modelTransformEvent.emit({ pitch, yaw }); modelTransformEvent.emit({ pitch, yaw });
lastPitch = pitch; lastPitch = pitch;
lastYaw = yaw; lastYaw = yaw;
@@ -198,8 +218,7 @@ export function SceneProps() {
targetCircleWrapper.current.position.copy(gunTarget); targetCircleWrapper.current.position.copy(gunTarget);
const distanceToTarget = gunTarget.distanceTo(shellOrigin); const distanceToTarget = gunTarget.distanceTo(shellOrigin);
const dispersionRadius = const dispersionRadius = dispersion * (distanceToTarget / 100);
characteristics.dispersion * (distanceToTarget / 100);
const dispersionSize = 2 * dispersionRadius; const dispersionSize = 2 * dispersionRadius;
const targetDistanceFromCamera = gunTarget.distanceTo(camera.position); const targetDistanceFromCamera = gunTarget.distanceTo(camera.position);
const angularSize = const angularSize =
@@ -210,8 +229,10 @@ export function SceneProps() {
gl.domElement.clientHeight * (angularSize / verticalScreenSize); gl.domElement.clientHeight * (angularSize / verticalScreenSize);
const targetCircleDotsSize = `${screenSpaceSize}px`; const targetCircleDotsSize = `${screenSpaceSize}px`;
targetCircle.current.style.width = targetCircleDotsSize; clientTargetCircle.current.style.width = targetCircleDotsSize;
targetCircle.current.style.height = targetCircleDotsSize; clientTargetCircle.current.style.height = targetCircleDotsSize;
serverTargetCircle.current.style.width = targetCircleDotsSize;
serverTargetCircle.current.style.height = targetCircleDotsSize;
}); });
return ( return (
@@ -227,7 +248,8 @@ export function SceneProps() {
<> <>
<group ref={targetCircleWrapper}> <group ref={targetCircleWrapper}>
<Html center occlude={false} zIndexRange={[0, 0]}> <Html center occlude={false} zIndexRange={[0, 0]}>
<TargetCircle ref={targetCircle} /> <TargetCircle variant="client" ref={clientTargetCircle} />
<TargetCircle variant="server" ref={serverTargetCircle} />
</Html> </Html>
</group> </group>
@@ -461,6 +461,8 @@ export function tankCharacteristics(
resolvedEnginePower / weightTons / softTerrainCoefficientRaw; resolvedEnginePower / weightTons / softTerrainCoefficientRaw;
const weight = weightTons; const weight = weightTons;
const turretTraverseSpeed = turret.traverse_speed * turretTraverseCoefficient; const turretTraverseSpeed = turret.traverse_speed * turretTraverseCoefficient;
const gunTraverseSpeed =
gun.gun_type!.value.base.rotation_speed * turretTraverseCoefficient;
const hullTraverseHardTerrain = const hullTraverseHardTerrain =
(resolvedEnginePower / stockEngine.power) * (resolvedEnginePower / stockEngine.power) *
track.traverse_speed * track.traverse_speed *
@@ -555,6 +557,7 @@ export function tankCharacteristics(
powerToWeightRatioSoftTerrain, powerToWeightRatioSoftTerrain,
weight, weight,
turretTraverseSpeed, turretTraverseSpeed,
gunTraverseSpeed, // TODO: display this
hullTraverseHardTerrain, hullTraverseHardTerrain,
hullTraverseMediumTerrain, hullTraverseMediumTerrain,
hullTraverseSoftTerrain, hullTraverseSoftTerrain,