mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01: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 { Suspense, use, useEffect, useRef, useState } from 'react';
|
||||||
import { isMobile } from 'react-device-detect';
|
import { isMobile } from 'react-device-detect';
|
||||||
import { Armor } from '../../../../../../components/Armor';
|
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 { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
||||||
import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTransform';
|
import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTransform';
|
||||||
@@ -201,6 +201,7 @@ export function TankSandbox() {
|
|||||||
<Lighting />
|
<Lighting />
|
||||||
<TankModel />
|
<TankModel />
|
||||||
<Armor />
|
<Armor />
|
||||||
|
<ShotDisplay />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+31
-20
@@ -1,6 +1,6 @@
|
|||||||
import { Text } from '@radix-ui/themes';
|
import { Text } from '@radix-ui/themes';
|
||||||
import { Html } from '@react-three/drei';
|
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 { J_HAT } from '../../../constants/axis';
|
||||||
import {
|
import {
|
||||||
ShotLayerGap,
|
ShotLayerGap,
|
||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
// const THICKNESS = 0.05;
|
// const THICKNESS = 0.05;
|
||||||
// const LENGTH = 4;
|
// const LENGTH = 4;
|
||||||
|
|
||||||
export function ShotScene() {
|
export function ShotDisplay() {
|
||||||
const shot = useTankopediaTemporary((state) => state.shot);
|
const shot = useTankopediaTemporary((state) => state.shot);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -39,28 +39,39 @@ export function ShotScene() {
|
|||||||
|
|
||||||
return (
|
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
|
<group
|
||||||
key={`${index}-line`}
|
key={`${index}-line`}
|
||||||
position={layer.point}
|
position={layer.point}
|
||||||
rotation={shellRotation}
|
rotation={shellRotation}
|
||||||
>
|
>
|
||||||
{shot.length > 1 && (
|
{shot.length > 1 && (
|
||||||
<Html>
|
<Html center>
|
||||||
<Text>{layer.index + 1}</Text>
|
<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>
|
</Html>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -73,9 +84,9 @@ export function ShotScene() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<mesh position={[0, length / 2, 0]} renderOrder={0}>
|
<mesh position={[0, length / 2, 0]}>
|
||||||
<cylinderGeometry args={[1 / 64, 1 / 64, length]} />
|
<cylinderGeometry args={[1 / 64, 1 / 64, length]} />
|
||||||
<meshBasicMaterial color={0xffffff} />
|
<meshBasicMaterial color={0xffffff} depthTest={false} />
|
||||||
</mesh>
|
</mesh>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
@@ -8,13 +8,17 @@ import {
|
|||||||
Scene,
|
Scene,
|
||||||
Vector3,
|
Vector3,
|
||||||
} from 'three';
|
} from 'three';
|
||||||
import { degToRad, radToDeg } from 'three/src/math/MathUtils';
|
import { degToRad } from 'three/src/math/MathUtils';
|
||||||
import { isExplosive } from '../../../../core/blitz/isExplosive';
|
import { isExplosive } from '../../../../core/blitz/isExplosive';
|
||||||
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
||||||
import { hasEquipment } from '../../../../core/blitzkrieg/hasEquipment';
|
import { hasEquipment } from '../../../../core/blitzkrieg/hasEquipment';
|
||||||
import { jsxTree } from '../../../../core/blitzkrieg/jsxTree';
|
import { jsxTree } from '../../../../core/blitzkrieg/jsxTree';
|
||||||
import { useDuel } from '../../../../stores/duel';
|
import { useDuel } from '../../../../stores/duel';
|
||||||
import { Shot, useTankopediaTemporary } from '../../../../stores/tankopedia';
|
import {
|
||||||
|
Shot,
|
||||||
|
ShotLayerBase,
|
||||||
|
useTankopediaTemporary,
|
||||||
|
} from '../../../../stores/tankopedia';
|
||||||
import { ArmorType } from '../SpacedArmorScene';
|
import { ArmorType } from '../SpacedArmorScene';
|
||||||
import { SpacedArmorSubExternal } from './components/SpacedArmorSubExternal';
|
import { SpacedArmorSubExternal } from './components/SpacedArmorSubExternal';
|
||||||
import { SpacedArmorSubSpaced } from './components/SpacedArmorSubSpaced';
|
import { SpacedArmorSubSpaced } from './components/SpacedArmorSubSpaced';
|
||||||
@@ -68,7 +72,7 @@ export function SpacedArmorSceneComponent({
|
|||||||
...props
|
...props
|
||||||
}: SpacedArmorSceneComponentProps) {
|
}: SpacedArmorSceneComponentProps) {
|
||||||
const camera = useThree((state) => state.camera);
|
const camera = useThree((state) => state.camera);
|
||||||
const cameraNormal = new Vector3();
|
// const cameraNormal = new Vector3();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -104,26 +108,26 @@ export function SpacedArmorSceneComponent({
|
|||||||
.clone()
|
.clone()
|
||||||
.sub(event.point)
|
.sub(event.point)
|
||||||
.normalize();
|
.normalize();
|
||||||
shellNormal
|
const cameraNormal = shellNormal.clone().multiplyScalar(-1);
|
||||||
.copy(camera.getWorldDirection(cameraNormal))
|
|
||||||
.multiplyScalar(-1);
|
|
||||||
pushLogs(
|
pushLogs(
|
||||||
shellNormal,
|
shellNormal,
|
||||||
|
cameraNormal,
|
||||||
filterIntersections(event.intersections),
|
filterIntersections(event.intersections),
|
||||||
true,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
console.clear();
|
// console.clear();
|
||||||
console.log(
|
// console.log(
|
||||||
JSON.stringify(
|
// JSON.stringify(
|
||||||
shot.map((i) => ({
|
// shot.map((i) => ({
|
||||||
...i,
|
// ...i,
|
||||||
...(i.angle ? { angle: radToDeg(i.angle) } : {}),
|
// ...(i.angle ? { angle: radToDeg(i.angle) } : {}),
|
||||||
})),
|
// })),
|
||||||
null,
|
// null,
|
||||||
2,
|
// 2,
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
|
|
||||||
function filterIntersections(intersectionsRaw: Intersection[]) {
|
function filterIntersections(intersectionsRaw: Intersection[]) {
|
||||||
const intersectionsAll = intersectionsRaw.filter(
|
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;
|
return intersections;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushLogs(
|
function pushLogs(
|
||||||
shellNormal: Vector3,
|
shellNormal: Vector3,
|
||||||
|
cameraNormal: Vector3,
|
||||||
intersections: ArmorMeshIntersection[],
|
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) {
|
for (const intersection of intersections) {
|
||||||
const surfaceNormal = intersection
|
const surfaceNormal = intersection
|
||||||
.normal!.clone()
|
.normal!.clone()
|
||||||
@@ -184,8 +208,8 @@ export function SpacedArmorSceneComponent({
|
|||||||
const thickness =
|
const thickness =
|
||||||
thicknessCoefficient * intersection.object.userData.thickness;
|
thicknessCoefficient * intersection.object.userData.thickness;
|
||||||
|
|
||||||
if (index !== 0) {
|
if (layerIndex !== 0 && startingIndex === 0) {
|
||||||
const previousIntersection = intersections[index - 1];
|
const previousIntersection = intersections[layerIndex - 1];
|
||||||
shot.push({
|
shot.push({
|
||||||
type: null,
|
type: null,
|
||||||
distance:
|
distance:
|
||||||
@@ -199,7 +223,7 @@ export function SpacedArmorSceneComponent({
|
|||||||
|
|
||||||
shot.push({
|
shot.push({
|
||||||
type: ArmorType.External,
|
type: ArmorType.External,
|
||||||
index,
|
index: layerIndex,
|
||||||
shellNormal,
|
shellNormal,
|
||||||
surfaceNormal,
|
surfaceNormal,
|
||||||
point: intersection.point,
|
point: intersection.point,
|
||||||
@@ -210,19 +234,11 @@ export function SpacedArmorSceneComponent({
|
|||||||
if (blocked) break;
|
if (blocked) break;
|
||||||
} else {
|
} else {
|
||||||
const type = intersection.object.userData.type;
|
const type = intersection.object.userData.type;
|
||||||
shellNormal.copy(
|
|
||||||
cameraNormal
|
|
||||||
.copy(camera.position)
|
|
||||||
.sub(event.point)
|
|
||||||
.normalize(),
|
|
||||||
);
|
|
||||||
const angle = surfaceNormal.angleTo(shellNormal);
|
const angle = surfaceNormal.angleTo(shellNormal);
|
||||||
const ricochet = degToRad(shell.ricochet ?? 90);
|
const ricochet = degToRad(shell.ricochet ?? 90);
|
||||||
const normalization = degToRad(shell.normalization ?? 0);
|
const normalization = degToRad(shell.normalization ?? 0);
|
||||||
const threeCalibersRule =
|
const threeCalibersRule =
|
||||||
shell.caliber > thickness * 3 ||
|
shell.caliber > thickness * 3 || layerIndex > 0;
|
||||||
index > 0 ||
|
|
||||||
!allowRicochets;
|
|
||||||
const twoCalibersRule = shell.caliber > thickness * 2;
|
const twoCalibersRule = shell.caliber > thickness * 2;
|
||||||
const finalNormalization = twoCalibersRule
|
const finalNormalization = twoCalibersRule
|
||||||
? (1.4 * normalization * shell.caliber) / (2.0 * thickness)
|
? (1.4 * normalization * shell.caliber) / (2.0 * thickness)
|
||||||
@@ -234,7 +250,7 @@ export function SpacedArmorSceneComponent({
|
|||||||
if (!threeCalibersRule && angle >= ricochet) {
|
if (!threeCalibersRule && angle >= ricochet) {
|
||||||
shot.push({
|
shot.push({
|
||||||
type,
|
type,
|
||||||
index,
|
index: layerIndex,
|
||||||
shellNormal,
|
shellNormal,
|
||||||
surfaceNormal,
|
surfaceNormal,
|
||||||
point: intersection.point,
|
point: intersection.point,
|
||||||
@@ -245,15 +261,21 @@ export function SpacedArmorSceneComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const raycaster = new Raycaster();
|
const raycaster = new Raycaster();
|
||||||
const newShellNormal = cameraNormal
|
const newShellNormal = shellNormal
|
||||||
.clone()
|
.clone()
|
||||||
.reflect(surfaceNormal);
|
.reflect(surfaceNormal);
|
||||||
|
const newCameraNormal = newShellNormal
|
||||||
|
.clone()
|
||||||
|
.multiplyScalar(-1);
|
||||||
|
|
||||||
raycaster.set(intersection.point, newShellNormal);
|
raycaster.set(intersection.point, newCameraNormal);
|
||||||
pushLogs(
|
pushLogs(
|
||||||
newShellNormal,
|
newShellNormal,
|
||||||
raycaster.intersectObjects(scene.children, true),
|
newCameraNormal,
|
||||||
false,
|
filterIntersections(
|
||||||
|
raycaster.intersectObjects(scene.children, true),
|
||||||
|
),
|
||||||
|
layerIndex + 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -261,7 +283,7 @@ export function SpacedArmorSceneComponent({
|
|||||||
const blocked = remainingPenetration < 0;
|
const blocked = remainingPenetration < 0;
|
||||||
shot.push({
|
shot.push({
|
||||||
type,
|
type,
|
||||||
index,
|
index: layerIndex,
|
||||||
shellNormal,
|
shellNormal,
|
||||||
surfaceNormal,
|
surfaceNormal,
|
||||||
point: intersection.point,
|
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 { DepthTexture, Scene, Vector2 } from 'three';
|
||||||
import { CoreArmorScene } from './components/CoreArmorScene';
|
import { CoreArmorScene } from './components/CoreArmorScene';
|
||||||
import { spacedArmorRenderTarget } from './components/CoreArmorSceneComponent';
|
import { spacedArmorRenderTarget } from './components/CoreArmorSceneComponent';
|
||||||
import { ShotScene } from './components/ShotScene';
|
|
||||||
import { SpacedArmorScene } from './components/SpacedArmorScene';
|
import { SpacedArmorScene } from './components/SpacedArmorScene';
|
||||||
|
|
||||||
export const Armor = memo(() => {
|
export const Armor = memo(() => {
|
||||||
const [spacedArmorScene] = useState(() => new Scene());
|
const [spacedArmorScene] = useState(() => new Scene());
|
||||||
const [coreArmorScene] = useState(() => new Scene());
|
const [coreArmorScene] = useState(() => new Scene());
|
||||||
const [shotScene] = useState(() => new Scene());
|
|
||||||
const spacedArmorPortal = createPortal(
|
const spacedArmorPortal = createPortal(
|
||||||
<SpacedArmorScene scene={spacedArmorScene} />,
|
<SpacedArmorScene scene={spacedArmorScene} />,
|
||||||
spacedArmorScene,
|
spacedArmorScene,
|
||||||
);
|
);
|
||||||
const coreArmorPortal = createPortal(<CoreArmorScene />, coreArmorScene);
|
const coreArmorPortal = createPortal(<CoreArmorScene />, coreArmorScene);
|
||||||
const shotPortal = createPortal(<ShotScene />, shotScene);
|
|
||||||
|
|
||||||
const renderSize = new Vector2();
|
const renderSize = new Vector2();
|
||||||
const newRenderSize = new Vector2();
|
const newRenderSize = new Vector2();
|
||||||
@@ -44,16 +41,12 @@ export const Armor = memo(() => {
|
|||||||
|
|
||||||
gl.clearDepth();
|
gl.clearDepth();
|
||||||
gl.render(coreArmorScene, camera);
|
gl.render(coreArmorScene, camera);
|
||||||
|
|
||||||
gl.clearDepth();
|
|
||||||
gl.render(shotScene, camera);
|
|
||||||
}, 1);
|
}, 1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{spacedArmorPortal}
|
{spacedArmorPortal}
|
||||||
{coreArmorPortal}
|
{coreArmorPortal}
|
||||||
{shotPortal}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user