feat: complete math

This commit is contained in:
TrèsAbhi committed 2024-05-25 13:32:00 -05:00
1 parent a2bf592eaf
commit dc50c4a758
4 files changed
+43 -275

No files matched your search

@@ -149,7 +149,7 @@ export function Modules() {
)
) {
draft.protagonist!.gun = draft.protagonist!.turret.guns.at(-1)!;
draft.protagonist!.shell = draft.protagonist!.gun.shells.at(-1)!;
draft.protagonist!.shell = draft.protagonist!.gun.shells[0];
}
} else if (unlock.type === 'gun') {
const gunInTurret = draft.protagonist!.turret.guns.find(
@@ -157,7 +157,7 @@ export function Modules() {
);
if (gunInTurret) {
draft.protagonist!.gun = gunInTurret;
draft.protagonist!.shell = gunInTurret.shells.at(-1)!;
draft.protagonist!.shell = gunInTurret.shells[0];
} else {
// TODO: warn somehow?
const suitableTurret = draft.protagonist!.tank.turrets.find(
@@ -169,7 +169,7 @@ export function Modules() {
draft.protagonist!.turret = suitableTurret;
draft.protagonist!.gun = gunInSuitableTurret;
draft.protagonist!.shell = gunInSuitableTurret.shells.at(-1)!;
draft.protagonist!.shell = gunInSuitableTurret.shells[0];
}
} else if (unlock.type === 'engine') {
draft.protagonist!.engine = draft.protagonist!.tank.engines.find(
@@ -9,6 +9,7 @@ import { degToRad } from 'three/src/math/MathUtils';
import { ArmorUserData } from '../..';
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/resolvePenetrationCoefficient';
import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
import { jsxTree } from '../../../../../../core/blitzkit/jsxTree';
import { ShellDefinition } from '../../../../../../core/blitzkit/tankDefinitions';
@@ -16,8 +17,6 @@ import { EquipmentMatrix, useDuel } from '../../../../../../stores/duel';
import { ArmorType } from '../../../SpacedArmorScene';
import fragmentShader from './shaders/fragment.glsl';
import vertexShader from './shaders/vertex.glsl';
import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/resolvePenetrationCoefficient';
import { hasColorSpace } from '@react-three/fiber/dist/declarations/src/core/utils';
interface SpacedArmorSubSpacedProps {
node: Object3D;
@@ -85,8 +84,10 @@ export function SpacedArmorSubSpaced({
duel.antagonist!.tank.equipment,
equipment,
);
material.uniforms.penetration.value=penetration*resolvePenetrationCoefficient(hasCalibratedShells, shell.type)
material.uniforms.penetration.value =
penetration *
resolvePenetrationCoefficient(hasCalibratedShells, shell.type);
}
handleShellChange(useDuel.getState().antagonist!.shell);
@@ -18,6 +18,7 @@ import { useDuel } from '../../../../stores/duel';
import {
Shot,
ShotLayerBase,
ShotLayerNonExternal,
useTankopediaTemporary,
} from '../../../../stores/tankopedia';
import { ArmorType } from '../SpacedArmorScene';
@@ -107,13 +108,13 @@ export function SpacedArmorSceneComponent({
const hasCalibratedShells = await hasEquipment(
103,
protagonist!.tank.equipment,
protagonist!.equipmentMatrix,
antagonist!.tank.equipment,
antagonist!.equipmentMatrix,
);
const hasEnhancedArmor = await hasEquipment(
110,
antagonist!.tank.equipment,
antagonist!.equipmentMatrix,
protagonist!.tank.equipment,
protagonist!.equipmentMatrix,
);
const penetration =
resolveNearPenetration(shell.penetration) *
@@ -186,6 +187,7 @@ export function SpacedArmorSceneComponent({
status: blocked ? 'blocked' : 'penetration',
});
} else {
const thickness = layer.thickness;
const ricochet = degToRad(
isExplosive(shell.type) ? 90 : shell.ricochet!,
);
@@ -245,19 +247,24 @@ export function SpacedArmorSceneComponent({
index++;
}
const lastLayer = shot.layersIn.at(-1) as ShotLayerBase;
const lastLayer = shot.layersIn.at(-1) as ShotLayerNonExternal;
const firstLayer = shot.layersIn[0] as ShotLayerBase;
if (shell.type === ShellType.HE) {
const totalThickness = shot.layersIn.reduce((acc, layer) => {
if (layer.type === null) return acc;
const totalSpacedArmorThickness = shot.layersIn.reduce(
(acc, layer) => {
if (layer.type === null || layer.type === ArmorType.Core) {
return acc;
}
if (layer.type === ArmorType.External) {
return acc + layer.thickness;
}
if (layer.type === ArmorType.External) {
return acc + layer.thickness;
}
return acc + layer.thicknessAngled;
}, 0);
return acc + layer.thicknessAngled;
},
0,
);
const distanceFromSpacedArmor = firstLayer.point.distanceTo(
lastLayer.point,
);
@@ -266,15 +273,26 @@ export function SpacedArmorSceneComponent({
0.5 *
shell.damage.armor *
(1 - distanceFromSpacedArmor / shell.explosionRadius!) -
1.1 * totalThickness,
1.1 *
(lastLayer.thicknessAngled +
Math.min(penetration, totalSpacedArmorThickness)),
);
/**
* Above is some peculiar math. We're multiplying 1.1 by the
* thickness of the core plate plus the total spaced armor
* thickness capped to the penetration itself. This is because
* the shader is normalized by the penetration value; hence,
* the total spaced armor thickness cannot ever be thicker
* than the penetration. This is a precision error on the
* shader-side and I do not intend on fixing it. Instead,
* for parity's sake, I am capping the value here.
*/
if (
shot.layersIn.length > 1 ||
lastLayer.status === 'blocked'
) {
console.log(finalDamage);
shot.status = finalDamage > 0 ? 'splash' : 'blocked';
shot.damage = finalDamage;
} else {
@@ -296,257 +314,6 @@ export function SpacedArmorSceneComponent({
console.log(shot);
useTankopediaTemporary.setState({ shot });
// const duel = useDuel.getState();
// const hasCalibratedShells = await hasEquipment(
// 103,
// duel.antagonist!.tank.equipment,
// duel.antagonist!.equipmentMatrix,
// );
// const hasEnhancedArmor = await hasEquipment(
// 110,
// duel.protagonist!.tank.equipment,
// duel.protagonist!.equipmentMatrix,
// );
// const thicknessCoefficient = hasEnhancedArmor ? 1.03 : 1;
// const shell = useDuel.getState().antagonist!.shell;
// const explosive = isExplosive(shell.type);
// const splashing = canSplash(shell.type);
// const penetration =
// resolveNearPenetration(shell.penetration) *
// (hasCalibratedShells
// ? duel.antagonist!.shell.type === 'ap'
// ? 1.08
// : duel.antagonist!.shell.type === 'ap_cr'
// ? 1.05
// : duel.antagonist!.shell.type === 'hc'
// ? 1.13
// : 1.08
// : 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(
// 0,
// intersectionsFiltered.findIndex(
// ({ object }) => object.userData.type === ArmorType.Core,
// ) + 1,
// );
// const firstGunIntersectionIndex =
// intersectionsWithDuplicates.findIndex(
// ({ object }) =>
// object.userData.type === ArmorType.External &&
// object.userData.variant === 'gun',
// );
// const firstTrackIntersectionIndex =
// intersectionsWithDuplicates.findIndex(
// ({ object }) =>
// object.userData.type === ArmorType.External &&
// object.userData.variant === 'track',
// );
// let intersections = intersectionsWithDuplicates;
// if (firstGunIntersectionIndex !== -1) {
// intersections = intersections.filter(({ object }, index) => {
// return object.userData.type === ArmorType.External &&
// 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 (shell.type === 'hc') {
// 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 =
// thicknessCoefficient *
// intersection.object.userData.thickness;
// if (layerIndex !== 0 && startingIndex === 0) {
// const previousIntersection = intersections[layerIndex - 1];
// const distance =
// intersection.distance - previousIntersection.distance;
// if (shell.type === 'hc') {
// remainingPenetration -=
// 0.5 * remainingPenetration * distance;
// }
// const wasted = remainingPenetration < 0 || splashing;
// 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;
// shot.layers.push({
// type: ArmorType.External,
// index: layerIndex,
// shellNormal,
// surfaceNormal,
// point: intersection.point,
// thickness: intersection.object.userData.thickness,
// 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(
// isExplosive(shell.type) ? 90 : shell.ricochet!,
// );
// 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++;
// }
// }
// useTankopediaTemporary.setState({ shot });
},
},
node.uuid,
+2 -2
View File
@@ -63,7 +63,7 @@ export function ModuleManager({
const draft = { ...modules };
draft.turret = turret;
draft.gun = draft.turret.guns.at(-1)!;
draft.shell = draft.gun.shells.at(-1)!;
draft.shell = draft.gun.shells[0];
onChange?.(draft);
setTurretMenuOpen(false);
@@ -106,7 +106,7 @@ export function ModuleManager({
onClick={() => {
const draft = { ...modules };
draft.gun = gun;
draft.shell = draft.gun.shells.at(-1)!;
draft.shell = draft.gun.shells[0];
onChange?.(draft);
setGunMenuOpen(false);