diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx index aa6e4a29a..394f9b1f3 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx @@ -1,27 +1,15 @@ import { ThreeEvent, useThree } from '@react-three/fiber'; -import { memo, useEffect, useRef } from 'react'; -import { - Euler, - Group, - Mesh, - MeshStandardMaterial, - Vector2, - Vector3, -} from 'three'; -import { degToRad } from 'three/src/math/MathUtils'; -import { I_HAT, J_HAT, K_HAT } from '../../../../../../../constants/axis'; +import { memo, useRef } from 'react'; +import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three'; import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits'; -import { correctZYTuple } from '../../../../../../../core/blitz/correctZYTuple'; import { hasEquipment } from '../../../../../../../core/blitzkit/hasEquipment'; import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree'; import { modelDefinitions } from '../../../../../../../core/blitzkit/modelDefinitions'; -import { - ModelTransformEventData, - modelTransformEvent, -} from '../../../../../../../core/blitzkit/modelTransform'; +import { modelTransformEvent } from '../../../../../../../core/blitzkit/modelTransform'; import { normalizeAngleRad } from '../../../../../../../core/math/normalizeAngleRad'; import { useAwait } from '../../../../../../../hooks/useAwait'; import { useModel } from '../../../../../../../hooks/useModel'; +import { useTankTransform } from '../../../../../../../hooks/useTankTransform'; import * as Duel from '../../../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral'; @@ -36,71 +24,11 @@ export const TankModel = memo(() => { const gunContainer = useRef(null); const mutateTankopediaTemporary = TankopediaEphemeral.useMutation(); - useEffect(() => { - const hullOrigin = correctZYTuple(trackModelDefinition.origin); - const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); - const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); - const turretPosition = new Vector3(); - const turretRotation = new Euler(); - const gunPosition = new Vector3(); - const gunRotation = new Euler(); - - function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { - gunPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .sub(gunOrigin) - .applyAxisAngle(I_HAT, pitch) - .add(gunOrigin) - .add(turretOrigin) - .add(hullOrigin); - gunRotation.set(pitch, 0, 0); - gunContainer.current?.position.copy(gunPosition); - gunContainer.current?.rotation.copy(gunRotation); - - if (yaw === undefined) return; - - turretPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .applyAxisAngle(new Vector3(0, 0, 1), yaw); - turretRotation.set(0, 0, yaw); - - if (tankModelDefinition.turretRotation) { - const initialPitch = -degToRad( - tankModelDefinition.turretRotation.pitch, - ); - const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); - const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll); - - turretPosition - .applyAxisAngle(I_HAT, initialPitch) - .applyAxisAngle(J_HAT, initialRoll) - .applyAxisAngle(K_HAT, initialYaw); - turretRotation.x += initialPitch; - turretRotation.y += initialRoll; - turretRotation.z += initialYaw; - } - - turretPosition.add(turretOrigin).add(hullOrigin); - turretContainer.current?.position.copy(turretPosition); - turretContainer.current?.rotation.copy(turretRotation); - } - - handleModelTransform(protagonist); - modelTransformEvent.on(handleModelTransform); - - return () => { - modelTransformEvent.off(handleModelTransform); - }; - }); + useTankTransform(protagonist, turretContainer, gunContainer); if (!awaitedModelDefinitions) return; const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id]; - const trackModelDefinition = tankModelDefinition.tracks[protagonist.track.id]; const turretModelDefinition = tankModelDefinition.turrets[protagonist.turret.id]; const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; diff --git a/src/components/Armor/components/CoreArmorScene.tsx b/src/components/Armor/components/CoreArmorScene.tsx index 861b4d71f..630b2a4d7 100644 --- a/src/components/Armor/components/CoreArmorScene.tsx +++ b/src/components/Armor/components/CoreArmorScene.tsx @@ -1,16 +1,11 @@ import { memo, useEffect, useRef } from 'react'; -import { Euler, Group, Vector3 } from 'three'; -import { degToRad } from 'three/src/math/MathUtils'; -import { I_HAT, J_HAT, K_HAT } from '../../../constants/axis'; +import { Group } from 'three'; import { correctZYTuple } from '../../../core/blitz/correctZYTuple'; -import { - ModelTransformEventData, - modelTransformEvent, -} from '../../../core/blitzkit/modelTransform'; import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; import { useArmor } from '../../../hooks/useArmor'; import { useModelDefinitions } from '../../../hooks/useModelDefinitions'; +import { useTankTransform } from '../../../hooks/useTankTransform'; import * as Duel from '../../../stores/duel'; import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import { CoreArmorSceneComponent } from './CoreArmorSceneComponent'; @@ -24,68 +19,7 @@ export const CoreArmorScene = memo(() => { const initialTankopediaState = tankopediaPersistentStore.getState(); const protagonist = Duel.use((draft) => draft.protagonist); - useEffect(() => { - if (!modelDefinitions) return; - - const hullOrigin = correctZYTuple(trackModelDefinition.origin); - const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); - const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); - const turretPosition = new Vector3(); - const turretRotation = new Euler(); - const gunPosition = new Vector3(); - const gunRotation = new Euler(); - - function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { - gunPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .sub(gunOrigin) - .applyAxisAngle(I_HAT, pitch) - .add(gunOrigin) - .add(turretOrigin) - .add(hullOrigin); - gunRotation.set(pitch, 0, 0); - gunContainer.current?.position.copy(gunPosition); - gunContainer.current?.rotation.copy(gunRotation); - - if (yaw === undefined) return; - - turretPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .applyAxisAngle(new Vector3(0, 0, 1), yaw); - turretRotation.set(0, 0, yaw); - - if (tankModelDefinition.turretRotation) { - const initialPitch = -degToRad( - tankModelDefinition.turretRotation.pitch, - ); - const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); - const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll); - - turretPosition - .applyAxisAngle(I_HAT, initialPitch) - .applyAxisAngle(J_HAT, initialRoll) - .applyAxisAngle(K_HAT, initialYaw); - turretRotation.x += initialPitch; - turretRotation.y += initialRoll; - turretRotation.z += initialYaw; - } - - turretPosition.add(turretOrigin).add(hullOrigin); - turretContainer.current?.position.copy(turretPosition); - turretContainer.current?.rotation.copy(turretRotation); - } - - handleModelTransform(protagonist); - modelTransformEvent.on(handleModelTransform); - - return () => { - modelTransformEvent.off(handleModelTransform); - }; - }); + useTankTransform(protagonist, turretContainer, gunContainer); useEffect(() => { const unsubscribe = tankopediaPersistentStore.subscribe( diff --git a/src/components/Armor/components/SpacedArmorScene.tsx b/src/components/Armor/components/SpacedArmorScene.tsx index c79dabffd..ebe650121 100644 --- a/src/components/Armor/components/SpacedArmorScene.tsx +++ b/src/components/Armor/components/SpacedArmorScene.tsx @@ -1,17 +1,12 @@ import { memo, useEffect, useRef } from 'react'; -import { Euler, Group, Plane, Scene, Vector3 } from 'three'; -import { degToRad } from 'three/src/math/MathUtils'; -import { I_HAT, J_HAT, K_HAT } from '../../../constants/axis'; +import { Group, Plane, Scene, Vector3 } from 'three'; import { correctZYTuple } from '../../../core/blitz/correctZYTuple'; -import { - ModelTransformEventData, - modelTransformEvent, -} from '../../../core/blitzkit/modelTransform'; import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; import { useArmor } from '../../../hooks/useArmor'; import { useModel } from '../../../hooks/useModel'; import { useModelDefinitions } from '../../../hooks/useModelDefinitions'; +import { useTankTransform } from '../../../hooks/useTankTransform'; import * as Duel from '../../../stores/duel'; import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent'; @@ -54,69 +49,7 @@ export const SpacedArmorScene = memo(({ scene }) => { ? undefined : gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y; - useEffect(() => { - if (!modelDefinitions) return; - - // BIG TODO: work out this repeat - const hullOrigin = correctZYTuple(trackModelDefinition.origin); - const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); - const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); - const turretPosition = new Vector3(); - const turretRotation = new Euler(); - const gunPosition = new Vector3(); - const gunRotation = new Euler(); - - function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { - gunPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .sub(gunOrigin) - .applyAxisAngle(I_HAT, pitch) - .add(gunOrigin) - .add(turretOrigin) - .add(hullOrigin); - gunRotation.set(pitch, 0, 0); - gunContainer.current?.position.copy(gunPosition); - gunContainer.current?.rotation.copy(gunRotation); - - if (yaw === undefined) return; - - turretPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .applyAxisAngle(new Vector3(0, 0, 1), yaw); - turretRotation.set(0, 0, yaw); - - if (tankModelDefinition.turretRotation) { - const initialPitch = -degToRad( - tankModelDefinition.turretRotation.pitch, - ); - const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); - const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll); - - turretPosition - .applyAxisAngle(I_HAT, initialPitch) - .applyAxisAngle(J_HAT, initialRoll) - .applyAxisAngle(K_HAT, initialYaw); - turretRotation.x += initialPitch; - turretRotation.y += initialRoll; - turretRotation.z += initialYaw; - } - - turretPosition.add(turretOrigin).add(hullOrigin); - turretContainer.current?.position.copy(turretPosition); - turretContainer.current?.rotation.copy(turretRotation); - } - - handleModelTransform(protagonist); - modelTransformEvent.on(handleModelTransform); - - return () => { - modelTransformEvent.off(handleModelTransform); - }; - }); + useTankTransform(protagonist, turretContainer, gunContainer); useEffect(() => { const unsubscribe = tankopediaPersistentStore.subscribe( diff --git a/src/hooks/useTankTransform.ts b/src/hooks/useTankTransform.ts new file mode 100644 index 000000000..fe905ba61 --- /dev/null +++ b/src/hooks/useTankTransform.ts @@ -0,0 +1,85 @@ +import { RefObject, useEffect } from 'react'; +import { Euler, Group, Vector3 } from 'three'; +import { degToRad } from 'three/src/math/MathUtils'; +import { I_HAT, J_HAT, K_HAT } from '../constants/axis'; +import { correctZYTuple } from '../core/blitz/correctZYTuple'; +import { modelDefinitions } from '../core/blitzkit/modelDefinitions'; +import { + ModelTransformEventData, + modelTransformEvent, +} from '../core/blitzkit/modelTransform'; +import { DuelMember } from '../stores/duel'; +import { useAwait } from './useAwait'; + +export function useTankTransform( + member: DuelMember, + turretContainer: RefObject, + gunContainer: RefObject, +) { + const awaitedModelDefinitions = useAwait(modelDefinitions); + + useEffect(() => { + const tankModelDefinition = awaitedModelDefinitions[member.tank.id]; + const trackModelDefinition = tankModelDefinition.tracks[member.track.id]; + const turretModelDefinition = tankModelDefinition.turrets[member.turret.id]; + + const hullOrigin = correctZYTuple(trackModelDefinition.origin); + const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); + const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); + const turretPosition = new Vector3(); + const turretRotation = new Euler(); + const gunPosition = new Vector3(); + const gunRotation = new Euler(); + + function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { + gunPosition + .set(0, 0, 0) + .sub(hullOrigin) + .sub(turretOrigin) + .sub(gunOrigin) + .applyAxisAngle(I_HAT, pitch) + .add(gunOrigin) + .add(turretOrigin) + .add(hullOrigin); + gunRotation.set(pitch, 0, 0); + gunContainer.current?.position.copy(gunPosition); + gunContainer.current?.rotation.copy(gunRotation); + + if (yaw === undefined) return; + + turretPosition + .set(0, 0, 0) + .sub(hullOrigin) + .sub(turretOrigin) + .applyAxisAngle(new Vector3(0, 0, 1), yaw); + turretRotation.set(0, 0, yaw); + + if (tankModelDefinition.turretRotation) { + const initialPitch = -degToRad( + tankModelDefinition.turretRotation.pitch, + ); + const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); + const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll); + + turretPosition + .applyAxisAngle(I_HAT, initialPitch) + .applyAxisAngle(J_HAT, initialRoll) + .applyAxisAngle(K_HAT, initialYaw); + turretRotation.x += initialPitch; + turretRotation.y += initialRoll; + turretRotation.z += initialYaw; + } + + turretPosition.add(turretOrigin).add(hullOrigin); + turretContainer.current?.position.copy(turretPosition); + turretContainer.current?.rotation.copy(turretRotation); + } + + handleModelTransform(member); + modelTransformEvent.on(handleModelTransform); + + return () => { + modelTransformEvent.off(handleModelTransform); + }; + }, [member]); +}