mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: physical aiming
This commit is contained in:
1 parent
3d6d18267d
commit
c039862c56
1 file changed
+64
-13
+64
-13
@@ -1,3 +1,4 @@
|
|||||||
|
import { I_HAT, J_HAT } from '@blitzkit/core';
|
||||||
import { useFrame, useLoader } from '@react-three/fiber';
|
import { useFrame, useLoader } from '@react-three/fiber';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
@@ -20,12 +21,14 @@ import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent
|
|||||||
|
|
||||||
const emptyVector = new Vector2();
|
const emptyVector = new Vector2();
|
||||||
const modelDefinitions = await awaitableModelDefinitions;
|
const modelDefinitions = await awaitableModelDefinitions;
|
||||||
|
const FAR_DISTANCE = 1000;
|
||||||
|
|
||||||
export function SceneProps() {
|
export function SceneProps() {
|
||||||
const shellPathHelper = useRef<ArrowHelper>(null);
|
const shellPathHelper = useRef<ArrowHelper>(null);
|
||||||
const show = TankopediaPersistent.use(
|
const show = TankopediaPersistent.use(
|
||||||
(state) => state.showGrid && !state.showEnvironment,
|
(state) => state.showGrid && !state.showEnvironment,
|
||||||
);
|
);
|
||||||
|
const targetCircle = useRef<Group>(null);
|
||||||
const texture = useLoader(TextureLoader, 'https://i.imgur.com/C28Z8nU.png');
|
const texture = useLoader(TextureLoader, 'https://i.imgur.com/C28Z8nU.png');
|
||||||
|
|
||||||
texture.anisotropy = 2;
|
texture.anisotropy = 2;
|
||||||
@@ -59,11 +62,6 @@ export function SceneProps() {
|
|||||||
protagonistModelDefinition.turret_origin.y,
|
protagonistModelDefinition.turret_origin.y,
|
||||||
-protagonistModelDefinition.turret_origin.z,
|
-protagonistModelDefinition.turret_origin.z,
|
||||||
);
|
);
|
||||||
const protagonistGunOrigin = new Vector3(
|
|
||||||
protagonistTurretModelDefinition.gun_origin.x,
|
|
||||||
protagonistTurretModelDefinition.gun_origin.y,
|
|
||||||
-protagonistTurretModelDefinition.gun_origin.z,
|
|
||||||
);
|
|
||||||
const protagonistGunOriginOnlyY = new Vector3(
|
const protagonistGunOriginOnlyY = new Vector3(
|
||||||
0,
|
0,
|
||||||
protagonistTurretModelDefinition.gun_origin.y,
|
protagonistTurretModelDefinition.gun_origin.y,
|
||||||
@@ -84,19 +82,22 @@ export function SceneProps() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let lastTime = 0;
|
let lastTime = 0;
|
||||||
|
let DEBUG_disable = false;
|
||||||
|
|
||||||
useFrame(({ raycaster, camera, clock }) => {
|
useFrame(({ raycaster, camera, clock }) => {
|
||||||
if (
|
if (
|
||||||
display !== TankopediaDisplay.ShootingRange ||
|
display !== TankopediaDisplay.ShootingRange ||
|
||||||
!playground.current ||
|
!playground.current ||
|
||||||
!shellPathHelper.current
|
!shellPathHelper.current ||
|
||||||
|
!targetCircle.current ||
|
||||||
|
DEBUG_disable
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
raycaster.setFromCamera(emptyVector, camera);
|
raycaster.setFromCamera(emptyVector, camera);
|
||||||
|
|
||||||
const intersections = raycaster.intersectObjects(
|
const cameraIntersections = raycaster.intersectObjects(
|
||||||
playground.current.children,
|
playground.current.children,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
@@ -104,19 +105,18 @@ export function SceneProps() {
|
|||||||
let length: number;
|
let length: number;
|
||||||
let direction: Vector3;
|
let direction: Vector3;
|
||||||
|
|
||||||
if (intersections.length === 0) {
|
if (cameraIntersections.length === 0) {
|
||||||
length = 1000;
|
length = FAR_DISTANCE;
|
||||||
direction = new Vector3(0, 0, -1).applyQuaternion(camera.quaternion);
|
direction = new Vector3(0, 0, -1).applyQuaternion(camera.quaternion);
|
||||||
} else {
|
} else {
|
||||||
const target = intersections[0].point;
|
const target = cameraIntersections[0].point;
|
||||||
const path = target.clone().sub(shellOrigin);
|
const path = target.clone().sub(shellOrigin);
|
||||||
|
|
||||||
length = path.length();
|
length = path.length();
|
||||||
direction = path.clone().normalize();
|
direction = path.clone().normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
shellPathHelper.current.setDirection(direction);
|
// shellPathHelper.current.setDirection(direction);
|
||||||
shellPathHelper.current.setLength(length);
|
// shellPathHelper.current.setLength(length);
|
||||||
|
|
||||||
const deltaT = clock.elapsedTime - lastTime;
|
const deltaT = clock.elapsedTime - lastTime;
|
||||||
lastTime = clock.elapsedTime;
|
lastTime = clock.elapsedTime;
|
||||||
@@ -141,6 +141,38 @@ export function SceneProps() {
|
|||||||
modelTransformEvent.emit({ pitch, yaw });
|
modelTransformEvent.emit({ pitch, yaw });
|
||||||
lastPitch = pitch;
|
lastPitch = pitch;
|
||||||
lastYaw = yaw;
|
lastYaw = yaw;
|
||||||
|
|
||||||
|
const gunDirection = new Vector3(0, 0, -1)
|
||||||
|
.applyAxisAngle(I_HAT, pitch)
|
||||||
|
.applyAxisAngle(J_HAT, yaw);
|
||||||
|
|
||||||
|
shellPathHelper.current.setLength(FAR_DISTANCE);
|
||||||
|
shellPathHelper.current.setDirection(gunDirection);
|
||||||
|
|
||||||
|
raycaster.set(shellOrigin, gunDirection);
|
||||||
|
|
||||||
|
const gunIntersections = raycaster.intersectObjects(
|
||||||
|
playground.current.children,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
let gunTarget: Vector3;
|
||||||
|
|
||||||
|
if (gunIntersections.length === 0) {
|
||||||
|
gunTarget = shellOrigin
|
||||||
|
.clone()
|
||||||
|
.add(gunDirection.multiplyScalar(FAR_DISTANCE));
|
||||||
|
} else {
|
||||||
|
gunTarget = gunIntersections[0].point;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetCircle.current.position.copy(gunTarget);
|
||||||
|
|
||||||
|
// window.addEventListener('keydown', (event) => {
|
||||||
|
// if (event.key === 'Enter') {
|
||||||
|
// DEBUG_disable = true;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -156,6 +188,25 @@ export function SceneProps() {
|
|||||||
<>
|
<>
|
||||||
<arrowHelper ref={shellPathHelper} position={shellOrigin} />
|
<arrowHelper ref={shellPathHelper} position={shellOrigin} />
|
||||||
|
|
||||||
|
<group ref={targetCircle}>
|
||||||
|
<mesh renderOrder={1}>
|
||||||
|
<sphereGeometry args={[0.1, 32, 32]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
depthTest={false}
|
||||||
|
depthWrite={false}
|
||||||
|
color="red"
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
{/* <Html center occlude={false}>
|
||||||
|
<Box
|
||||||
|
width="10em"
|
||||||
|
height="10em"
|
||||||
|
style={{ backgroundColor: 'red' }}
|
||||||
|
/>
|
||||||
|
</Html> */}
|
||||||
|
</group>
|
||||||
|
|
||||||
<group ref={playground}>
|
<group ref={playground}>
|
||||||
<mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
|
<mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
|
||||||
<planeGeometry args={[100, 100]} />
|
<planeGeometry args={[100, 100]} />
|
||||||
|
|||||||
Reference in new issue
Block a user