mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: generalize transform handling
This commit is contained in:
1 parent
fde9319bbd
commit
85166a2614
4 files changed
+96
-216
No files matched your search
@@ -1,27 +1,15 @@
|
|||||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||||
import { memo, useEffect, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import {
|
import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three';
|
||||||
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 { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
import { correctZYTuple } from '../../../../../../../core/blitz/correctZYTuple';
|
|
||||||
import { hasEquipment } from '../../../../../../../core/blitzkit/hasEquipment';
|
import { hasEquipment } from '../../../../../../../core/blitzkit/hasEquipment';
|
||||||
import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree';
|
import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree';
|
||||||
import { modelDefinitions } from '../../../../../../../core/blitzkit/modelDefinitions';
|
import { modelDefinitions } from '../../../../../../../core/blitzkit/modelDefinitions';
|
||||||
import {
|
import { modelTransformEvent } from '../../../../../../../core/blitzkit/modelTransform';
|
||||||
ModelTransformEventData,
|
|
||||||
modelTransformEvent,
|
|
||||||
} from '../../../../../../../core/blitzkit/modelTransform';
|
|
||||||
import { normalizeAngleRad } from '../../../../../../../core/math/normalizeAngleRad';
|
import { normalizeAngleRad } from '../../../../../../../core/math/normalizeAngleRad';
|
||||||
import { useAwait } from '../../../../../../../hooks/useAwait';
|
import { useAwait } from '../../../../../../../hooks/useAwait';
|
||||||
import { useModel } from '../../../../../../../hooks/useModel';
|
import { useModel } from '../../../../../../../hooks/useModel';
|
||||||
|
import { useTankTransform } from '../../../../../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../../../../../stores/duel';
|
import * as Duel from '../../../../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
||||||
|
|
||||||
@@ -36,71 +24,11 @@ export const TankModel = memo(() => {
|
|||||||
const gunContainer = useRef<Group>(null);
|
const gunContainer = useRef<Group>(null);
|
||||||
const mutateTankopediaTemporary = TankopediaEphemeral.useMutation();
|
const mutateTankopediaTemporary = TankopediaEphemeral.useMutation();
|
||||||
|
|
||||||
useEffect(() => {
|
useTankTransform(protagonist, turretContainer, gunContainer);
|
||||||
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);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!awaitedModelDefinitions) return;
|
if (!awaitedModelDefinitions) return;
|
||||||
|
|
||||||
const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id];
|
const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id];
|
||||||
const trackModelDefinition = tankModelDefinition.tracks[protagonist.track.id];
|
|
||||||
const turretModelDefinition =
|
const turretModelDefinition =
|
||||||
tankModelDefinition.turrets[protagonist.turret.id];
|
tankModelDefinition.turrets[protagonist.turret.id];
|
||||||
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
|
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { memo, useEffect, useRef } from 'react';
|
import { memo, useEffect, useRef } from 'react';
|
||||||
import { Euler, Group, Vector3 } from 'three';
|
import { Group } 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 { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
||||||
import {
|
|
||||||
ModelTransformEventData,
|
|
||||||
modelTransformEvent,
|
|
||||||
} from '../../../core/blitzkit/modelTransform';
|
|
||||||
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
||||||
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
||||||
import { useArmor } from '../../../hooks/useArmor';
|
import { useArmor } from '../../../hooks/useArmor';
|
||||||
import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
||||||
|
import { useTankTransform } from '../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../stores/duel';
|
import * as Duel from '../../../stores/duel';
|
||||||
import * as TankopediaPersistent from '../../../stores/tankopediaPersistent';
|
import * as TankopediaPersistent from '../../../stores/tankopediaPersistent';
|
||||||
import { CoreArmorSceneComponent } from './CoreArmorSceneComponent';
|
import { CoreArmorSceneComponent } from './CoreArmorSceneComponent';
|
||||||
@@ -24,68 +19,7 @@ export const CoreArmorScene = memo(() => {
|
|||||||
const initialTankopediaState = tankopediaPersistentStore.getState();
|
const initialTankopediaState = tankopediaPersistentStore.getState();
|
||||||
const protagonist = Duel.use((draft) => draft.protagonist);
|
const protagonist = Duel.use((draft) => draft.protagonist);
|
||||||
|
|
||||||
useEffect(() => {
|
useTankTransform(protagonist, turretContainer, gunContainer);
|
||||||
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);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = tankopediaPersistentStore.subscribe(
|
const unsubscribe = tankopediaPersistentStore.subscribe(
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import { memo, useEffect, useRef } from 'react';
|
import { memo, useEffect, useRef } from 'react';
|
||||||
import { Euler, Group, Plane, Scene, Vector3 } from 'three';
|
import { Group, Plane, Scene, 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 { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
||||||
import {
|
|
||||||
ModelTransformEventData,
|
|
||||||
modelTransformEvent,
|
|
||||||
} from '../../../core/blitzkit/modelTransform';
|
|
||||||
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
||||||
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
||||||
import { useArmor } from '../../../hooks/useArmor';
|
import { useArmor } from '../../../hooks/useArmor';
|
||||||
import { useModel } from '../../../hooks/useModel';
|
import { useModel } from '../../../hooks/useModel';
|
||||||
import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
||||||
|
import { useTankTransform } from '../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../stores/duel';
|
import * as Duel from '../../../stores/duel';
|
||||||
import * as TankopediaPersistent from '../../../stores/tankopediaPersistent';
|
import * as TankopediaPersistent from '../../../stores/tankopediaPersistent';
|
||||||
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent';
|
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent';
|
||||||
@@ -54,69 +49,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
? undefined
|
? undefined
|
||||||
: gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y;
|
: gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y;
|
||||||
|
|
||||||
useEffect(() => {
|
useTankTransform(protagonist, turretContainer, gunContainer);
|
||||||
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);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = tankopediaPersistentStore.subscribe(
|
const unsubscribe = tankopediaPersistentStore.subscribe(
|
||||||
|
|||||||
@@ -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<Group>,
|
||||||
|
gunContainer: RefObject<Group>,
|
||||||
|
) {
|
||||||
|
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]);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user