mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
fix: jsx tree node uuids
This commit is contained in:
1 parent
b805c2e3b4
commit
abb72fb674
5 files changed
+312
-262
No files matched your search
@@ -124,11 +124,15 @@ export const TankModel = memo(() => {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsxTree(node, {
|
return jsxTree(
|
||||||
castShadow: true,
|
node,
|
||||||
receiveShadow: true,
|
{
|
||||||
onPointerDown,
|
castShadow: true,
|
||||||
});
|
receiveShadow: true,
|
||||||
|
onPointerDown,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<group ref={turretContainer}>
|
<group ref={turretContainer}>
|
||||||
@@ -189,11 +193,15 @@ export const TankModel = memo(() => {
|
|||||||
window.removeEventListener('pointerup', handlePointerUp);
|
window.removeEventListener('pointerup', handlePointerUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsxTree(node, {
|
return jsxTree(
|
||||||
castShadow: true,
|
node,
|
||||||
receiveShadow: true,
|
{
|
||||||
onPointerDown,
|
castShadow: true,
|
||||||
});
|
receiveShadow: true,
|
||||||
|
onPointerDown,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<group ref={gunContainer}>
|
<group ref={gunContainer}>
|
||||||
@@ -255,11 +263,15 @@ export const TankModel = memo(() => {
|
|||||||
window.removeEventListener('pointerup', handlePointerUp);
|
window.removeEventListener('pointerup', handlePointerUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsxTree(node, {
|
return jsxTree(
|
||||||
castShadow: true,
|
node,
|
||||||
receiveShadow: true,
|
{
|
||||||
onPointerDown,
|
castShadow: true,
|
||||||
});
|
receiveShadow: true,
|
||||||
|
onPointerDown,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -153,14 +153,22 @@ export function CoreArmorSceneComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 0,
|
node,
|
||||||
material: excludeMaterial,
|
{
|
||||||
})}
|
renderOrder: 0,
|
||||||
{jsxTree(node, {
|
material: excludeMaterial,
|
||||||
renderOrder: 1,
|
},
|
||||||
material,
|
node.uuid,
|
||||||
})}
|
)}
|
||||||
|
{jsxTree(
|
||||||
|
node,
|
||||||
|
{
|
||||||
|
renderOrder: 1,
|
||||||
|
material,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+27
-19
@@ -107,26 +107,34 @@ export function SpacedArmorSubExternal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 3,
|
node,
|
||||||
material: new MeshBasicMaterial({
|
{
|
||||||
colorWrite: false,
|
renderOrder: 3,
|
||||||
depthTest: true,
|
material: new MeshBasicMaterial({
|
||||||
depthWrite: true,
|
colorWrite: false,
|
||||||
...(clip ? { clippingPlanes: [clip] } : {}),
|
depthTest: true,
|
||||||
}),
|
depthWrite: true,
|
||||||
onClick() {},
|
...(clip ? { clippingPlanes: [clip] } : {}),
|
||||||
userData: {
|
}),
|
||||||
type: ArmorType.External,
|
onClick() {},
|
||||||
thickness,
|
userData: {
|
||||||
variant,
|
type: ArmorType.External,
|
||||||
} satisfies ArmorUserData,
|
thickness,
|
||||||
})}
|
variant,
|
||||||
|
} satisfies ArmorUserData,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
)}
|
||||||
|
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 4,
|
node,
|
||||||
material,
|
{
|
||||||
})}
|
renderOrder: 4,
|
||||||
|
material,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+21
-13
@@ -113,20 +113,28 @@ export function SpacedArmorSubSpaced({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 2,
|
node,
|
||||||
material,
|
{
|
||||||
onClick() {},
|
renderOrder: 2,
|
||||||
userData: {
|
material,
|
||||||
type: ArmorType.Spaced,
|
onClick() {},
|
||||||
thickness,
|
userData: {
|
||||||
} satisfies ArmorUserData,
|
type: ArmorType.Spaced,
|
||||||
})}
|
thickness,
|
||||||
|
} satisfies ArmorUserData,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
)}
|
||||||
|
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 5,
|
node,
|
||||||
material: depthWriteMaterial,
|
{
|
||||||
})}
|
renderOrder: 5,
|
||||||
|
material: depthWriteMaterial,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -81,251 +81,265 @@ export function SpacedArmorSceneComponent({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{props.type === ArmorType.Core &&
|
{props.type === ArmorType.Core &&
|
||||||
jsxTree(node, {
|
jsxTree(
|
||||||
renderOrder: 0,
|
node,
|
||||||
material: omitMaterial,
|
{
|
||||||
userData: {
|
renderOrder: 0,
|
||||||
type: ArmorType.Core,
|
material: omitMaterial,
|
||||||
thickness,
|
userData: {
|
||||||
} satisfies ArmorUserData,
|
type: ArmorType.Core,
|
||||||
|
thickness,
|
||||||
|
} satisfies ArmorUserData,
|
||||||
|
|
||||||
async onClick(event) {
|
async onClick(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
const duel = useDuel.getState();
|
const duel = useDuel.getState();
|
||||||
const hasCalibratedShells = await hasEquipment(
|
const hasCalibratedShells = await hasEquipment(
|
||||||
103,
|
103,
|
||||||
duel.antagonist!.tank.equipment,
|
duel.antagonist!.tank.equipment,
|
||||||
duel.antagonist!.equipmentMatrix,
|
duel.antagonist!.equipmentMatrix,
|
||||||
);
|
|
||||||
const hasEnhancedArmor = await hasEquipment(
|
|
||||||
110,
|
|
||||||
duel.protagonist!.tank.equipment,
|
|
||||||
duel.protagonist!.equipmentMatrix,
|
|
||||||
);
|
|
||||||
const thicknessCoefficient = hasEnhancedArmor ? 1.04 : 1;
|
|
||||||
const shell = useDuel.getState().antagonist!.shell;
|
|
||||||
const explosive = isExplosive(shell.type);
|
|
||||||
const splashing = canSplash(shell.type);
|
|
||||||
const penetration =
|
|
||||||
resolveNearPenetration(shell.penetration) *
|
|
||||||
(hasCalibratedShells
|
|
||||||
? isExplosive(shell.type)
|
|
||||||
? 1.1
|
|
||||||
: 1.05
|
|
||||||
: 1);
|
|
||||||
const shot: Shot = {
|
|
||||||
layers: [],
|
|
||||||
point: event.point,
|
|
||||||
}; // TODO: type this
|
|
||||||
let remainingPenetration = penetration;
|
|
||||||
|
|
||||||
const shellNormal = camera.position
|
|
||||||
.clone()
|
|
||||||
.sub(event.point)
|
|
||||||
.normalize();
|
|
||||||
|
|
||||||
pushLogs(shellNormal, filterIntersections(event.intersections), 0);
|
|
||||||
|
|
||||||
function filterIntersections(intersectionsRaw: Intersection[]) {
|
|
||||||
const showSpacedArmor =
|
|
||||||
useTankopediaPersistent.getState().model.visual.showSpacedArmor;
|
|
||||||
const intersectionsTyped = intersectionsRaw.filter(
|
|
||||||
({ object }) => object.userData.type !== undefined,
|
|
||||||
) as ArmorMeshIntersection[];
|
|
||||||
const intersectionsFiltered = intersectionsTyped.filter(
|
|
||||||
({ object }) =>
|
|
||||||
showSpacedArmor
|
|
||||||
? true
|
|
||||||
: object.userData.type === ArmorType.Core,
|
|
||||||
);
|
);
|
||||||
const intersectionsWithDuplicates = intersectionsFiltered.slice(
|
const hasEnhancedArmor = await hasEquipment(
|
||||||
|
110,
|
||||||
|
duel.protagonist!.tank.equipment,
|
||||||
|
duel.protagonist!.equipmentMatrix,
|
||||||
|
);
|
||||||
|
const thicknessCoefficient = hasEnhancedArmor ? 1.04 : 1;
|
||||||
|
const shell = useDuel.getState().antagonist!.shell;
|
||||||
|
const explosive = isExplosive(shell.type);
|
||||||
|
const splashing = canSplash(shell.type);
|
||||||
|
const penetration =
|
||||||
|
resolveNearPenetration(shell.penetration) *
|
||||||
|
(hasCalibratedShells
|
||||||
|
? isExplosive(shell.type)
|
||||||
|
? 1.1
|
||||||
|
: 1.05
|
||||||
|
: 1);
|
||||||
|
const shot: Shot = {
|
||||||
|
layers: [],
|
||||||
|
point: event.point,
|
||||||
|
}; // TODO: type this
|
||||||
|
let remainingPenetration = penetration;
|
||||||
|
|
||||||
|
const shellNormal = camera.position
|
||||||
|
.clone()
|
||||||
|
.sub(event.point)
|
||||||
|
.normalize();
|
||||||
|
|
||||||
|
pushLogs(
|
||||||
|
shellNormal,
|
||||||
|
filterIntersections(event.intersections),
|
||||||
0,
|
0,
|
||||||
intersectionsFiltered.findIndex(
|
|
||||||
({ object }) => object.userData.type === ArmorType.Core,
|
|
||||||
) + 1,
|
|
||||||
);
|
);
|
||||||
const firstGunIntersectionIndex =
|
|
||||||
intersectionsWithDuplicates.findIndex(
|
function filterIntersections(intersectionsRaw: Intersection[]) {
|
||||||
|
const showSpacedArmor =
|
||||||
|
useTankopediaPersistent.getState().model.visual
|
||||||
|
.showSpacedArmor;
|
||||||
|
const intersectionsTyped = intersectionsRaw.filter(
|
||||||
|
({ object }) => object.userData.type !== undefined,
|
||||||
|
) as ArmorMeshIntersection[];
|
||||||
|
const intersectionsFiltered = intersectionsTyped.filter(
|
||||||
({ object }) =>
|
({ object }) =>
|
||||||
object.userData.type === ArmorType.External &&
|
showSpacedArmor
|
||||||
object.userData.variant === 'gun',
|
? true
|
||||||
|
: object.userData.type === ArmorType.Core,
|
||||||
);
|
);
|
||||||
const firstTrackIntersectionIndex =
|
const intersectionsWithDuplicates = intersectionsFiltered.slice(
|
||||||
intersectionsWithDuplicates.findIndex(
|
0,
|
||||||
({ object }) =>
|
intersectionsFiltered.findIndex(
|
||||||
object.userData.type === ArmorType.External &&
|
({ object }) => object.userData.type === ArmorType.Core,
|
||||||
object.userData.variant === 'track',
|
) + 1,
|
||||||
);
|
);
|
||||||
let intersections = intersectionsWithDuplicates;
|
const firstGunIntersectionIndex =
|
||||||
|
intersectionsWithDuplicates.findIndex(
|
||||||
if (firstGunIntersectionIndex !== -1) {
|
({ object }) =>
|
||||||
intersections = intersections.filter(({ object }, index) => {
|
object.userData.type === ArmorType.External &&
|
||||||
return object.userData.type === ArmorType.External &&
|
object.userData.variant === 'gun',
|
||||||
object.userData.variant === 'gun'
|
|
||||||
? index === firstGunIntersectionIndex
|
|
||||||
: true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (firstTrackIntersectionIndex !== -1) {
|
|
||||||
intersections = intersections.filter(({ object }, index) => {
|
|
||||||
return object.userData.type === ArmorType.External &&
|
|
||||||
object.userData.variant === 'track'
|
|
||||||
? index === firstTrackIntersectionIndex
|
|
||||||
: true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersections;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pushLogs(
|
|
||||||
shellNormal: Vector3,
|
|
||||||
intersections: ArmorMeshIntersection[],
|
|
||||||
startingIndex: number,
|
|
||||||
) {
|
|
||||||
let layerIndex = startingIndex;
|
|
||||||
let loopIndex = 0;
|
|
||||||
|
|
||||||
if (layerIndex !== 0 && intersections.length > 0) {
|
|
||||||
const distance = (
|
|
||||||
shot.layers.at(-1) as ShotLayerBase
|
|
||||||
).point.distanceTo(intersections[0].point);
|
|
||||||
if (explosive && !splashing)
|
|
||||||
remainingPenetration -= 0.5 * remainingPenetration * distance;
|
|
||||||
const blocked = remainingPenetration < 0;
|
|
||||||
|
|
||||||
shot.layers.push({
|
|
||||||
type: null,
|
|
||||||
status: blocked ? 'blocked' : 'penetration',
|
|
||||||
distance,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (blocked) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const intersection of intersections) {
|
|
||||||
const surfaceNormal = intersection
|
|
||||||
.normal!.clone()
|
|
||||||
.applyQuaternion(
|
|
||||||
event.object.getWorldQuaternion(new Quaternion()),
|
|
||||||
);
|
);
|
||||||
const thickness =
|
const firstTrackIntersectionIndex =
|
||||||
thicknessCoefficient * intersection.object.userData.thickness;
|
intersectionsWithDuplicates.findIndex(
|
||||||
|
({ object }) =>
|
||||||
|
object.userData.type === ArmorType.External &&
|
||||||
|
object.userData.variant === 'track',
|
||||||
|
);
|
||||||
|
let intersections = intersectionsWithDuplicates;
|
||||||
|
|
||||||
if (layerIndex !== 0 && startingIndex === 0) {
|
if (firstGunIntersectionIndex !== -1) {
|
||||||
const previousIntersection = intersections[layerIndex - 1];
|
intersections = intersections.filter(({ object }, index) => {
|
||||||
const distance =
|
return object.userData.type === ArmorType.External &&
|
||||||
intersection.distance - previousIntersection.distance;
|
object.userData.variant === 'gun'
|
||||||
|
? index === firstGunIntersectionIndex
|
||||||
|
: true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (firstTrackIntersectionIndex !== -1) {
|
||||||
|
intersections = intersections.filter(({ object }, index) => {
|
||||||
|
return object.userData.type === ArmorType.External &&
|
||||||
|
object.userData.variant === 'track'
|
||||||
|
? index === firstTrackIntersectionIndex
|
||||||
|
: true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushLogs(
|
||||||
|
shellNormal: Vector3,
|
||||||
|
intersections: ArmorMeshIntersection[],
|
||||||
|
startingIndex: number,
|
||||||
|
) {
|
||||||
|
let layerIndex = startingIndex;
|
||||||
|
let loopIndex = 0;
|
||||||
|
|
||||||
|
if (layerIndex !== 0 && intersections.length > 0) {
|
||||||
|
const distance = (
|
||||||
|
shot.layers.at(-1) as ShotLayerBase
|
||||||
|
).point.distanceTo(intersections[0].point);
|
||||||
if (explosive && !splashing)
|
if (explosive && !splashing)
|
||||||
remainingPenetration -=
|
remainingPenetration -=
|
||||||
0.5 * remainingPenetration * distance;
|
0.5 * remainingPenetration * distance;
|
||||||
const wasted = remainingPenetration < 0;
|
|
||||||
|
|
||||||
shot.layers.push({
|
|
||||||
type: null,
|
|
||||||
status: wasted ? 'blocked' : 'penetration',
|
|
||||||
distance,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (wasted && !splashing) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intersection.object.userData.type === ArmorType.External) {
|
|
||||||
remainingPenetration -= thickness;
|
|
||||||
const blocked = remainingPenetration < 0;
|
const blocked = remainingPenetration < 0;
|
||||||
|
|
||||||
shot.layers.push({
|
shot.layers.push({
|
||||||
type: ArmorType.External,
|
type: null,
|
||||||
index: layerIndex,
|
|
||||||
shellNormal,
|
|
||||||
surfaceNormal,
|
|
||||||
point: intersection.point,
|
|
||||||
thickness: intersection.object.userData.thickness,
|
|
||||||
status: blocked ? 'blocked' : 'penetration',
|
status: blocked ? 'blocked' : 'penetration',
|
||||||
|
distance,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (splashing) {
|
if (blocked) return;
|
||||||
remainingPenetration = Math.max(0, remainingPenetration);
|
}
|
||||||
} else if (blocked) {
|
|
||||||
break;
|
for (const intersection of intersections) {
|
||||||
}
|
const surfaceNormal = intersection
|
||||||
} else {
|
.normal!.clone()
|
||||||
const type = intersection.object.userData.type;
|
.applyQuaternion(
|
||||||
const angle = surfaceNormal.angleTo(shellNormal);
|
event.object.getWorldQuaternion(new Quaternion()),
|
||||||
const ricochet = degToRad(shell.ricochet ?? 90);
|
);
|
||||||
const normalization = degToRad(shell.normalization ?? 0);
|
const thickness =
|
||||||
const threeCalibersRule =
|
thicknessCoefficient *
|
||||||
shell.caliber > thickness * 3 || layerIndex > 0;
|
intersection.object.userData.thickness;
|
||||||
const twoCalibersRule = shell.caliber > thickness * 2;
|
|
||||||
const finalNormalization = twoCalibersRule
|
if (layerIndex !== 0 && startingIndex === 0) {
|
||||||
? (1.4 * normalization * shell.caliber) / (2.0 * thickness)
|
const previousIntersection = intersections[layerIndex - 1];
|
||||||
: normalization;
|
const distance =
|
||||||
const finalThickness =
|
intersection.distance - previousIntersection.distance;
|
||||||
thickness === 0
|
if (explosive && !splashing)
|
||||||
? 0
|
remainingPenetration -=
|
||||||
: thickness /
|
0.5 * remainingPenetration * distance;
|
||||||
Math.cos(Math.max(0, angle - finalNormalization));
|
const wasted = remainingPenetration < 0;
|
||||||
|
|
||||||
if (!threeCalibersRule && angle >= ricochet) {
|
|
||||||
shot.layers.push({
|
shot.layers.push({
|
||||||
type,
|
type: null,
|
||||||
index: layerIndex,
|
status: wasted ? 'blocked' : 'penetration',
|
||||||
shellNormal,
|
distance,
|
||||||
surfaceNormal,
|
|
||||||
point: intersection.point,
|
|
||||||
thickness,
|
|
||||||
thicknessAngled: finalThickness,
|
|
||||||
angle,
|
|
||||||
status: 'ricochet',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
remainingPenetration *= 0.75;
|
if (wasted && !splashing) return;
|
||||||
|
}
|
||||||
|
|
||||||
const raycaster = new Raycaster();
|
if (
|
||||||
const newShellNormal = shellNormal
|
intersection.object.userData.type === ArmorType.External
|
||||||
.clone()
|
) {
|
||||||
.reflect(surfaceNormal);
|
remainingPenetration -= thickness;
|
||||||
const newCameraNormal = newShellNormal
|
|
||||||
.clone()
|
|
||||||
.multiplyScalar(-1);
|
|
||||||
|
|
||||||
raycaster.set(intersection.point, newCameraNormal);
|
|
||||||
pushLogs(
|
|
||||||
newShellNormal,
|
|
||||||
filterIntersections(
|
|
||||||
raycaster.intersectObjects(scene.children, true),
|
|
||||||
),
|
|
||||||
layerIndex + 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
remainingPenetration -= finalThickness;
|
|
||||||
const blocked = remainingPenetration < 0;
|
const blocked = remainingPenetration < 0;
|
||||||
|
|
||||||
shot.layers.push({
|
shot.layers.push({
|
||||||
type,
|
type: ArmorType.External,
|
||||||
index: layerIndex,
|
index: layerIndex,
|
||||||
shellNormal,
|
shellNormal,
|
||||||
surfaceNormal,
|
surfaceNormal,
|
||||||
point: intersection.point,
|
point: intersection.point,
|
||||||
thickness,
|
thickness: intersection.object.userData.thickness,
|
||||||
thicknessAngled: finalThickness,
|
|
||||||
angle,
|
|
||||||
status: blocked ? 'blocked' : 'penetration',
|
status: blocked ? 'blocked' : 'penetration',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (splashing) {
|
||||||
|
remainingPenetration = Math.max(0, remainingPenetration);
|
||||||
|
} else if (blocked) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const type = intersection.object.userData.type;
|
||||||
|
const angle = surfaceNormal.angleTo(shellNormal);
|
||||||
|
const ricochet = degToRad(shell.ricochet ?? 90);
|
||||||
|
const normalization = degToRad(shell.normalization ?? 0);
|
||||||
|
const threeCalibersRule =
|
||||||
|
shell.caliber > thickness * 3 || layerIndex > 0;
|
||||||
|
const twoCalibersRule = shell.caliber > thickness * 2;
|
||||||
|
const finalNormalization = twoCalibersRule
|
||||||
|
? (1.4 * normalization * shell.caliber) /
|
||||||
|
(2.0 * thickness)
|
||||||
|
: normalization;
|
||||||
|
const finalThickness =
|
||||||
|
thickness === 0
|
||||||
|
? 0
|
||||||
|
: thickness /
|
||||||
|
Math.cos(Math.max(0, angle - finalNormalization));
|
||||||
|
|
||||||
|
if (!threeCalibersRule && angle >= ricochet) {
|
||||||
|
shot.layers.push({
|
||||||
|
type,
|
||||||
|
index: layerIndex,
|
||||||
|
shellNormal,
|
||||||
|
surfaceNormal,
|
||||||
|
point: intersection.point,
|
||||||
|
thickness,
|
||||||
|
thicknessAngled: finalThickness,
|
||||||
|
angle,
|
||||||
|
status: 'ricochet',
|
||||||
|
});
|
||||||
|
|
||||||
|
remainingPenetration *= 0.75;
|
||||||
|
|
||||||
|
const raycaster = new Raycaster();
|
||||||
|
const newShellNormal = shellNormal
|
||||||
|
.clone()
|
||||||
|
.reflect(surfaceNormal);
|
||||||
|
const newCameraNormal = newShellNormal
|
||||||
|
.clone()
|
||||||
|
.multiplyScalar(-1);
|
||||||
|
|
||||||
|
raycaster.set(intersection.point, newCameraNormal);
|
||||||
|
pushLogs(
|
||||||
|
newShellNormal,
|
||||||
|
filterIntersections(
|
||||||
|
raycaster.intersectObjects(scene.children, true),
|
||||||
|
),
|
||||||
|
layerIndex + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
remainingPenetration -= finalThickness;
|
||||||
|
const blocked = remainingPenetration < 0;
|
||||||
|
|
||||||
|
shot.layers.push({
|
||||||
|
type,
|
||||||
|
index: layerIndex,
|
||||||
|
shellNormal,
|
||||||
|
surfaceNormal,
|
||||||
|
point: intersection.point,
|
||||||
|
thickness,
|
||||||
|
thicknessAngled: finalThickness,
|
||||||
|
angle,
|
||||||
|
status: blocked ? 'blocked' : 'penetration',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layerIndex++;
|
||||||
|
loopIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
layerIndex++;
|
|
||||||
loopIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
useTankopediaTemporary.setState({ shot });
|
useTankopediaTemporary.setState({ shot });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})}
|
node.uuid,
|
||||||
|
)}
|
||||||
|
|
||||||
{props.type === ArmorType.Spaced && (
|
{props.type === ArmorType.Spaced && (
|
||||||
<SpacedArmorSubSpaced node={node} thickness={thickness} />
|
<SpacedArmorSubSpaced node={node} thickness={thickness} />
|
||||||
|
|||||||
Reference in new issue
Block a user