mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
fix: render tracer over armor
This commit is contained in:
1 parent
2b34863b53
commit
00cee28e08
3 files changed
+100
-63
No files matched your search
@@ -2,7 +2,6 @@ import { PerspectiveCamera } from '@react-three/drei';
|
|||||||
import { Canvas } from '@react-three/fiber';
|
import { Canvas } from '@react-three/fiber';
|
||||||
import { Suspense, use, useEffect, useRef } from 'react';
|
import { Suspense, use, useEffect, useRef } from 'react';
|
||||||
import { Armor } from '../../../../../../components/Armor';
|
import { Armor } from '../../../../../../components/Armor';
|
||||||
import { ShotDisplay } from '../../../../../../components/Armor/components/ShotDisplay';
|
|
||||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitions';
|
import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitions';
|
||||||
import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform';
|
import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform';
|
||||||
@@ -143,7 +142,6 @@ export function TankSandbox() {
|
|||||||
<Lighting />
|
<Lighting />
|
||||||
<TankModel />
|
<TankModel />
|
||||||
<Armor />
|
<Armor />
|
||||||
<ShotDisplay />
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useModelDefinitions } from '../../../hooks/useModelDefinitions';
|
|||||||
import { useDuel } from '../../../stores/duel';
|
import { useDuel } from '../../../stores/duel';
|
||||||
import { useTankopediaPersistent } from '../../../stores/tankopedia';
|
import { useTankopediaPersistent } from '../../../stores/tankopedia';
|
||||||
import { CoreArmorSceneComponent } from './CoreArmorSceneComponent';
|
import { CoreArmorSceneComponent } from './CoreArmorSceneComponent';
|
||||||
|
import { ShotDisplay } from './ShotDisplay';
|
||||||
|
|
||||||
export const CoreArmorScene = memo(() => {
|
export const CoreArmorScene = memo(() => {
|
||||||
const wrapper = useRef<Group>(null);
|
const wrapper = useRef<Group>(null);
|
||||||
@@ -135,86 +136,94 @@ export const CoreArmorScene = memo(() => {
|
|||||||
).applyAxisAngle(I_HAT, Math.PI / 2);
|
).applyAxisAngle(I_HAT, Math.PI / 2);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<>
|
||||||
ref={wrapper}
|
<ShotDisplay />
|
||||||
rotation={[-Math.PI / 2, 0, 0]}
|
|
||||||
visible={initialTankopediaState.mode === 'armor'}
|
|
||||||
>
|
|
||||||
<group position={hullOrigin}>
|
|
||||||
{armorNodes.map((node) => {
|
|
||||||
const isHull = node.name.startsWith('hull_');
|
|
||||||
const isVisible = isHull;
|
|
||||||
const armorId = nameToArmorId(node.name);
|
|
||||||
const { spaced, thickness } = resolveArmor(
|
|
||||||
tankModelDefinition.armor,
|
|
||||||
armorId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isVisible || spaced || thickness === undefined) return null;
|
<group
|
||||||
|
ref={wrapper}
|
||||||
return (
|
rotation={[-Math.PI / 2, 0, 0]}
|
||||||
<CoreArmorSceneComponent
|
visible={initialTankopediaState.mode === 'armor'}
|
||||||
key={node.uuid}
|
>
|
||||||
thickness={thickness}
|
|
||||||
node={node}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</group>
|
|
||||||
|
|
||||||
<group ref={turretContainer}>
|
|
||||||
<group position={hullOrigin}>
|
<group position={hullOrigin}>
|
||||||
{armorNodes.map((node) => {
|
{armorNodes.map((node) => {
|
||||||
const isCurrentTurret = node.name.startsWith(
|
const isHull = node.name.startsWith('hull_');
|
||||||
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
|
const isVisible = isHull;
|
||||||
);
|
|
||||||
const isVisible = isCurrentTurret;
|
|
||||||
const armorId = nameToArmorId(node.name);
|
const armorId = nameToArmorId(node.name);
|
||||||
const { spaced, thickness } = resolveArmor(
|
const { spaced, thickness } = resolveArmor(
|
||||||
turretModelDefinition.armor,
|
tankModelDefinition.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}>
|
<CoreArmorSceneComponent
|
||||||
<CoreArmorSceneComponent
|
key={node.uuid}
|
||||||
key={node.uuid}
|
thickness={thickness}
|
||||||
thickness={thickness}
|
node={node}
|
||||||
node={node}
|
/>
|
||||||
/>
|
|
||||||
</group>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
<group ref={gunContainer}>
|
|
||||||
|
<group ref={turretContainer}>
|
||||||
<group position={hullOrigin}>
|
<group position={hullOrigin}>
|
||||||
{armorNodes.map((node) => {
|
{armorNodes.map((node) => {
|
||||||
const isCurrentGun = node.name.startsWith(
|
const isCurrentTurret = node.name.startsWith(
|
||||||
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
|
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
|
||||||
);
|
);
|
||||||
const isVisible = isCurrentGun;
|
const isVisible = isCurrentTurret;
|
||||||
const armorId = nameToArmorId(node.name);
|
const armorId = nameToArmorId(node.name);
|
||||||
const { spaced, thickness } = resolveArmor(
|
const { spaced, thickness } = resolveArmor(
|
||||||
gunModelDefinition.armor,
|
turretModelDefinition.armor,
|
||||||
armorId,
|
armorId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isVisible || spaced || thickness === undefined) return null;
|
if (!isVisible || spaced || thickness === undefined) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<group key={node.uuid} position={turretOrigin}>
|
||||||
key={node.uuid}
|
<CoreArmorSceneComponent
|
||||||
position={turretOrigin.clone().add(gunOrigin)}
|
key={node.uuid}
|
||||||
>
|
thickness={thickness}
|
||||||
<CoreArmorSceneComponent thickness={thickness} node={node} />
|
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>
|
</group>
|
||||||
</group>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -164,6 +164,10 @@ export function ShotDisplay() {
|
|||||||
)
|
)
|
||||||
: LENGTH_INFINITY;
|
: LENGTH_INFINITY;
|
||||||
const inLast = shot.in.layers.findLast((layer) => layer.type !== null)!;
|
const inLast = shot.in.layers.findLast((layer) => layer.type !== null)!;
|
||||||
|
const outTitleColor = shot.out
|
||||||
|
? shotStatusColors[shot.out.status]
|
||||||
|
: undefined;
|
||||||
|
const inTitleColor = shotStatusColors[shot.in.status];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group>
|
<group>
|
||||||
@@ -177,7 +181,7 @@ export function ShotDisplay() {
|
|||||||
<Card ml="9" style={{ width: 300 }}>
|
<Card ml="9" style={{ width: 300 }}>
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
<Flex direction="column" gap="1">
|
<Flex direction="column" gap="1">
|
||||||
<Text color={shotStatusColors[shot.in.status]} weight="bold">
|
<Text color={inTitleColor} weight="bold">
|
||||||
{shot.in.status !== 'blocked' &&
|
{shot.in.status !== 'blocked' &&
|
||||||
shot.in.status !== 'ricochet' && (
|
shot.in.status !== 'ricochet' && (
|
||||||
<>
|
<>
|
||||||
@@ -224,10 +228,24 @@ export function ShotDisplay() {
|
|||||||
{shot.out && shot.out.layers.length > 0 && (
|
{shot.out && shot.out.layers.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Inset side="x">
|
<Inset side="x">
|
||||||
<Separator size="4" />
|
<Flex align="center" gap="2">
|
||||||
|
<Separator
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text size="1" color="gray">
|
||||||
|
ricochet (-25% penetration)
|
||||||
|
</Text>
|
||||||
|
<Separator
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
</Inset>
|
</Inset>
|
||||||
|
|
||||||
<Text color={shotStatusColors[shot.out.status]} weight="bold">
|
<Text color={outTitleColor} weight="bold">
|
||||||
{shot.out.status !== 'blocked' &&
|
{shot.out.status !== 'blocked' &&
|
||||||
shot.out.status !== 'ricochet' && (
|
shot.out.status !== 'ricochet' && (
|
||||||
<>
|
<>
|
||||||
@@ -309,18 +327,22 @@ export function ShotDisplay() {
|
|||||||
new Quaternion().setFromUnitVectors(J_HAT, shot.in.surfaceNormal),
|
new Quaternion().setFromUnitVectors(J_HAT, shot.in.surfaceNormal),
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<mesh position={[0, inLength / 2, 0]}>
|
<mesh position={[0, inLength / 2, 0]} renderOrder={2}>
|
||||||
<cylinderGeometry
|
<cylinderGeometry
|
||||||
args={[TRACER_THIN / 2, TRACER_THIN / 2, inLength]}
|
args={[TRACER_THIN / 2, TRACER_THIN / 2, inLength]}
|
||||||
/>
|
/>
|
||||||
<meshBasicMaterial depthTest={false} />
|
<meshBasicMaterial depthTest={false} transparent />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
<mesh ref={inTracer} position={[0, inLength / 2, 0]}>
|
<mesh ref={inTracer} position={[0, inLength / 2, 0]} renderOrder={3}>
|
||||||
<cylinderGeometry
|
<cylinderGeometry
|
||||||
args={[TRACER_THICK / 2, TRACER_THICK / 2, inLength]}
|
args={[TRACER_THICK / 2, TRACER_THICK / 2, inLength]}
|
||||||
/>
|
/>
|
||||||
<meshBasicMaterial color="red" />
|
<meshBasicMaterial
|
||||||
|
color={inTitleColor}
|
||||||
|
depthTest={false}
|
||||||
|
transparent
|
||||||
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
@@ -334,18 +356,26 @@ export function ShotDisplay() {
|
|||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<mesh position={[0, outLength / 2, 0]}>
|
<mesh position={[0, outLength / 2, 0]} renderOrder={2}>
|
||||||
<cylinderGeometry
|
<cylinderGeometry
|
||||||
args={[TRACER_THIN / 2, TRACER_THIN / 2, outLength]}
|
args={[TRACER_THIN / 2, TRACER_THIN / 2, outLength]}
|
||||||
/>
|
/>
|
||||||
<meshBasicMaterial depthTest={false} />
|
<meshBasicMaterial depthTest={false} transparent />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
<mesh ref={outTracer} position={[0, outLength / 2, 0]}>
|
<mesh
|
||||||
|
ref={outTracer}
|
||||||
|
position={[0, outLength / 2, 0]}
|
||||||
|
renderOrder={3}
|
||||||
|
>
|
||||||
<cylinderGeometry
|
<cylinderGeometry
|
||||||
args={[TRACER_THICK / 2, TRACER_THICK / 2, outLength]}
|
args={[TRACER_THICK / 2, TRACER_THICK / 2, outLength]}
|
||||||
/>
|
/>
|
||||||
<meshBasicMaterial color="yellow" />
|
<meshBasicMaterial
|
||||||
|
color={outTitleColor}
|
||||||
|
depthTest={false}
|
||||||
|
transparent
|
||||||
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in new issue
Block a user