mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: more progress
This commit is contained in:
1 parent
f55313e0cd
commit
7f49245f15
4 files changed
+95
-67
No files matched your search
@@ -5,7 +5,7 @@ import { Canvas } from '@react-three/fiber';
|
||||
import { Suspense, use, useEffect, useRef, useState } from 'react';
|
||||
import { isMobile } from 'react-device-detect';
|
||||
import { Armor } from '../../../../../../components/Armor';
|
||||
import { ShotScene } from '../../../../../../components/Armor/components/ShotScene';
|
||||
import { ShotDisplay } from '../../../../../../components/Armor/components/ShotDisplay';
|
||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
||||
import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTransform';
|
||||
@@ -201,6 +201,7 @@ export function TankSandbox() {
|
||||
<Lighting />
|
||||
<TankModel />
|
||||
<Armor />
|
||||
<ShotDisplay />
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
</div>
|
||||
|
||||
+31
-20
@@ -1,6 +1,6 @@
|
||||
import { Text } from '@radix-ui/themes';
|
||||
import { Html } from '@react-three/drei';
|
||||
import { DoubleSide, Euler, Quaternion, Vector3 } from 'three';
|
||||
import { Euler, Quaternion, Vector3 } from 'three';
|
||||
import { J_HAT } from '../../../constants/axis';
|
||||
import {
|
||||
ShotLayerGap,
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
// const THICKNESS = 0.05;
|
||||
// const LENGTH = 4;
|
||||
|
||||
export function ShotScene() {
|
||||
export function ShotDisplay() {
|
||||
const shot = useTankopediaTemporary((state) => state.shot);
|
||||
|
||||
return (
|
||||
@@ -39,28 +39,39 @@ export function ShotScene() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<mesh renderOrder={1} key={`${index}-point`} position={layer.point}>
|
||||
<icosahedronGeometry args={[1 / 16, 1]} />
|
||||
<meshBasicMaterial
|
||||
side={DoubleSide}
|
||||
color={
|
||||
layer.status === 'penetration'
|
||||
? 0x00ff00
|
||||
: layer.status === 'blocked'
|
||||
? 0xff0000
|
||||
: 0xffff00
|
||||
}
|
||||
/>
|
||||
</mesh>
|
||||
|
||||
<group
|
||||
key={`${index}-line`}
|
||||
position={layer.point}
|
||||
rotation={shellRotation}
|
||||
>
|
||||
{shot.length > 1 && (
|
||||
<Html>
|
||||
<Text>{layer.index + 1}</Text>
|
||||
<Html center>
|
||||
<div
|
||||
style={{
|
||||
width: 12,
|
||||
height: 12,
|
||||
borderRadius: '100%',
|
||||
position: 'relative',
|
||||
backgroundColor:
|
||||
layer.status === 'penetration'
|
||||
? '#00ff00'
|
||||
: layer.status === 'blocked'
|
||||
? '#ff0000'
|
||||
: '#ffff00',
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '100%',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
marginLeft: 8,
|
||||
}}
|
||||
>
|
||||
{layer.index + 1}
|
||||
</Text>
|
||||
</div>
|
||||
</Html>
|
||||
)}
|
||||
|
||||
@@ -73,9 +84,9 @@ export function ShotScene() {
|
||||
}
|
||||
|
||||
return (
|
||||
<mesh position={[0, length / 2, 0]} renderOrder={0}>
|
||||
<mesh position={[0, length / 2, 0]}>
|
||||
<cylinderGeometry args={[1 / 64, 1 / 64, length]} />
|
||||
<meshBasicMaterial color={0xffffff} />
|
||||
<meshBasicMaterial color={0xffffff} depthTest={false} />
|
||||
</mesh>
|
||||
);
|
||||
})()}
|
||||
@@ -8,13 +8,17 @@ import {
|
||||
Scene,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
import { degToRad, radToDeg } from 'three/src/math/MathUtils';
|
||||
import { degToRad } from 'three/src/math/MathUtils';
|
||||
import { isExplosive } from '../../../../core/blitz/isExplosive';
|
||||
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
||||
import { hasEquipment } from '../../../../core/blitzkrieg/hasEquipment';
|
||||
import { jsxTree } from '../../../../core/blitzkrieg/jsxTree';
|
||||
import { useDuel } from '../../../../stores/duel';
|
||||
import { Shot, useTankopediaTemporary } from '../../../../stores/tankopedia';
|
||||
import {
|
||||
Shot,
|
||||
ShotLayerBase,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../stores/tankopedia';
|
||||
import { ArmorType } from '../SpacedArmorScene';
|
||||
import { SpacedArmorSubExternal } from './components/SpacedArmorSubExternal';
|
||||
import { SpacedArmorSubSpaced } from './components/SpacedArmorSubSpaced';
|
||||
@@ -68,7 +72,7 @@ export function SpacedArmorSceneComponent({
|
||||
...props
|
||||
}: SpacedArmorSceneComponentProps) {
|
||||
const camera = useThree((state) => state.camera);
|
||||
const cameraNormal = new Vector3();
|
||||
// const cameraNormal = new Vector3();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -104,26 +108,26 @@ export function SpacedArmorSceneComponent({
|
||||
.clone()
|
||||
.sub(event.point)
|
||||
.normalize();
|
||||
shellNormal
|
||||
.copy(camera.getWorldDirection(cameraNormal))
|
||||
.multiplyScalar(-1);
|
||||
const cameraNormal = shellNormal.clone().multiplyScalar(-1);
|
||||
|
||||
pushLogs(
|
||||
shellNormal,
|
||||
cameraNormal,
|
||||
filterIntersections(event.intersections),
|
||||
true,
|
||||
0,
|
||||
);
|
||||
|
||||
console.clear();
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
shot.map((i) => ({
|
||||
...i,
|
||||
...(i.angle ? { angle: radToDeg(i.angle) } : {}),
|
||||
})),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
// console.clear();
|
||||
// console.log(
|
||||
// JSON.stringify(
|
||||
// shot.map((i) => ({
|
||||
// ...i,
|
||||
// ...(i.angle ? { angle: radToDeg(i.angle) } : {}),
|
||||
// })),
|
||||
// null,
|
||||
// 2,
|
||||
// ),
|
||||
// );
|
||||
|
||||
function filterIntersections(intersectionsRaw: Intersection[]) {
|
||||
const intersectionsAll = intersectionsRaw.filter(
|
||||
@@ -166,15 +170,35 @@ export function SpacedArmorSceneComponent({
|
||||
});
|
||||
}
|
||||
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
intersections.map((i) => i.object.userData),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
function pushLogs(
|
||||
shellNormal: Vector3,
|
||||
cameraNormal: Vector3,
|
||||
intersections: ArmorMeshIntersection[],
|
||||
allowRicochets: boolean,
|
||||
startingIndex: number,
|
||||
) {
|
||||
let index = 0;
|
||||
let layerIndex = startingIndex;
|
||||
let loopIndex = 0;
|
||||
|
||||
if (layerIndex !== 0) {
|
||||
shot.push({
|
||||
type: null,
|
||||
distance: (shot.at(-1) as ShotLayerBase).point.distanceTo(
|
||||
intersections[0].point,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
for (const intersection of intersections) {
|
||||
const surfaceNormal = intersection
|
||||
.normal!.clone()
|
||||
@@ -184,8 +208,8 @@ export function SpacedArmorSceneComponent({
|
||||
const thickness =
|
||||
thicknessCoefficient * intersection.object.userData.thickness;
|
||||
|
||||
if (index !== 0) {
|
||||
const previousIntersection = intersections[index - 1];
|
||||
if (layerIndex !== 0 && startingIndex === 0) {
|
||||
const previousIntersection = intersections[layerIndex - 1];
|
||||
shot.push({
|
||||
type: null,
|
||||
distance:
|
||||
@@ -199,7 +223,7 @@ export function SpacedArmorSceneComponent({
|
||||
|
||||
shot.push({
|
||||
type: ArmorType.External,
|
||||
index,
|
||||
index: layerIndex,
|
||||
shellNormal,
|
||||
surfaceNormal,
|
||||
point: intersection.point,
|
||||
@@ -210,19 +234,11 @@ export function SpacedArmorSceneComponent({
|
||||
if (blocked) break;
|
||||
} else {
|
||||
const type = intersection.object.userData.type;
|
||||
shellNormal.copy(
|
||||
cameraNormal
|
||||
.copy(camera.position)
|
||||
.sub(event.point)
|
||||
.normalize(),
|
||||
);
|
||||
const angle = surfaceNormal.angleTo(shellNormal);
|
||||
const ricochet = degToRad(shell.ricochet ?? 90);
|
||||
const normalization = degToRad(shell.normalization ?? 0);
|
||||
const threeCalibersRule =
|
||||
shell.caliber > thickness * 3 ||
|
||||
index > 0 ||
|
||||
!allowRicochets;
|
||||
shell.caliber > thickness * 3 || layerIndex > 0;
|
||||
const twoCalibersRule = shell.caliber > thickness * 2;
|
||||
const finalNormalization = twoCalibersRule
|
||||
? (1.4 * normalization * shell.caliber) / (2.0 * thickness)
|
||||
@@ -234,7 +250,7 @@ export function SpacedArmorSceneComponent({
|
||||
if (!threeCalibersRule && angle >= ricochet) {
|
||||
shot.push({
|
||||
type,
|
||||
index,
|
||||
index: layerIndex,
|
||||
shellNormal,
|
||||
surfaceNormal,
|
||||
point: intersection.point,
|
||||
@@ -245,15 +261,21 @@ export function SpacedArmorSceneComponent({
|
||||
});
|
||||
|
||||
const raycaster = new Raycaster();
|
||||
const newShellNormal = cameraNormal
|
||||
const newShellNormal = shellNormal
|
||||
.clone()
|
||||
.reflect(surfaceNormal);
|
||||
const newCameraNormal = newShellNormal
|
||||
.clone()
|
||||
.multiplyScalar(-1);
|
||||
|
||||
raycaster.set(intersection.point, newShellNormal);
|
||||
raycaster.set(intersection.point, newCameraNormal);
|
||||
pushLogs(
|
||||
newShellNormal,
|
||||
raycaster.intersectObjects(scene.children, true),
|
||||
false,
|
||||
newCameraNormal,
|
||||
filterIntersections(
|
||||
raycaster.intersectObjects(scene.children, true),
|
||||
),
|
||||
layerIndex + 1,
|
||||
);
|
||||
|
||||
break;
|
||||
@@ -261,7 +283,7 @@ export function SpacedArmorSceneComponent({
|
||||
const blocked = remainingPenetration < 0;
|
||||
shot.push({
|
||||
type,
|
||||
index,
|
||||
index: layerIndex,
|
||||
shellNormal,
|
||||
surfaceNormal,
|
||||
point: intersection.point,
|
||||
@@ -273,7 +295,8 @@ export function SpacedArmorSceneComponent({
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
layerIndex++;
|
||||
loopIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,19 +3,16 @@ import { memo, useState } from 'react';
|
||||
import { DepthTexture, Scene, Vector2 } from 'three';
|
||||
import { CoreArmorScene } from './components/CoreArmorScene';
|
||||
import { spacedArmorRenderTarget } from './components/CoreArmorSceneComponent';
|
||||
import { ShotScene } from './components/ShotScene';
|
||||
import { SpacedArmorScene } from './components/SpacedArmorScene';
|
||||
|
||||
export const Armor = memo(() => {
|
||||
const [spacedArmorScene] = useState(() => new Scene());
|
||||
const [coreArmorScene] = useState(() => new Scene());
|
||||
const [shotScene] = useState(() => new Scene());
|
||||
const spacedArmorPortal = createPortal(
|
||||
<SpacedArmorScene scene={spacedArmorScene} />,
|
||||
spacedArmorScene,
|
||||
);
|
||||
const coreArmorPortal = createPortal(<CoreArmorScene />, coreArmorScene);
|
||||
const shotPortal = createPortal(<ShotScene />, shotScene);
|
||||
|
||||
const renderSize = new Vector2();
|
||||
const newRenderSize = new Vector2();
|
||||
@@ -44,16 +41,12 @@ export const Armor = memo(() => {
|
||||
|
||||
gl.clearDepth();
|
||||
gl.render(coreArmorScene, camera);
|
||||
|
||||
gl.clearDepth();
|
||||
gl.render(shotScene, camera);
|
||||
}, 1);
|
||||
|
||||
return (
|
||||
<>
|
||||
{spacedArmorPortal}
|
||||
{coreArmorPortal}
|
||||
{shotPortal}
|
||||
</>
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user