feat: remove reactive pitch and yaw

This commit is contained in:
TrèsAbhi committed 2025-08-12 13:43:11 -05:00
1 parent 4ddf77fc7f
commit 94cba0c9ba
12 files changed
+141 -190

No files matched your search

@@ -1,4 +1,3 @@
import { normalizeAngleRad } from '@blitzkit/core';
import { useThree, type ThreeEvent } from '@react-three/fiber';
import { memo, useRef } from 'react';
import { Group, Plane, Vector2, Vector3 } from 'three';
@@ -153,15 +152,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
const position = new Vector2();
const delta = new Vector2();
let pitch = 0;
let yaw = 0;
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
position.set(event.clientX, event.clientY);
yaw = protagonist.yaw;
pitch = protagonist.pitch;
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = false;
@@ -190,9 +185,10 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
[pitch, yaw] = applyPitchYawLimits(
pitch,
yaw + delta.x * (Math.PI / boundingRect.width),
const [pitch, yaw] = applyPitchYawLimits(
modelTransformEvent.last!.pitch,
modelTransformEvent.last!.yaw +
delta.x * (Math.PI / boundingRect.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
@@ -201,10 +197,6 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
modelTransformEvent.dispatch({ pitch, yaw });
}
function handlePointerUp() {
mutateDuel((draft) => {
draft.protagonist.pitch = normalizeAngleRad(pitch);
draft.protagonist.yaw = normalizeAngleRad(yaw);
});
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = true;
});
@@ -253,8 +245,6 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
const position = new Vector2();
const delta = new Vector2();
let pitch = 0;
let yaw = 0;
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
@@ -268,8 +258,6 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
});
position.set(event.clientX, event.clientY);
pitch = protagonist.pitch;
yaw = protagonist.yaw;
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
@@ -290,9 +278,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
[pitch, yaw] = applyPitchYawLimits(
pitch - delta.y * (Math.PI / boundingRect.height),
yaw + delta.x * (Math.PI / boundingRect.width),
const [pitch, yaw] = applyPitchYawLimits(
modelTransformEvent.last!.pitch -
delta.y * (Math.PI / boundingRect.height),
modelTransformEvent.last!.yaw +
delta.x * (Math.PI / boundingRect.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
@@ -304,10 +294,6 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = true;
});
mutateDuel((draft) => {
draft.protagonist.pitch = normalizeAngleRad(pitch);
draft.protagonist.yaw = normalizeAngleRad(yaw);
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
}
@@ -341,8 +327,6 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
const position = new Vector2();
const delta = new Vector2();
let pitch = 0;
let yaw = 0;
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
@@ -356,9 +340,6 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
});
position.set(event.clientX, event.clientY);
pitch = protagonist.pitch;
yaw = protagonist.yaw;
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}
@@ -378,9 +359,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
[pitch, yaw] = applyPitchYawLimits(
pitch - delta.y * (Math.PI / boundingRect.height),
yaw + delta.x * (Math.PI / boundingRect.width),
const [pitch, yaw] = applyPitchYawLimits(
modelTransformEvent.last!.pitch -
delta.y * (Math.PI / boundingRect.height),
modelTransformEvent.last!.yaw +
delta.x * (Math.PI / boundingRect.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
@@ -392,10 +375,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = true;
});
mutateDuel((draft) => {
draft.protagonist.pitch = normalizeAngleRad(pitch);
draft.protagonist.yaw = normalizeAngleRad(yaw);
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
}
@@ -1,6 +1,7 @@
import { I_HAT, J_HAT } from '@blitzkit/core';
import { type MeshProps, useThree } from '@react-three/fiber';
import { clamp } from 'lodash-es';
import type { QuicklimeEvent } from 'quicklime';
import { useEffect, useMemo } from 'react';
import {
Box3,
@@ -186,16 +187,18 @@ export function StaticArmorSceneComponent({
const distanceToBarrel = clip.distanceToPoint(barrelOrigin);
const point = new Vector3();
function handleModelTransform(data: ModelTransformEventData) {
function handleModelTransform(
event: QuicklimeEvent<ModelTransformEventData>,
) {
clip.normal
.set(0, 0, -1)
.applyAxisAngle(I_HAT, data.pitch)
.applyAxisAngle(J_HAT, data.yaw ?? 0);
.applyAxisAngle(I_HAT, event.data.pitch)
.applyAxisAngle(J_HAT, event.data.yaw);
clip.constant = 0;
point
.copy(gunOrigin)
.applyAxisAngle(J_HAT, data.yaw ?? 0)
.applyAxisAngle(J_HAT, event.data.yaw)
.add(clip.normal.multiplyScalar(-distanceToBarrel))
.add(neckOrigin);
clip.normal.normalize();
@@ -3,6 +3,7 @@ import { useEffect } from 'react';
import { awaitableEquipmentDefinitions } from '../../../../../core/awaitables/equipmentDefinitions';
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimits';
import { modelTransformEvent } from '../../../../../core/blitzkit/modelTransform';
import { tankCharacteristics } from '../../../../../core/blitzkit/tankCharacteristics';
import { useEquipment } from '../../../../../hooks/useEquipment';
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
@@ -75,16 +76,16 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
const hasDownImprovedVerticalStabilizer = useEquipment(124);
useEffect(() => {
mutateDuel((draft) => {
[draft.protagonist.pitch, draft.protagonist.yaw] = applyPitchYawLimits(
draft.protagonist.pitch,
draft.protagonist.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
});
const [pitch, yaw] = applyPitchYawLimits(
modelTransformEvent.last!.pitch,
modelTransformEvent.last!.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
}, [hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer]);
return (
@@ -1,5 +1,6 @@
import { HeightIcon, WidthIcon } from '@radix-ui/react-icons';
import { Flex, TextField } from '@radix-ui/themes';
import type { QuicklimeEvent } from 'quicklime';
import { useEffect, useRef } from 'react';
import { degToRad, radToDeg } from 'three/src/math/MathUtils.js';
import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
@@ -28,31 +29,19 @@ export function QuickInputs() {
const hasDownImprovedVerticalStabilizer = useEquipment(124);
useEffect(() => {
if (!yawInput.current) return;
yawInput.current.value = radToDeg(protagonist.yaw).toFixed(1);
}, [protagonist.yaw]);
useEffect(() => {
if (!pitchInput.current) return;
pitchInput.current.value = (
-radToDeg(protagonist.pitch) + initialGunPitch
).toFixed(1);
}, [protagonist.pitch]);
useEffect(() => {
function handleTransformEvent({ pitch, yaw }: ModelTransformEventData) {
function handleTransformEvent(
event: QuicklimeEvent<ModelTransformEventData>,
) {
if (!pitchInput.current || !yawInput.current) return;
pitchInput.current.value = (
-radToDeg(pitch) +
-radToDeg(event.data.pitch) +
(tankModelDefinition.initial_turret_rotation?.pitch ?? 0)
).toFixed(1);
if (yaw === undefined) return;
if (event.data.yaw === undefined) return;
yawInput.current.value = radToDeg(yaw).toFixed(1);
yawInput.current.value = radToDeg(event.data.yaw).toFixed(1);
}
modelTransformEvent.on(handleTransformEvent);
@@ -85,24 +74,27 @@ export function QuickInputs() {
defaultValue="0.0"
onBlur={() => {
const value = Number(yawInput.current!.value);
if (isNaN(value)) {
yawInput.current!.value = radToDeg(protagonist.yaw).toFixed(1);
yawInput.current!.value = radToDeg(
modelTransformEvent.last!.yaw,
).toFixed(1);
return;
}
const [pitch, yaw] = applyPitchYawLimits(
protagonist.pitch,
modelTransformEvent.last!.pitch,
degToRad(value),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
mutateDuel((state) => {
state.protagonist.pitch = pitch;
state.protagonist.yaw = yaw;
});
yawInput.current!.value = radToDeg(protagonist.yaw).toFixed(1);
yawInput.current!.value = radToDeg(
modelTransformEvent.last!.yaw,
).toFixed(1);
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
@@ -128,25 +120,21 @@ export function QuickInputs() {
const value = Number(pitchInput.current!.value);
if (isNaN(value)) {
pitchInput.current!.value = (
-radToDeg(protagonist.pitch) + initialGunPitch
-radToDeg(modelTransformEvent.last!.pitch) + initialGunPitch
).toFixed(1);
return;
}
const [pitch, yaw] = applyPitchYawLimits(
degToRad(-value + initialGunPitch),
protagonist.yaw,
modelTransformEvent.last!.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
mutateDuel((state) => {
state.protagonist.pitch = pitch;
state.protagonist.yaw = yaw;
});
pitchInput.current!.value = (
-radToDeg(protagonist.pitch) + initialGunPitch
-radToDeg(modelTransformEvent.last!.pitch) + initialGunPitch
).toFixed(1);
}}
onKeyDown={(event) => {
@@ -0,0 +1,31 @@
import { useEffect } from 'react';
import { degToRad } from 'three/src/math/MathUtils.js';
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform';
import { Duel } from '../../../../../../stores/duel';
const modelDefinitions = await awaitableModelDefinitions;
export function InitialAligner() {
const tank = Duel.use((state) => state.protagonist.tank);
const turret = Duel.use((state) => state.protagonist.turret);
const gun = Duel.use((state) => state.protagonist.gun);
const tankModel = modelDefinitions.models[tank.id];
const turretModel = tankModel.turrets[turret.id];
const gunModel = turretModel.guns[gun.gun_type!.value.base.id];
useEffect(() => {
const [pitch, yaw] = applyPitchYawLimits(
degToRad(8),
degToRad(25),
gunModel.pitch,
turretModel.yaw,
);
modelTransformEvent.dispatch({ pitch, yaw });
}, []);
return null;
}
@@ -39,9 +39,6 @@ export function SceneProps() {
const material = useRef<MeshStandardMaterial>(null);
const playground = useRef<Group>(null);
let lastPitch = Duel.use((state) => state.protagonist.pitch);
let lastYaw = Duel.use((state) => state.protagonist.yaw);
const display = TankopediaEphemeral.use((state) => state.display);
const turret = Duel.use((state) => state.protagonist.turret);
const track = Duel.use((state) => state.protagonist.track);
const tank = Duel.use((state) => state.protagonist.tank);
@@ -152,8 +149,8 @@ export function SceneProps() {
const desiredPitch = Math.asin(direction.y);
const desiredYaw = Math.atan2(-direction.x, -direction.z);
const deltaPitch = desiredPitch - lastPitch;
const deltaYaw = desiredYaw - lastYaw;
const deltaPitch = desiredPitch - modelTransformEvent.last!.pitch;
const deltaYaw = desiredYaw - modelTransformEvent.last!.yaw;
const deltaAngle = Math.sqrt(deltaPitch ** 2 + deltaYaw ** 2);
const maxPossibleRotationInTime = gunRotationSpeed * deltaT;
const clampedDeltaAngle = Math.min(maxPossibleRotationInTime, deltaAngle);
@@ -163,14 +160,14 @@ export function SceneProps() {
deltaAngle === 0 ? 0 : deltaYaw * (clampedDeltaAngle / deltaAngle);
const [pitch, yaw] = applyPitchYawLimits(
lastPitch + clampedDeltaPitch,
lastYaw + clampedDeltaYaw,
modelTransformEvent.last!.pitch + clampedDeltaPitch,
modelTransformEvent.last!.yaw + clampedDeltaYaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
);
const actualDeltaPitch = pitch - lastPitch;
const actualDeltaYaw = yaw - lastYaw;
const actualDeltaPitch = pitch - modelTransformEvent.last!.pitch;
const actualDeltaYaw = yaw - modelTransformEvent.last!.yaw;
const deltaRotation = Math.abs(actualDeltaPitch) + Math.abs(actualDeltaYaw);
const rotationSpeed = deltaRotation / deltaT;
const turretTraversePenalty =
@@ -190,8 +187,6 @@ export function SceneProps() {
}
modelTransformEvent.dispatch({ pitch, yaw });
lastPitch = pitch;
lastYaw = yaw;
const gunDirection = new Vector3(0, 0, -1)
.applyAxisAngle(I_HAT, pitch)
@@ -1,4 +1,3 @@
import { normalizeAngleRad } from '@blitzkit/core';
import { invalidate, useThree, type ThreeEvent } from '@react-three/fiber';
import { useRef } from 'react';
import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three';
@@ -125,17 +124,12 @@ export function TankModel() {
if (!isVisible) return null;
let pitch = 0;
let yaw = 0;
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
if (!isTurret) return;
position.set(event.clientX, event.clientY);
yaw = protagonist.yaw;
pitch = protagonist.pitch;
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = false;
@@ -164,9 +158,10 @@ export function TankModel() {
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
[pitch, yaw] = applyPitchYawLimits(
pitch,
yaw + delta.x * (Math.PI / boundingRect.width),
const [pitch, yaw] = applyPitchYawLimits(
modelTransformEvent.last!.pitch,
modelTransformEvent.last!.yaw +
delta.x * (Math.PI / boundingRect.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
@@ -175,10 +170,6 @@ export function TankModel() {
modelTransformEvent.dispatch({ pitch, yaw });
}
function handlePointerUp() {
mutateDuel((draft) => {
draft.protagonist.pitch = normalizeAngleRad(pitch);
draft.protagonist.yaw = normalizeAngleRad(yaw);
});
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = true;
});
@@ -231,8 +222,8 @@ export function TankModel() {
});
position.set(event.clientX, event.clientY);
pitch = protagonist.pitch;
yaw = protagonist.yaw;
pitch = modelTransformEvent.last!.pitch;
yaw = modelTransformEvent.last!.yaw;
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
@@ -267,10 +258,6 @@ export function TankModel() {
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = true;
});
mutateDuel((draft) => {
draft.protagonist.pitch = normalizeAngleRad(pitch);
draft.protagonist.yaw = normalizeAngleRad(yaw);
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
}
@@ -28,6 +28,7 @@ import {
import { SmartCanvas } from '../../../../SmartCanvas';
import { AutoClear } from './components/AutoClear';
import { Controls } from './components/Control';
import { InitialAligner } from './components/InitialAligner';
import { InitialFogReveal } from './components/InitialFogReveal';
import { Lighting } from './components/Lighting';
import { SceneProps } from './components/SceneProps';
@@ -114,56 +115,44 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
function handlePoseEvent(pose: Pose) {
switch (pose) {
case Pose.HullDown: {
mutateDuel((draft) => {
const [pitch, yaw] = applyPitchYawLimits(
-Infinity,
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
const [pitch, yaw] = applyPitchYawLimits(
-Infinity,
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
draft.protagonist.pitch = pitch;
draft.protagonist.yaw = yaw;
});
modelTransformEvent.dispatch({ pitch, yaw });
break;
}
case Pose.FaceHug: {
mutateDuel((draft) => {
const [pitch, yaw] = applyPitchYawLimits(
Infinity,
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
const [pitch, yaw] = applyPitchYawLimits(
Infinity,
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
draft.protagonist.pitch = pitch;
draft.protagonist.yaw = yaw;
});
modelTransformEvent.dispatch({ pitch, yaw });
break;
}
case Pose.Default:
mutateDuel((draft) => {
const [pitch, yaw] = applyPitchYawLimits(
0,
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
const [pitch, yaw] = applyPitchYawLimits(
0,
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
draft.protagonist.pitch = pitch;
draft.protagonist.yaw = yaw;
});
modelTransformEvent.dispatch({ pitch, yaw });
break;
}
@@ -177,15 +166,15 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
});
useEffect(() => {
mutateDuel((draft) => {
[draft.protagonist.pitch, draft.protagonist.yaw] = applyPitchYawLimits(
draft.protagonist.pitch,
draft.protagonist.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
});
const [pitch, yaw] = applyPitchYawLimits(
modelTransformEvent.last!.pitch,
modelTransformEvent.last!.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.dispatch({ pitch, yaw });
}, [protagonistGun, protagonistTurret]);
useEffect(() => {
@@ -246,6 +235,8 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
)}
<Lighting display={display} />
</Suspense>
<InitialAligner />
</SmartCanvas>
);
},
@@ -1,8 +1,11 @@
import { Quicklime } from 'quicklime';
export interface ModelTransformEventData {
yaw?: number;
yaw: number;
pitch: number;
}
export const modelTransformEvent = new Quicklime<ModelTransformEventData>();
export const modelTransformEvent = new Quicklime<ModelTransformEventData>({
pitch: 0,
yaw: 0,
});
@@ -4,10 +4,8 @@ import {
type ProvisionDefinitions,
type TankDefinition,
} from '@blitzkit/core';
import { degToRad } from 'three/src/math/MathUtils.js';
import type { DuelMember } from '../../stores/duel';
import { genericDefaultEquipmentMatrix } from '../../stores/duel/constants';
import { applyPitchYawLimits } from '../blitz/applyPitchYawLimits';
export function tankToDuelMember(
tank: TankDefinition,
@@ -15,16 +13,7 @@ export function tankToDuelMember(
provisionDefinitions: ProvisionDefinitions,
) {
const turret = tank.turrets.at(-1)!;
const turretModel = model.turrets[turret.id];
const gun = turret.guns.at(-1)!;
const gunModel = turretModel.guns[gun.gun_type!.value.base.id];
const [pitch, yaw] = applyPitchYawLimits(
degToRad(8),
degToRad(25),
gunModel.pitch,
turretModel.yaw,
);
return {
camouflage: true,
@@ -37,8 +26,6 @@ export function tankToDuelMember(
shell: tank.turrets.at(-1)!.guns.at(-1)!.gun_type!.value.base.shells[0],
tank,
track: tank.tracks.at(-1)!,
yaw,
pitch,
turret,
assaultDistance:
(gun.gun_type!.value.base.assault_ranges?.ranges[0].distance ?? 0) / 2,
+3 -16
View File
@@ -45,9 +45,8 @@ export function useTankTransform(
}
function handleModelTransformInner(data?: ModelTransformEventData) {
const duel = duelStore.getState();
const yaw = data?.yaw ?? duel.protagonist.yaw;
const pitch = data?.pitch ?? duel.protagonist.pitch;
const yaw = data?.yaw ?? modelTransformEvent.last!.yaw;
const pitch = data?.pitch ?? modelTransformEvent.last!.pitch;
gunPosition
.set(0, 0, 0)
@@ -102,20 +101,8 @@ export function useTankTransform(
modelTransformEvent.on(handleModelTransform);
const unsubscribes = [
duelStore.subscribe(
(state) => state.protagonist.pitch,
() => handleModelTransformInner(),
),
duelStore.subscribe(
(state) => state.protagonist.yaw,
() => handleModelTransformInner(),
),
() => modelTransformEvent.off(handleModelTransform),
];
return () => {
unsubscribes.forEach((unsubscribe) => unsubscribe());
modelTransformEvent.off(handleModelTransform);
};
}, [track, turret]);
}
@@ -33,8 +33,6 @@ export interface DuelMember {
shell: ShellDefinition;
track: TrackDefinition;
equipmentMatrix: EquipmentMatrix;
pitch: number;
yaw: number;
consumables: number[];
provisions: number[];
camouflage: boolean;