mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: generalize wrapper
This commit is contained in:
1 parent
85166a2614
commit
e88fdd861f
4 files changed
+87
-101
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three';
|
import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three';
|
||||||
|
import { ModelTankWrapper } from '../../../../../../../components/Armor/components/ModelTankWrapper';
|
||||||
import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
import { hasEquipment } from '../../../../../../../core/blitzkit/hasEquipment';
|
import { hasEquipment } from '../../../../../../../core/blitzkit/hasEquipment';
|
||||||
import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree';
|
import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree';
|
||||||
@@ -36,7 +37,7 @@ export const TankModel = memo(() => {
|
|||||||
const nodes = Object.values(gltf.nodes);
|
const nodes = Object.values(gltf.nodes);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group ref={hullContainer} rotation={[-Math.PI / 2, 0, 0]}>
|
<ModelTankWrapper ref={hullContainer}>
|
||||||
{nodes.map((node) => {
|
{nodes.map((node) => {
|
||||||
const isHull = node.name === 'hull';
|
const isHull = node.name === 'hull';
|
||||||
const isWheel = node.name.startsWith('chassis_wheel_');
|
const isWheel = node.name.startsWith('chassis_wheel_');
|
||||||
@@ -260,6 +261,6 @@ export const TankModel = memo(() => {
|
|||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</ModelTankWrapper>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -9,6 +9,7 @@ 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';
|
||||||
|
import { ModelTankWrapper } from './ModelTankWrapper';
|
||||||
|
|
||||||
export const CoreArmorScene = memo(() => {
|
export const CoreArmorScene = memo(() => {
|
||||||
const wrapper = useRef<Group>(null);
|
const wrapper = useRef<Group>(null);
|
||||||
@@ -47,9 +48,8 @@ export const CoreArmorScene = memo(() => {
|
|||||||
const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin);
|
const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<ModelTankWrapper
|
||||||
ref={wrapper}
|
ref={wrapper}
|
||||||
rotation={[-Math.PI / 2, 0, 0]}
|
|
||||||
visible={initialTankopediaState.mode === 'armor'}
|
visible={initialTankopediaState.mode === 'armor'}
|
||||||
>
|
>
|
||||||
<group position={hullOrigin}>
|
<group position={hullOrigin}>
|
||||||
@@ -75,58 +75,55 @@ export const CoreArmorScene = memo(() => {
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group ref={turretContainer}>
|
<group ref={turretContainer}>
|
||||||
<group position={hullOrigin}>
|
{armorNodes.map((node) => {
|
||||||
|
const isCurrentTurret = node.name.startsWith(
|
||||||
|
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
|
||||||
|
);
|
||||||
|
const isVisible = isCurrentTurret;
|
||||||
|
const armorId = nameToArmorId(node.name);
|
||||||
|
const { spaced, thickness } = resolveArmor(
|
||||||
|
turretModelDefinition.armor,
|
||||||
|
armorId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isVisible || spaced || thickness === undefined) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group key={node.uuid} position={turretOrigin}>
|
||||||
|
<CoreArmorSceneComponent
|
||||||
|
key={node.uuid}
|
||||||
|
thickness={thickness}
|
||||||
|
node={node}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<group ref={gunContainer}>
|
||||||
{armorNodes.map((node) => {
|
{armorNodes.map((node) => {
|
||||||
const isCurrentTurret = node.name.startsWith(
|
const isCurrentGun = node.name.startsWith(
|
||||||
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
|
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
|
||||||
);
|
);
|
||||||
const isVisible = isCurrentTurret;
|
const isVisible = isCurrentGun;
|
||||||
const armorId = nameToArmorId(node.name);
|
const armorId = nameToArmorId(node.name);
|
||||||
const { spaced, thickness } = resolveArmor(
|
const { spaced, thickness } = resolveArmor(
|
||||||
turretModelDefinition.armor,
|
gunModelDefinition.armor,
|
||||||
armorId,
|
armorId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isVisible || spaced || thickness === undefined) return null;
|
if (!isVisible || spaced || thickness === undefined) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group key={node.uuid} position={turretOrigin}>
|
<group
|
||||||
<CoreArmorSceneComponent
|
key={node.uuid}
|
||||||
key={node.uuid}
|
position={turretOrigin.clone().add(gunOrigin)}
|
||||||
thickness={thickness}
|
>
|
||||||
node={node}
|
<CoreArmorSceneComponent thickness={thickness} node={node} />
|
||||||
/>
|
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
<group ref={gunContainer}>
|
|
||||||
<group position={hullOrigin}>
|
|
||||||
{armorNodes.map((node) => {
|
|
||||||
const isCurrentGun = node.name.startsWith(
|
|
||||||
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
|
|
||||||
);
|
|
||||||
const isVisible = isCurrentGun;
|
|
||||||
const armorId = nameToArmorId(node.name);
|
|
||||||
const { spaced, thickness } = resolveArmor(
|
|
||||||
gunModelDefinition.armor,
|
|
||||||
armorId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isVisible || spaced || thickness === undefined) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={node.uuid}
|
|
||||||
position={turretOrigin.clone().add(gunOrigin)}
|
|
||||||
>
|
|
||||||
<CoreArmorSceneComponent thickness={thickness} node={node} />
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</ModelTankWrapper>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { GroupProps } from '@react-three/fiber';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
import { Group } from 'three';
|
||||||
|
|
||||||
|
export const ModelTankWrapper = forwardRef<Group, GroupProps>((props, ref) => {
|
||||||
|
return <group rotation={[-Math.PI / 2, 0, 0]} ref={ref} {...props} />;
|
||||||
|
});
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { memo, useEffect, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { Group, Plane, Scene, Vector3 } from 'three';
|
import { Group, Plane, Scene, Vector3 } from 'three';
|
||||||
import { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
import { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
||||||
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
||||||
@@ -8,7 +8,7 @@ import { useModel } from '../../../hooks/useModel';
|
|||||||
import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
||||||
import { useTankTransform } from '../../../hooks/useTankTransform';
|
import { useTankTransform } from '../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../stores/duel';
|
import * as Duel from '../../../stores/duel';
|
||||||
import * as TankopediaPersistent from '../../../stores/tankopediaPersistent';
|
import { ModelTankWrapper } from './ModelTankWrapper';
|
||||||
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent';
|
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent';
|
||||||
|
|
||||||
export enum ArmorType {
|
export enum ArmorType {
|
||||||
@@ -26,8 +26,6 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
const modelDefinitions = useModelDefinitions();
|
const modelDefinitions = useModelDefinitions();
|
||||||
const turretContainer = useRef<Group>(null);
|
const turretContainer = useRef<Group>(null);
|
||||||
const gunContainer = useRef<Group>(null);
|
const gunContainer = useRef<Group>(null);
|
||||||
const tankopediaPersistentStore = TankopediaPersistent.useStore();
|
|
||||||
const initialTankopediaState = tankopediaPersistentStore.getState();
|
|
||||||
const protagonist = Duel.use((draft) => draft.protagonist);
|
const protagonist = Duel.use((draft) => draft.protagonist);
|
||||||
const tank = Duel.use((state) => state.protagonist.tank);
|
const tank = Duel.use((state) => state.protagonist.tank);
|
||||||
const track = Duel.use((state) => state.protagonist.track);
|
const track = Duel.use((state) => state.protagonist.track);
|
||||||
@@ -51,23 +49,8 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
|
|
||||||
useTankTransform(protagonist, turretContainer, gunContainer);
|
useTankTransform(protagonist, turretContainer, gunContainer);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const unsubscribe = tankopediaPersistentStore.subscribe(
|
|
||||||
(state) => state.mode,
|
|
||||||
(mode) => {
|
|
||||||
if (wrapper.current) wrapper.current.visible = mode === 'armor';
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return unsubscribe;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<ModelTankWrapper ref={wrapper}>
|
||||||
ref={wrapper}
|
|
||||||
rotation={[-Math.PI / 2, 0, 0]}
|
|
||||||
visible={initialTankopediaState.mode === 'armor'}
|
|
||||||
>
|
|
||||||
<group position={hullOrigin}>
|
<group position={hullOrigin}>
|
||||||
{armorNodes.map((node) => {
|
{armorNodes.map((node) => {
|
||||||
const isHull = node.name.startsWith('hull_');
|
const isHull = node.name.startsWith('hull_');
|
||||||
@@ -91,6 +74,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
{modelNodes.map((node) => {
|
{modelNodes.map((node) => {
|
||||||
const isWheel = node.name.startsWith('chassis_wheel_');
|
const isWheel = node.name.startsWith('chassis_wheel_');
|
||||||
const isTrack = node.name.startsWith('chassis_track_');
|
const isTrack = node.name.startsWith('chassis_track_');
|
||||||
@@ -111,25 +95,53 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
})}
|
})}
|
||||||
|
|
||||||
<group ref={turretContainer}>
|
<group ref={turretContainer}>
|
||||||
<group position={hullOrigin}>
|
{armorNodes.map((node) => {
|
||||||
|
const isCurrentTurret = node.name.startsWith(
|
||||||
|
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
|
||||||
|
);
|
||||||
|
const isVisible = isCurrentTurret;
|
||||||
|
const armorId = nameToArmorId(node.name);
|
||||||
|
const { spaced, thickness } = resolveArmor(
|
||||||
|
turretModelDefinition.armor,
|
||||||
|
armorId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isVisible || thickness === undefined) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group key={node.uuid} position={turretOrigin}>
|
||||||
|
<SpacedArmorSceneComponent
|
||||||
|
scene={scene}
|
||||||
|
key={node.uuid}
|
||||||
|
type={spaced ? ArmorType.Spaced : ArmorType.Core}
|
||||||
|
thickness={thickness}
|
||||||
|
node={node}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<group ref={gunContainer}>
|
||||||
{armorNodes.map((node) => {
|
{armorNodes.map((node) => {
|
||||||
const isCurrentTurret = node.name.startsWith(
|
const isCurrentGun = node.name.startsWith(
|
||||||
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
|
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
|
||||||
);
|
);
|
||||||
const isVisible = isCurrentTurret;
|
const isVisible = isCurrentGun;
|
||||||
const armorId = nameToArmorId(node.name);
|
const armorId = nameToArmorId(node.name);
|
||||||
const { spaced, thickness } = resolveArmor(
|
const { spaced, thickness } = resolveArmor(
|
||||||
turretModelDefinition.armor,
|
gunModelDefinition.armor,
|
||||||
armorId,
|
armorId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isVisible || thickness === undefined) return null;
|
if (!isVisible || thickness === undefined) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group key={node.uuid} position={turretOrigin}>
|
<group
|
||||||
|
key={node.uuid}
|
||||||
|
position={turretOrigin.clone().add(gunOrigin)}
|
||||||
|
>
|
||||||
<SpacedArmorSceneComponent
|
<SpacedArmorSceneComponent
|
||||||
scene={scene}
|
scene={scene}
|
||||||
key={node.uuid}
|
|
||||||
type={spaced ? ArmorType.Spaced : ArmorType.Core}
|
type={spaced ? ArmorType.Spaced : ArmorType.Core}
|
||||||
thickness={thickness}
|
thickness={thickness}
|
||||||
node={node}
|
node={node}
|
||||||
@@ -137,37 +149,6 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</group>
|
|
||||||
<group ref={gunContainer}>
|
|
||||||
<group position={hullOrigin}>
|
|
||||||
{armorNodes.map((node) => {
|
|
||||||
const isCurrentGun = node.name.startsWith(
|
|
||||||
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
|
|
||||||
);
|
|
||||||
const isVisible = isCurrentGun;
|
|
||||||
const armorId = nameToArmorId(node.name);
|
|
||||||
const { spaced, thickness } = resolveArmor(
|
|
||||||
gunModelDefinition.armor,
|
|
||||||
armorId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isVisible || thickness === undefined) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={node.uuid}
|
|
||||||
position={turretOrigin.clone().add(gunOrigin)}
|
|
||||||
>
|
|
||||||
<SpacedArmorSceneComponent
|
|
||||||
scene={scene}
|
|
||||||
type={spaced ? ArmorType.Spaced : ArmorType.Core}
|
|
||||||
thickness={thickness}
|
|
||||||
node={node}
|
|
||||||
/>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</group>
|
|
||||||
|
|
||||||
{modelNodes.map((node) => {
|
{modelNodes.map((node) => {
|
||||||
const gunString = `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
|
const gunString = `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
|
||||||
@@ -196,6 +177,6 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</ModelTankWrapper>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user