From b5598786673a5d05b6f108ec5386d02492220a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:38:37 -0500 Subject: [PATCH] feat: rotation inputs in static mode --- .../components/Model/components/TankModel.tsx | 42 +++--- .../components/StaticArmorSceneComponent.tsx | 18 ++- src/components/StaticArmor/index.tsx | 132 +++++++++++++++++- src/core/blitzkit/tankTransformHandlers.ts | 67 +++++++++ 4 files changed, 228 insertions(+), 31 deletions(-) create mode 100644 src/core/blitzkit/tankTransformHandlers.ts 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 5d8337d0b..8ccc3087c 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx @@ -24,7 +24,7 @@ export const TankModel = memo(() => { const hullContainer = useRef(null); const turretContainer = useRef(null); const gunContainer = useRef(null); - const mutateTankopediaTemporary = TankopediaEphemeral.useMutation(); + const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); const tankModelDefinition = useTankModelDefinition(); const turretModelDefinition = tankModelDefinition.turrets[protagonist.turret.id]; @@ -68,7 +68,7 @@ export const TankModel = memo(() => { position.set(event.clientX, event.clientY); event.stopPropagation(); - mutateTankopediaTemporary((draft) => { + mutateTankopediaEphemeral((draft) => { draft.controlsEnabled = false; }); @@ -87,7 +87,7 @@ export const TankModel = memo(() => { translateTexture(deltaX + deltaY); } function handlePointerUp() { - mutateTankopediaTemporary((draft) => { + mutateTankopediaEphemeral((draft) => { draft.controlsEnabled = true; }); @@ -124,21 +124,21 @@ export const TankModel = memo(() => { function onPointerDown(event: ThreeEvent) { event.stopPropagation(); - if (isTurret) { - position.set(event.clientX, event.clientY); - yaw = protagonist.yaw; - pitch = protagonist.pitch; + if (!isTurret) return; - mutateTankopediaTemporary((draft) => { - draft.controlsEnabled = false; - }); - mutateTankopediaTemporary((draft) => { - draft.shot = undefined; - draft.highlightArmor = undefined; - }); - window.addEventListener('pointermove', handlePointerMove); - window.addEventListener('pointerup', handlePointerUp); - } + position.set(event.clientX, event.clientY); + yaw = protagonist.yaw; + pitch = protagonist.pitch; + + mutateTankopediaEphemeral((draft) => { + draft.controlsEnabled = false; + }); + mutateTankopediaEphemeral((draft) => { + draft.shot = undefined; + draft.highlightArmor = undefined; + }); + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); } async function handlePointerMove(event: PointerEvent) { const duel = duelStore.getState(); @@ -166,7 +166,7 @@ export const TankModel = memo(() => { draft.protagonist.pitch = normalizeAngleRad(pitch); draft.protagonist.yaw = normalizeAngleRad(yaw); }); - mutateTankopediaTemporary((draft) => { + mutateTankopediaEphemeral((draft) => { draft.controlsEnabled = true; }); window.removeEventListener('pointermove', handlePointerMove); @@ -206,10 +206,10 @@ export const TankModel = memo(() => { function onPointerDown(event: ThreeEvent) { event.stopPropagation(); - mutateTankopediaTemporary((draft) => { + mutateTankopediaEphemeral((draft) => { draft.controlsEnabled = false; }); - mutateTankopediaTemporary((draft) => { + mutateTankopediaEphemeral((draft) => { draft.shot = undefined; draft.highlightArmor = undefined; }); @@ -242,7 +242,7 @@ export const TankModel = memo(() => { modelTransformEvent.emit({ pitch, yaw }); } function handlePointerUp() { - mutateTankopediaTemporary((draft) => { + mutateTankopediaEphemeral((draft) => { draft.controlsEnabled = true; }); mutateDuel((draft) => { diff --git a/src/components/Armor/components/StaticArmorSceneComponent.tsx b/src/components/Armor/components/StaticArmorSceneComponent.tsx index be6881827..0dcec35e5 100644 --- a/src/components/Armor/components/StaticArmorSceneComponent.tsx +++ b/src/components/Armor/components/StaticArmorSceneComponent.tsx @@ -99,7 +99,6 @@ export function StaticArmorSceneComponent({ }), [thickness], ); - const outlineMaterial = useMemo( () => new LineBasicMaterial({ @@ -110,10 +109,19 @@ export function StaticArmorSceneComponent({ [thickness], ); - /** - * hook inside an if statement?? don't panic! I assure you the static prop - * never mutates :) - */ + // if (clip) { + // /** + // * hook inside an if statement?? don't panic! I assure you the clip prop + // * never mutates :) + // */ + // useFrame(() => { + // surfaceMaterial.clippingPlanes!.forEach((plane) => { + // // console.log(plane.normal); + // plane.applyMatrix4(node.matrix); + // }); + // }); + // } + useEffect(() => { function handleHighlightArmor(selectedName?: string) { if (selectedName === undefined) { diff --git a/src/components/StaticArmor/index.tsx b/src/components/StaticArmor/index.tsx index 5b312f65d..5261e3671 100644 --- a/src/components/StaticArmor/index.tsx +++ b/src/components/StaticArmor/index.tsx @@ -1,13 +1,19 @@ +import { ThreeEvent, useThree } from '@react-three/fiber'; import { memo, useRef } from 'react'; -import { Group, Plane, Vector3 } from 'three'; +import { Group, Plane, Vector2, Vector3 } from 'three'; +import { applyPitchYawLimits } from '../../core/blitz/applyPitchYawLimits'; import { correctZYTuple } from '../../core/blitz/correctZYTuple'; +import { hasEquipment } from '../../core/blitzkit/hasEquipment'; +import { modelTransformEvent } from '../../core/blitzkit/modelTransform'; import { nameToArmorId } from '../../core/blitzkit/nameToArmorId'; import { resolveArmor } from '../../core/blitzkit/resolveThickness'; +import { normalizeAngleRad } from '../../core/math/normalizeAngleRad'; import { useArmor } from '../../hooks/useArmor'; import { useModel } from '../../hooks/useModel'; import { useTankModelDefinition } from '../../hooks/useTankModelDefinition'; import { useTankTransform } from '../../hooks/useTankTransform'; import * as Duel from '../../stores/duel'; +import * as TankopediaEphemeral from '../../stores/tankopediaEphemeral'; import * as TankopediaPersistent from '../../stores/tankopediaPersistent'; import { ModelTankWrapper } from '../Armor/components/ModelTankWrapper'; import { ArmorType } from '../Armor/components/SpacedArmorScene'; @@ -41,6 +47,10 @@ export const StaticArmor = memo(({ thicknessRange }) => { const hullOrigin = correctZYTuple(trackModelDefinition.origin); const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); + const mutateDuel = Duel.useMutation(); + const canvas = useThree((state) => state.gl.domElement); + const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); + const duelStore = Duel.useStore(); const maskOrigin = gunModelDefinition.mask === undefined ? undefined @@ -127,11 +137,67 @@ export const StaticArmor = memo(({ thicknessRange }) => { thickness === undefined || (!showPrimaryArmor && !spaced) || (!showSpacedArmor && spaced) - ) + ) { return null; + } + + const position = new Vector2(); + const delta = new Vector2(); + let pitch = 0; + let yaw = 0; + + function onPointerDown(event: ThreeEvent) { + event.stopPropagation(); + + position.set(event.clientX, event.clientY); + yaw = protagonist.yaw; + pitch = protagonist.pitch; + + mutateTankopediaEphemeral((draft) => { + draft.controlsEnabled = false; + }); + mutateTankopediaEphemeral((draft) => { + draft.shot = undefined; + draft.highlightArmor = undefined; + }); + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); + } + async function handlePointerMove(event: PointerEvent) { + const duel = duelStore.getState(); + const hasImprovedVerticalStabilizer = await hasEquipment( + 122, + duel.protagonist.tank.equipment, + duel.protagonist.equipmentMatrix, + ); + const boundingRect = canvas.getBoundingClientRect(); + + 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), + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); + modelTransformEvent.emit({ pitch, yaw }); + } + function handlePointerUp() { + mutateDuel((draft) => { + draft.protagonist.pitch = normalizeAngleRad(pitch); + draft.protagonist.yaw = normalizeAngleRad(yaw); + }); + mutateTankopediaEphemeral((draft) => { + draft.controlsEnabled = true; + }); + window.removeEventListener('pointermove', handlePointerMove); + window.removeEventListener('pointerup', handlePointerUp); + } return ( - + (({ thicknessRange }) => { thickness === undefined || (!showPrimaryArmor && !spaced) || (!showSpacedArmor && spaced) - ) + ) { return null; + } + + const position = new Vector2(); + const delta = new Vector2(); + let pitch = 0; + let yaw = 0; + + function onPointerDown(event: ThreeEvent) { + event.stopPropagation(); + + mutateTankopediaEphemeral((draft) => { + draft.controlsEnabled = false; + }); + mutateTankopediaEphemeral((draft) => { + draft.shot = undefined; + draft.highlightArmor = undefined; + }); + + position.set(event.clientX, event.clientY); + pitch = protagonist.pitch; + yaw = protagonist.yaw; + + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); + } + async function handlePointerMove(event: PointerEvent) { + const duel = duelStore.getState(); + const hasImprovedVerticalStabilizer = await hasEquipment( + 122, + duel.protagonist.tank.equipment, + duel.protagonist.equipmentMatrix, + ); + const boundingRect = canvas.getBoundingClientRect(); + 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), + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); + modelTransformEvent.emit({ pitch, yaw }); + } + function handlePointerUp() { + 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); + } return ( - + ) { + event.stopPropagation(); + + if (isTurret) { + position.set(event.clientX, event.clientY); + yaw = protagonist.yaw; + pitch = protagonist.pitch; + + mutateTankopediaTemporary((draft) => { + draft.controlsEnabled = false; + }); + mutateTankopediaTemporary((draft) => { + draft.shot = undefined; + draft.highlightArmor = undefined; + }); + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); + } + } + async function handlePointerMove(event: PointerEvent) { + const duel = duelStore.getState(); + const hasImprovedVerticalStabilizer = await hasEquipment( + 122, + duel.protagonist.tank.equipment, + duel.protagonist.equipmentMatrix, + ); + const boundingRect = canvas.getBoundingClientRect(); + + 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), + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); + modelTransformEvent.emit({ pitch, yaw }); + } + function handlePointerUp() { + mutateDuel((draft) => { + draft.protagonist.pitch = normalizeAngleRad(pitch); + draft.protagonist.yaw = normalizeAngleRad(yaw); + }); + mutateTankopediaTemporary((draft) => { + draft.controlsEnabled = true; + }); + window.removeEventListener('pointermove', handlePointerMove); + window.removeEventListener('pointerup', handlePointerUp); + } + + return { onPointerDown }; +}