mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: some more stuff
This commit is contained in:
1 parent
d7e556e136
commit
7a3bdd8f35
7 files changed
+58
-25
No files matched your search
@@ -55,10 +55,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
const hasCustomShell = TankopediaEphemeral.use(
|
const hasCustomShell = TankopediaEphemeral.use(
|
||||||
(state) => state.customShell !== undefined,
|
(state) => state.customShell !== undefined,
|
||||||
);
|
);
|
||||||
const display = TankopediaPersistent.useDeferred(
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
(state) => state.display,
|
|
||||||
TankopediaDisplay.Model,
|
|
||||||
);
|
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
const showGrid = TankopediaPersistent.use((state) => state.showGrid);
|
const showGrid = TankopediaPersistent.use((state) => state.showGrid);
|
||||||
const showEnvironment = TankopediaPersistent.use(
|
const showEnvironment = TankopediaPersistent.use(
|
||||||
@@ -356,7 +353,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
<SegmentedControl.Root
|
<SegmentedControl.Root
|
||||||
value={`${display}`}
|
value={`${display}`}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
mutateTankopediaPersistent((draft) => {
|
mutateTankopediaEphemeral((draft) => {
|
||||||
draft.display = Number(value);
|
draft.display = Number(value);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
+41
-6
@@ -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 { Vector3 } from 'three';
|
import { PerspectiveCamera, Vector3 } from 'three';
|
||||||
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
|
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
|
||||||
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
|
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
|
||||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
@@ -9,6 +9,7 @@ import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
|
|||||||
import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose';
|
import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose';
|
||||||
import { Duel } from '../../../../../../stores/duel';
|
import { Duel } from '../../../../../../stores/duel';
|
||||||
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
|
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
|
||||||
|
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
|
||||||
|
|
||||||
const poseDistances: Record<Pose, number> = {
|
const poseDistances: Record<Pose, number> = {
|
||||||
[Pose.HullDown]: 15,
|
[Pose.HullDown]: 15,
|
||||||
@@ -18,7 +19,14 @@ const poseDistances: Record<Pose, number> = {
|
|||||||
|
|
||||||
const modelDefinitions = await awaitableModelDefinitions;
|
const modelDefinitions = await awaitableModelDefinitions;
|
||||||
|
|
||||||
|
const ARCADE_MODE_DISTANCE = 19;
|
||||||
|
const ARCADE_MODE_ANGLE = Math.PI / 4;
|
||||||
|
|
||||||
|
export const ARCADE_MODE_FOV = 54;
|
||||||
|
export const INSPECT_MODE_FOV = 25;
|
||||||
|
|
||||||
export function Controls() {
|
export function Controls() {
|
||||||
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
const duelStore = Duel.useStore();
|
const duelStore = Duel.useStore();
|
||||||
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
|
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
|
||||||
const camera = useThree((state) => state.camera);
|
const camera = useThree((state) => state.camera);
|
||||||
@@ -62,8 +70,10 @@ export function Controls() {
|
|||||||
protagonistTrackModelDefinition.origin.y +
|
protagonistTrackModelDefinition.origin.y +
|
||||||
antagonistModelDefinition.turret_origin.y +
|
antagonistModelDefinition.turret_origin.y +
|
||||||
antagonistTurretModelDefinition.gun_origin.y;
|
antagonistTurretModelDefinition.gun_origin.y;
|
||||||
const [autoRotate, setAutoRotate] = useState(true);
|
const [autoRotate, setAutoRotate] = useState(
|
||||||
const initialPosition = [
|
display !== TankopediaDisplay.ShootingRange,
|
||||||
|
);
|
||||||
|
let initialPosition = [
|
||||||
-8,
|
-8,
|
||||||
protagonistHullOrigin.y +
|
protagonistHullOrigin.y +
|
||||||
protagonistTurretOrigin.y +
|
protagonistTurretOrigin.y +
|
||||||
@@ -72,9 +82,27 @@ export function Controls() {
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
camera.position.set(...initialPosition);
|
if (display === TankopediaDisplay.ShootingRange) {
|
||||||
orbitControls.current?.target.set(0, initialPosition[1] / 2, 0);
|
(camera as PerspectiveCamera).fov = ARCADE_MODE_FOV;
|
||||||
}, [camera, protagonistTrack, protagonistTank]);
|
camera.position.set(
|
||||||
|
0,
|
||||||
|
initialPosition[1] + ARCADE_MODE_DISTANCE * Math.sin(ARCADE_MODE_ANGLE),
|
||||||
|
ARCADE_MODE_DISTANCE * Math.cos(ARCADE_MODE_ANGLE),
|
||||||
|
);
|
||||||
|
orbitControls.current?.target.set(0, initialPosition[1], 0);
|
||||||
|
} else {
|
||||||
|
(camera as PerspectiveCamera).fov = INSPECT_MODE_FOV;
|
||||||
|
camera.position.set(...initialPosition);
|
||||||
|
orbitControls.current?.target.set(0, initialPosition[1] / 2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
}, [
|
||||||
|
camera,
|
||||||
|
protagonistTrack,
|
||||||
|
protagonistTank,
|
||||||
|
display === TankopediaDisplay.ShootingRange,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe(
|
const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe(
|
||||||
@@ -187,13 +215,20 @@ export function Controls() {
|
|||||||
|
|
||||||
poseEvent.on(handleDisturbance);
|
poseEvent.on(handleDisturbance);
|
||||||
canvas.addEventListener('pointerdown', handleDisturbance);
|
canvas.addEventListener('pointerdown', handleDisturbance);
|
||||||
|
const unsubscribeTankopediaPersistent = tankopediaEphemeralStore.subscribe(
|
||||||
|
(state) => state.display,
|
||||||
|
handleDisturbance,
|
||||||
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
canvas.removeEventListener('pointerdown', handleDisturbance);
|
canvas.removeEventListener('pointerdown', handleDisturbance);
|
||||||
poseEvent.off(handleDisturbance);
|
poseEvent.off(handleDisturbance);
|
||||||
|
unsubscribeTankopediaPersistent();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {}, [display]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OrbitControls
|
<OrbitControls
|
||||||
maxDistance={20}
|
maxDistance={20}
|
||||||
|
|||||||
+2
-1
@@ -1,12 +1,13 @@
|
|||||||
import { Environment } from '@react-three/drei';
|
import { Environment } from '@react-three/drei';
|
||||||
import { useModel } from '../../../../../../hooks/useModel';
|
import { useModel } from '../../../../../../hooks/useModel';
|
||||||
import { Duel } from '../../../../../../stores/duel';
|
import { Duel } from '../../../../../../stores/duel';
|
||||||
|
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
|
||||||
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
|
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
|
||||||
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
|
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
|
||||||
|
|
||||||
export function Lighting() {
|
export function Lighting() {
|
||||||
const protagonist = Duel.use((state) => state.protagonist);
|
const protagonist = Duel.use((state) => state.protagonist);
|
||||||
const display = TankopediaPersistent.use((state) => state.display);
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
const { hasPbr } = useModel(protagonist.tank.id);
|
const { hasPbr } = useModel(protagonist.tank.id);
|
||||||
const isBrighterLighting =
|
const isBrighterLighting =
|
||||||
!hasPbr && display !== TankopediaDisplay.StaticArmor;
|
!hasPbr && display !== TankopediaDisplay.StaticArmor;
|
||||||
|
|||||||
+2
-3
@@ -11,7 +11,6 @@ import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefi
|
|||||||
import { useTankTransform } from '../../../../../../hooks/useTankTransform';
|
import { useTankTransform } from '../../../../../../hooks/useTankTransform';
|
||||||
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 { ModelTankWrapper } from '../../../../../Armor/components/ModelTankWrapper';
|
import { ModelTankWrapper } from '../../../../../Armor/components/ModelTankWrapper';
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ export const TankModel = memo(() => {
|
|||||||
const mutateDuel = Duel.useMutation();
|
const mutateDuel = Duel.useMutation();
|
||||||
const duelStore = Duel.useStore();
|
const duelStore = Duel.useStore();
|
||||||
const protagonist = Duel.use((draft) => draft.protagonist);
|
const protagonist = Duel.use((draft) => draft.protagonist);
|
||||||
const tankopediaPersistentStore = TankopediaPersistent.useStore();
|
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
|
||||||
const track = Duel.use((state) => state.protagonist.track);
|
const track = Duel.use((state) => state.protagonist.track);
|
||||||
const turret = Duel.use((state) => state.protagonist.turret);
|
const turret = Duel.use((state) => state.protagonist.turret);
|
||||||
const canvas = useThree((state) => state.gl.domElement);
|
const canvas = useThree((state) => state.gl.domElement);
|
||||||
@@ -67,7 +66,7 @@ export const TankModel = memo(() => {
|
|||||||
function onPointerDown(event: ThreeEvent<PointerEvent>) {
|
function onPointerDown(event: ThreeEvent<PointerEvent>) {
|
||||||
if (
|
if (
|
||||||
isTrack &&
|
isTrack &&
|
||||||
tankopediaPersistentStore.getState().display ===
|
tankopediaEphemeralStore.getState().display ===
|
||||||
TankopediaDisplay.Model
|
TankopediaDisplay.Model
|
||||||
) {
|
) {
|
||||||
position.set(event.clientX, event.clientY);
|
position.set(event.clientX, event.clientY);
|
||||||
|
|||||||
+7
-6
@@ -24,7 +24,7 @@ import {
|
|||||||
type ThicknessRange,
|
type ThicknessRange,
|
||||||
} from '../../../../Armor/components/StaticArmor';
|
} from '../../../../Armor/components/StaticArmor';
|
||||||
import { AutoClear } from './components/AutoClear';
|
import { AutoClear } from './components/AutoClear';
|
||||||
import { Controls } from './components/Control';
|
import { Controls, INSPECT_MODE_FOV } from './components/Control';
|
||||||
import { Lighting } from './components/Lighting';
|
import { Lighting } from './components/Lighting';
|
||||||
import { ModelLoader } from './components/ModelLoader';
|
import { ModelLoader } from './components/ModelLoader';
|
||||||
import { SceneProps } from './components/SceneProps';
|
import { SceneProps } from './components/SceneProps';
|
||||||
@@ -46,10 +46,8 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
|||||||
tankModelDefinition.turrets[protagonist.turret.id];
|
tankModelDefinition.turrets[protagonist.turret.id];
|
||||||
const gunModelDefinition =
|
const gunModelDefinition =
|
||||||
turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id];
|
turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id];
|
||||||
const display = TankopediaPersistent.useDeferred(
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
(state) => state.display,
|
const tankopediaPersistentStore = TankopediaPersistent.useStore();
|
||||||
TankopediaDisplay.Model,
|
|
||||||
);
|
|
||||||
const onScreen = useOnScreen(canvas);
|
const onScreen = useOnScreen(canvas);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => canvas.current!, []);
|
useImperativeHandle(ref, () => canvas.current!, []);
|
||||||
@@ -177,7 +175,10 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
style={{ userSelect: 'none' }}
|
style={{ userSelect: 'none' }}
|
||||||
camera={{ fov: 25, far: 32 }}
|
camera={{
|
||||||
|
fov: INSPECT_MODE_FOV,
|
||||||
|
far: 32,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
<SceneProps />
|
<SceneProps />
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type { ExternalModuleVariant } from '../components/Armor/components/Space
|
|||||||
import type { XP_MULTIPLIERS } from '../components/Tankopedia/TechTreeSection';
|
import type { XP_MULTIPLIERS } from '../components/Tankopedia/TechTreeSection';
|
||||||
import { awaitableSkillDefinitions } from '../core/awaitables/skillDefinitions';
|
import { awaitableSkillDefinitions } from '../core/awaitables/skillDefinitions';
|
||||||
import { createContextualStore } from '../core/zustand/createContextualStore';
|
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||||
|
import { TankopediaDisplay } from './tankopediaPersistent/constants';
|
||||||
|
|
||||||
export interface ShotLayerBase {
|
export interface ShotLayerBase {
|
||||||
index: number;
|
index: number;
|
||||||
@@ -100,6 +101,7 @@ interface TankopediaEphemeral {
|
|||||||
);
|
);
|
||||||
xpMultiplier: (typeof XP_MULTIPLIERS)[number];
|
xpMultiplier: (typeof XP_MULTIPLIERS)[number];
|
||||||
customShell?: ShellDefinition;
|
customShell?: ShellDefinition;
|
||||||
|
display: TankopediaDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
const skillDefinitions = await awaitableSkillDefinitions;
|
const skillDefinitions = await awaitableSkillDefinitions;
|
||||||
@@ -114,6 +116,7 @@ export const TankopediaEphemeral = createContextualStore(
|
|||||||
model,
|
model,
|
||||||
controlsEnabled: true,
|
controlsEnabled: true,
|
||||||
xpMultiplier: 1,
|
xpMultiplier: 1,
|
||||||
|
display: TankopediaDisplay.Model,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { create } from 'zustand';
|
|||||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { ENVIRONMENTS } from '../../constants/lightingEnvironments';
|
import { ENVIRONMENTS } from '../../constants/lightingEnvironments';
|
||||||
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
import { SORT_NAMES, TankopediaDisplay } from './constants';
|
import { SORT_NAMES } from './constants';
|
||||||
|
|
||||||
export type TankopediaSortBy = keyof typeof SORT_NAMES;
|
export type TankopediaSortBy = keyof typeof SORT_NAMES;
|
||||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||||
@@ -25,8 +25,6 @@ export interface TankopediaPersistentStore {
|
|||||||
by: TankopediaSortBy;
|
by: TankopediaSortBy;
|
||||||
direction: TankopediaSortDirection;
|
direction: TankopediaSortDirection;
|
||||||
};
|
};
|
||||||
|
|
||||||
display: TankopediaDisplay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TankopediaPersistent = createContextualStore(() =>
|
export const TankopediaPersistent = createContextualStore(() =>
|
||||||
@@ -47,7 +45,6 @@ export const TankopediaPersistent = createContextualStore(() =>
|
|||||||
by: 'meta.none',
|
by: 'meta.none',
|
||||||
direction: 'ascending',
|
direction: 'ascending',
|
||||||
},
|
},
|
||||||
display: TankopediaDisplay.Model,
|
|
||||||
})),
|
})),
|
||||||
{ name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) },
|
{ name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) },
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in new issue
Block a user