mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-29 21:49:50 +01:00
feat: aiming caster
This commit is contained in:
1 parent
5a34a35638
commit
65c52c2e82
3 files changed
+45
-21
No files matched your search
+39
-15
@@ -1,7 +1,7 @@
|
|||||||
import { OrbitControls } from '@react-three/drei';
|
import { OrbitControls } from '@react-three/drei';
|
||||||
import { invalidate, useThree } from '@react-three/fiber';
|
import { invalidate, useThree } from '@react-three/fiber';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { PerspectiveCamera, Vector3 } from 'three';
|
import { AxesHelper, PerspectiveCamera, Vector2, Vector3 } from 'three';
|
||||||
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
|
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
|
||||||
import { degToRad } from 'three/src/math/MathUtils.js';
|
import { degToRad } from 'three/src/math/MathUtils.js';
|
||||||
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
|
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
|
||||||
@@ -22,11 +22,13 @@ const modelDefinitions = await awaitableModelDefinitions;
|
|||||||
|
|
||||||
const ARCADE_MODE_DISTANCE = 16;
|
const ARCADE_MODE_DISTANCE = 16;
|
||||||
const ARCADE_MODE_ANGLE = Math.PI / 8;
|
const ARCADE_MODE_ANGLE = Math.PI / 8;
|
||||||
|
|
||||||
export const ARCADE_MODE_FOV = 54;
|
export const ARCADE_MODE_FOV = 54;
|
||||||
export const INSPECT_MODE_FOV = 25;
|
export const INSPECT_MODE_FOV = 25;
|
||||||
|
|
||||||
|
const emptyVector = new Vector2();
|
||||||
|
|
||||||
export function Controls() {
|
export function Controls() {
|
||||||
|
const helper = useRef<AxesHelper>(null);
|
||||||
const display = TankopediaEphemeral.use((state) => state.display);
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
const duelStore = Duel.useStore();
|
const duelStore = Duel.useStore();
|
||||||
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
|
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
|
||||||
@@ -79,6 +81,8 @@ export function Controls() {
|
|||||||
protagonistTurretOrigin.y +
|
protagonistTurretOrigin.y +
|
||||||
protagonistGunOrigin.y;
|
protagonistGunOrigin.y;
|
||||||
const initialPosition = [-8, gunHeight + 4, -13] as const;
|
const initialPosition = [-8, gunHeight + 4, -13] as const;
|
||||||
|
const raycaster = useThree((state) => state.raycaster);
|
||||||
|
const scene = useThree((state) => state.scene);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!orbitControls.current) return;
|
if (!orbitControls.current) return;
|
||||||
@@ -232,19 +236,39 @@ export function Controls() {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {}, [display]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OrbitControls
|
<>
|
||||||
maxDistance={20}
|
<axesHelper ref={helper} />
|
||||||
minDistance={5}
|
<OrbitControls
|
||||||
ref={orbitControls}
|
maxDistance={20}
|
||||||
enabled={tankopediaEphemeralStore.getState().controlsEnabled}
|
minDistance={5}
|
||||||
rotateSpeed={0.25}
|
ref={orbitControls}
|
||||||
enableDamping={false}
|
enabled={tankopediaEphemeralStore.getState().controlsEnabled}
|
||||||
maxPolarAngle={degToRad(100)}
|
rotateSpeed={0.25}
|
||||||
autoRotate={autoRotate}
|
enableDamping={false}
|
||||||
autoRotateSpeed={1 / 4}
|
maxPolarAngle={degToRad(100)}
|
||||||
/>
|
autoRotate={autoRotate}
|
||||||
|
autoRotateSpeed={1 / 4}
|
||||||
|
onChange={() => {
|
||||||
|
if (display !== TankopediaDisplay.ShootingRange || !helper.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
raycaster.setFromCamera(emptyVector, camera);
|
||||||
|
|
||||||
|
const intersections = raycaster.intersectObjects(
|
||||||
|
scene.children,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
const first = intersections.find(
|
||||||
|
(intersection) => intersection.object !== helper.current,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (first === undefined) return;
|
||||||
|
|
||||||
|
helper.current.position.copy(first.point);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+1
@@ -34,6 +34,7 @@ export function Lighting() {
|
|||||||
|
|
||||||
{times(LIGHTS_COUNT, (index) => (
|
{times(LIGHTS_COUNT, (index) => (
|
||||||
<directionalLight
|
<directionalLight
|
||||||
|
key={index}
|
||||||
castShadow
|
castShadow
|
||||||
position={[
|
position={[
|
||||||
Math.sin(2 * Math.PI * (index / LIGHTS_COUNT)),
|
Math.sin(2 * Math.PI * (index / LIGHTS_COUNT)),
|
||||||
|
|||||||
+5
-6
@@ -14,7 +14,6 @@ import { useOnScreen } from '../../../../../hooks/useOnScreen';
|
|||||||
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
|
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
|
||||||
import { Duel } from '../../../../../stores/duel';
|
import { Duel } from '../../../../../stores/duel';
|
||||||
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
||||||
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
|
||||||
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
|
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
|
||||||
import { Armor } from '../../../../Armor';
|
import { Armor } from '../../../../Armor';
|
||||||
import { ArmorPlateDisplay } from '../../../../Armor/components/ArmorPlateDisplay';
|
import { ArmorPlateDisplay } from '../../../../Armor/components/ArmorPlateDisplay';
|
||||||
@@ -39,15 +38,15 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
|||||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||||
const canvas = useRef<HTMLCanvasElement>(null);
|
const canvas = useRef<HTMLCanvasElement>(null);
|
||||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||||
const protagonist = Duel.use((state) => state.protagonist);
|
const protagonistGun = Duel.use((state) => state.protagonist.gun);
|
||||||
|
const protagonistTurret = Duel.use((state) => state.protagonist.turret);
|
||||||
const mutateDuel = Duel.useMutation();
|
const mutateDuel = Duel.useMutation();
|
||||||
const tankModelDefinition = useTankModelDefinition();
|
const tankModelDefinition = useTankModelDefinition();
|
||||||
const turretModelDefinition =
|
const turretModelDefinition =
|
||||||
tankModelDefinition.turrets[protagonist.turret.id];
|
tankModelDefinition.turrets[protagonistTurret.id];
|
||||||
const gunModelDefinition =
|
const gunModelDefinition =
|
||||||
turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id];
|
turretModelDefinition.guns[protagonistGun.gun_type!.value.base.id];
|
||||||
const display = TankopediaEphemeral.use((state) => state.display);
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
const tankopediaPersistentStore = TankopediaPersistent.useStore();
|
|
||||||
const onScreen = useOnScreen(canvas);
|
const onScreen = useOnScreen(canvas);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => canvas.current!, []);
|
useImperativeHandle(ref, () => canvas.current!, []);
|
||||||
@@ -141,7 +140,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
|||||||
hasImprovedVerticalStabilizer,
|
hasImprovedVerticalStabilizer,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, [protagonist.gun, protagonist.turret]);
|
}, [protagonistGun, protagonistTurret]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (display !== TankopediaDisplay.DynamicArmor) {
|
if (display !== TankopediaDisplay.DynamicArmor) {
|
||||||
|
|||||||
Reference in new issue
Block a user