mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: dragger
This commit is contained in:
1 parent
dcd7ce61f7
commit
5982fdde8c
4 files changed
+283
-186
No files matched your search
@@ -1,4 +1,16 @@
|
||||
import { asset } from '@blitzkit/core';
|
||||
import { asset, J_HAT } from '@blitzkit/core';
|
||||
import {
|
||||
amberDark,
|
||||
blueDark,
|
||||
bronzeDark,
|
||||
indigoDark,
|
||||
mauveDark,
|
||||
orangeDark,
|
||||
plumDark,
|
||||
redDark,
|
||||
skyDark,
|
||||
slateDark,
|
||||
} from '@radix-ui/colors';
|
||||
import {
|
||||
Base,
|
||||
Geometry,
|
||||
@@ -15,6 +27,7 @@ import {
|
||||
LineBasicMaterial,
|
||||
Material,
|
||||
MeshStandardMaterial,
|
||||
Plane,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
import {
|
||||
@@ -33,28 +46,28 @@ interface DissectorSceneComponentProps {
|
||||
|
||||
const NEGATIVE_SIZE = 20;
|
||||
|
||||
const armorColor = new Color().multiplyScalar(2 ** -8);
|
||||
const armorColor = new Color().multiplyScalar(2 ** -4);
|
||||
const armorOutlineColor = armorColor.clone().multiplyScalar(2 ** 4.5);
|
||||
|
||||
const moduleColor: Record<string, Color> = {
|
||||
Armor: armorColor,
|
||||
ArmorScreen: armorColor,
|
||||
|
||||
Commander: new Color('white'),
|
||||
Driver: new Color('white'),
|
||||
Gunner1: new Color('white'),
|
||||
Loader1: new Color('white'),
|
||||
Commander: new Color(mauveDark.mauve11),
|
||||
Driver: new Color(mauveDark.mauve11),
|
||||
Gunner1: new Color(mauveDark.mauve11),
|
||||
Loader1: new Color(mauveDark.mauve11),
|
||||
|
||||
SurveyingDevice: new Color('purple'),
|
||||
Radio: new Color('indigo'),
|
||||
Gun: new Color('pink'),
|
||||
FuelTank: new Color('yellow'),
|
||||
Engine: new Color('orange'),
|
||||
AmmoBay: new Color('gold'),
|
||||
LeftTrack: new Color('green'),
|
||||
RightTrack: new Color('green'),
|
||||
TurretRotator: new Color('blue'),
|
||||
Transmission: new Color('cyan'),
|
||||
SurveyingDevice: new Color(plumDark.plum8),
|
||||
Radio: new Color(slateDark.slate8),
|
||||
Gun: new Color(blueDark.blue8),
|
||||
FuelTank: new Color(orangeDark.orange8),
|
||||
Engine: new Color(redDark.red8),
|
||||
AmmoBay: new Color(amberDark.amber8),
|
||||
LeftTrack: new Color(bronzeDark.bronze8),
|
||||
RightTrack: new Color(bronzeDark.bronze8),
|
||||
TurretRotator: new Color(indigoDark.indigo8),
|
||||
Transmission: new Color(skyDark.sky8),
|
||||
};
|
||||
const moduleOutlineColor: Record<string, Color> = {
|
||||
Armor: armorOutlineColor,
|
||||
@@ -87,27 +100,56 @@ export function DissectorSceneComponent({
|
||||
|
||||
const armorName = mesh.material.name;
|
||||
const armorPlate = groupArmor.armors[armorName];
|
||||
|
||||
if (armorPlate.type === 'Armor' || armorPlate.type === 'ArmorScreen') {
|
||||
return null;
|
||||
}
|
||||
const isModule =
|
||||
armorPlate.type !== 'Armor' && armorPlate.type !== 'ArmorScreen';
|
||||
const isTrack =
|
||||
armorPlate.type === 'LeftTrack' || armorPlate.type === 'RightTrack';
|
||||
|
||||
if (!(armorPlate.type in moduleColor)) {
|
||||
throw new TypeError(`Unhandled armor type: ${armorPlate.type}`);
|
||||
}
|
||||
|
||||
const material = new MeshStandardMaterial({
|
||||
side: DoubleSide,
|
||||
color: moduleColor[armorPlate.type],
|
||||
});
|
||||
const outlineMaterial = new LineBasicMaterial({
|
||||
side: DoubleSide,
|
||||
color: moduleOutlineColor[armorPlate.type],
|
||||
});
|
||||
const clippingPlane = useRef(new Plane());
|
||||
const clippingPlaneInverse = useRef(new Plane());
|
||||
const material = useRef(
|
||||
new MeshStandardMaterial({
|
||||
transparent: isTrack,
|
||||
opacity: 2 ** -1,
|
||||
side: DoubleSide,
|
||||
color: moduleColor[armorPlate.type],
|
||||
clippingPlanes: isModule ? undefined : [clippingPlane.current],
|
||||
}),
|
||||
);
|
||||
const outlineMaterial = useRef(
|
||||
new LineBasicMaterial({
|
||||
transparent: !isModule,
|
||||
opacity: 2 ** -3,
|
||||
side: DoubleSide,
|
||||
color: moduleOutlineColor[armorPlate.type],
|
||||
clippingPlanes: isModule ? undefined : [clippingPlane.current],
|
||||
}),
|
||||
);
|
||||
const outlineMaterialInverse = useRef(
|
||||
new LineBasicMaterial({
|
||||
transparent: !isModule,
|
||||
opacity: 2 ** -6,
|
||||
side: DoubleSide,
|
||||
color: moduleOutlineColor[armorPlate.type],
|
||||
clippingPlanes: isModule ? undefined : [clippingPlaneInverse.current],
|
||||
}),
|
||||
);
|
||||
const worldPosition = new Vector3();
|
||||
|
||||
useEffect(() => {
|
||||
const offset = new Vector3();
|
||||
|
||||
function handleDissectEvent(event: DissectEventData) {
|
||||
clippingPlane.current.normal
|
||||
.set(0, 0, 1)
|
||||
.applyAxisAngle(J_HAT, event.rotation - Math.PI / 2);
|
||||
clippingPlane.current.constant = event.offset;
|
||||
clippingPlaneInverse.current.copy(clippingPlane.current).negate();
|
||||
|
||||
if (
|
||||
!subtractionWrapper.current ||
|
||||
!csg.current ||
|
||||
@@ -116,9 +158,10 @@ export function DissectorSceneComponent({
|
||||
return;
|
||||
|
||||
baseWrapper.current.getWorldPosition(worldPosition);
|
||||
|
||||
offset.set(-event.offset, 0, 0).applyAxisAngle(J_HAT, event.rotation);
|
||||
subtractionWrapper.current.position
|
||||
.copy(worldPosition)
|
||||
.add(offset)
|
||||
.multiplyScalar(-1);
|
||||
subtractionWrapper.current.rotation.y = event.rotation;
|
||||
csg.current.update();
|
||||
@@ -132,13 +175,11 @@ export function DissectorSceneComponent({
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <mesh {...props} material={material} /> */}
|
||||
|
||||
<mesh material={material} ref={baseWrapper}>
|
||||
if (isModule) {
|
||||
return (
|
||||
<mesh material={material.current} ref={baseWrapper}>
|
||||
<Geometry ref={csg}>
|
||||
<Base geometry={props.geometry}></Base>
|
||||
<Base geometry={props.geometry} />
|
||||
|
||||
<group rotation={[0, 0, 0]} ref={subtractionWrapper}>
|
||||
<Subtraction position={[NEGATIVE_SIZE / 2, 0, 0]}>
|
||||
@@ -149,10 +190,17 @@ export function DissectorSceneComponent({
|
||||
</group>
|
||||
</Geometry>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
{/* <lineSegments material={outlineMaterial}>
|
||||
return (
|
||||
<>
|
||||
<lineSegments material={outlineMaterial.current}>
|
||||
<edgesGeometry args={[props.geometry, 45]} />
|
||||
</lineSegments> */}
|
||||
</lineSegments>
|
||||
<lineSegments material={outlineMaterialInverse.current}>
|
||||
<edgesGeometry args={[props.geometry, 45]} />
|
||||
</lineSegments>
|
||||
</>
|
||||
);
|
||||
},
|
||||
|
||||
+105
-101
@@ -85,9 +85,9 @@ export function Controls({ naked }: ControlsProps) {
|
||||
// protagonistGunOrigin.y;
|
||||
const gunHeight = 2;
|
||||
const inspectModeInitialPosition = [
|
||||
-8,
|
||||
13,
|
||||
gunHeight + (naked ? 10 : 4),
|
||||
-13,
|
||||
-8,
|
||||
] as const;
|
||||
// const protagonistGunOriginOnlyY = new Vector3(
|
||||
// 0,
|
||||
@@ -99,116 +99,120 @@ export function Controls({ naked }: ControlsProps) {
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOriginOnlyY);
|
||||
|
||||
// useEffect(() => {
|
||||
// const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe(
|
||||
// (state) => state.controlsEnabled,
|
||||
// (enabled) => {
|
||||
// if (orbitControls.current) orbitControls.current.enabled = enabled;
|
||||
// },
|
||||
// );
|
||||
useEffect(() => {
|
||||
const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe(
|
||||
(state) => state.controlsEnabled,
|
||||
(enabled) => {
|
||||
if (orbitControls.current) orbitControls.current.enabled = enabled;
|
||||
},
|
||||
);
|
||||
|
||||
// async function handlePoseEvent(event: Pose) {
|
||||
// const duel = duelStore.getState();
|
||||
// const hasImprovedVerticalStabilizer = await hasEquipment(
|
||||
// 122,
|
||||
// duel.protagonist.tank.equipment_preset,
|
||||
// duel.protagonist.equipmentMatrix,
|
||||
// );
|
||||
// const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
// 124,
|
||||
// duel.protagonist.tank.equipment_preset,
|
||||
// duel.protagonist.equipmentMatrix,
|
||||
// );
|
||||
// async function handlePoseEvent(event: Pose) {
|
||||
// const duel = duelStore.getState();
|
||||
// const hasImprovedVerticalStabilizer = await hasEquipment(
|
||||
// 122,
|
||||
// duel.protagonist.tank.equipment_preset,
|
||||
// duel.protagonist.equipmentMatrix,
|
||||
// );
|
||||
// const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
// 124,
|
||||
// duel.protagonist.tank.equipment_preset,
|
||||
// duel.protagonist.equipmentMatrix,
|
||||
// );
|
||||
|
||||
// switch (event) {
|
||||
// case Pose.HullDown: {
|
||||
// const [pitch] = applyPitchYawLimits(
|
||||
// -Infinity,
|
||||
// 0,
|
||||
// protagonistGunModelDefinition.pitch,
|
||||
// protagonistTurretModelDefinition.yaw,
|
||||
// hasImprovedVerticalStabilizer,
|
||||
// hasDownImprovedVerticalStabilizer,
|
||||
// );
|
||||
// switch (event) {
|
||||
// case Pose.HullDown: {
|
||||
// const [pitch] = applyPitchYawLimits(
|
||||
// -Infinity,
|
||||
// 0,
|
||||
// protagonistGunModelDefinition.pitch,
|
||||
// protagonistTurretModelDefinition.yaw,
|
||||
// hasImprovedVerticalStabilizer,
|
||||
// hasDownImprovedVerticalStabilizer,
|
||||
// );
|
||||
|
||||
// camera.position
|
||||
// .set(0, 0, 0)
|
||||
// .add(protagonistHullOrigin)
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin)
|
||||
// .add(
|
||||
// new Vector3(
|
||||
// 0,
|
||||
// poseDistances[event] * Math.sin(pitch),
|
||||
// poseDistances[event] * -Math.cos(pitch),
|
||||
// ),
|
||||
// );
|
||||
// camera.lookAt(
|
||||
// protagonistHullOrigin
|
||||
// .clone()
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin),
|
||||
// );
|
||||
// orbitControls.current?.target.set(0, antagonistGunHeight, 0);
|
||||
// camera.position
|
||||
// .set(0, 0, 0)
|
||||
// .add(protagonistHullOrigin)
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin)
|
||||
// .add(
|
||||
// new Vector3(
|
||||
// 0,
|
||||
// poseDistances[event] * Math.sin(pitch),
|
||||
// poseDistances[event] * -Math.cos(pitch),
|
||||
// ),
|
||||
// );
|
||||
// camera.lookAt(
|
||||
// protagonistHullOrigin
|
||||
// .clone()
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin),
|
||||
// );
|
||||
// orbitControls.current?.target.set(0, antagonistGunHeight, 0);
|
||||
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case Pose.FaceHug: {
|
||||
// const [pitch] = applyPitchYawLimits(
|
||||
// 0,
|
||||
// 0,
|
||||
// protagonistGunModelDefinition.pitch,
|
||||
// protagonistTurretModelDefinition.yaw,
|
||||
// hasImprovedVerticalStabilizer,
|
||||
// hasDownImprovedVerticalStabilizer,
|
||||
// );
|
||||
// case Pose.FaceHug: {
|
||||
// const [pitch] = applyPitchYawLimits(
|
||||
// 0,
|
||||
// 0,
|
||||
// protagonistGunModelDefinition.pitch,
|
||||
// protagonistTurretModelDefinition.yaw,
|
||||
// hasImprovedVerticalStabilizer,
|
||||
// hasDownImprovedVerticalStabilizer,
|
||||
// );
|
||||
|
||||
// camera.position
|
||||
// .set(0, 0, 0)
|
||||
// .add(protagonistHullOrigin)
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin)
|
||||
// .add(
|
||||
// new Vector3(
|
||||
// 0,
|
||||
// poseDistances[event] * Math.sin(pitch),
|
||||
// poseDistances[event] * -Math.cos(pitch),
|
||||
// ),
|
||||
// );
|
||||
// orbitControls.current?.target
|
||||
// .set(0, 0, 0)
|
||||
// .add(protagonistHullOrigin)
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin)
|
||||
// .add(
|
||||
// new Vector3(
|
||||
// 0,
|
||||
// 0.5 * poseDistances[event] * Math.sin(pitch),
|
||||
// 0.5 * poseDistances[event] * -Math.cos(pitch),
|
||||
// ),
|
||||
// );
|
||||
// camera.position
|
||||
// .set(0, 0, 0)
|
||||
// .add(protagonistHullOrigin)
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin)
|
||||
// .add(
|
||||
// new Vector3(
|
||||
// 0,
|
||||
// poseDistances[event] * Math.sin(pitch),
|
||||
// poseDistances[event] * -Math.cos(pitch),
|
||||
// ),
|
||||
// );
|
||||
// orbitControls.current?.target
|
||||
// .set(0, 0, 0)
|
||||
// .add(protagonistHullOrigin)
|
||||
// .add(protagonistTurretOrigin)
|
||||
// .add(protagonistGunOrigin)
|
||||
// .add(
|
||||
// new Vector3(
|
||||
// 0,
|
||||
// 0.5 * poseDistances[event] * Math.sin(pitch),
|
||||
// 0.5 * poseDistances[event] * -Math.cos(pitch),
|
||||
// ),
|
||||
// );
|
||||
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case Pose.Default: {
|
||||
// camera.position.set(...inspectModeInitialPosition);
|
||||
// orbitControls.current?.target.set(0, 1.25, 0);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// case Pose.Default: {
|
||||
// camera.position.set(...inspectModeInitialPosition);
|
||||
// orbitControls.current?.target.set(0, 1.25, 0);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// invalidate();
|
||||
// }
|
||||
// invalidate();
|
||||
// }
|
||||
|
||||
// poseEvent.on(handlePoseEvent);
|
||||
// poseEvent.on(handlePoseEvent);
|
||||
|
||||
// return () => {
|
||||
// unsubscribeTankopediaEphemeral();
|
||||
// poseEvent.off(handlePoseEvent);
|
||||
// };
|
||||
// }, [camera, protagonistTank.id, antagonistTank.id]);
|
||||
return () => {
|
||||
unsubscribeTankopediaEphemeral();
|
||||
// poseEvent.off(handlePoseEvent);
|
||||
};
|
||||
}, [
|
||||
camera,
|
||||
// protagonistTank.id,
|
||||
// antagonistTank.id
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
let isInitialIteration = true;
|
||||
|
||||
+89
-47
@@ -1,33 +1,32 @@
|
||||
import { imgur } from '@blitzkit/core';
|
||||
import { useFrame, useLoader } from '@react-three/fiber';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { MeshStandardMaterial, TextureLoader, Vector2 } from 'three';
|
||||
import { awaitableEquipmentDefinitions } from '../../../../../../../core/awaitables/equipmentDefinitions';
|
||||
import { awaitableModelDefinitions } from '../../../../../../../core/awaitables/modelDefinitions';
|
||||
import { awaitableProvisionDefinitions } from '../../../../../../../core/awaitables/provisionDefinitions';
|
||||
import { imgur, J_HAT } from '@blitzkit/core';
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { Group, Plane, TextureLoader, Vector2 } from 'three';
|
||||
import { clamp } from 'three/src/math/MathUtils.js';
|
||||
import {
|
||||
dissectEvent,
|
||||
lastDissection,
|
||||
type DissectEventData,
|
||||
} from '../../../../../../../core/blitzkit/dissect';
|
||||
import { TankopediaEphemeral } from '../../../../../../../stores/tankopediaEphemeral';
|
||||
import { TankopediaDisplay } from '../../../../../../../stores/tankopediaPersistent/constants';
|
||||
|
||||
const [modelDefinitions, equipmentDefinitions, provisionDefinitions] =
|
||||
await Promise.all([
|
||||
awaitableModelDefinitions,
|
||||
awaitableEquipmentDefinitions,
|
||||
awaitableProvisionDefinitions,
|
||||
]);
|
||||
// const [modelDefinitions, equipmentDefinitions, provisionDefinitions] =
|
||||
// await Promise.all([
|
||||
// awaitableModelDefinitions,
|
||||
// awaitableEquipmentDefinitions,
|
||||
// awaitableProvisionDefinitions,
|
||||
// ]);
|
||||
|
||||
const emptyVector = new Vector2();
|
||||
// const emptyVector = new Vector2();
|
||||
|
||||
const GRID_SIZE = 10;
|
||||
|
||||
export function SceneProps() {
|
||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||
// const targetCircleWrapper = useRef<Group>(null);
|
||||
// const clientTargetCircle = useRef<HTMLDivElement>(null);
|
||||
// const serverTargetCircle = useRef<HTMLDivElement>(null);
|
||||
const material = useRef<MeshStandardMaterial>(null);
|
||||
// const playground = useRef<Group>(null);
|
||||
|
||||
// let lastPitch = Duel.use((state) => state.protagonist.pitch);
|
||||
@@ -90,19 +89,12 @@ export function SceneProps() {
|
||||
// let { dispersion } = characteristics;
|
||||
// const gunRotationSpeed = degToRad(characteristics.gunTraverseSpeed);
|
||||
// const mockTank = useLoader(GLTFLoader, asset(`3d/tanks/models/6929.glb`));
|
||||
const texture = useLoader(
|
||||
TextureLoader,
|
||||
imgur(display === TankopediaDisplay.Dissector ? 'GgYPSVA' : 'C28Z8nU'),
|
||||
);
|
||||
texture.anisotropy = 2;
|
||||
const gridTexture = useLoader(TextureLoader, imgur('iq0iOCJ'));
|
||||
const dragTexture = useLoader(TextureLoader, imgur('Vi3xXsb'));
|
||||
gridTexture.anisotropy = 2;
|
||||
// const path = new Vector3();
|
||||
// const direction = new Vector3();
|
||||
|
||||
useFrame(({ camera }) => {
|
||||
if (!material.current) return;
|
||||
material.current.opacity = clamp(0.5 * camera.position.y, 0, 1);
|
||||
});
|
||||
|
||||
// let lastTime = 0;
|
||||
// let DEBUG_disable = false;
|
||||
|
||||
@@ -225,15 +217,23 @@ export function SceneProps() {
|
||||
// serverTargetCircle.current.style.height = targetCircleDotsSize;
|
||||
// });
|
||||
|
||||
const position = new Vector2();
|
||||
const delta = new Vector2();
|
||||
const dissector = useRef<Group>(null);
|
||||
const position = useRef(new Vector2());
|
||||
const delta = useRef(new Vector2());
|
||||
const clippingPlane = useRef(new Plane());
|
||||
const handlePointerMove = useCallback((event: PointerEvent) => {
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
delta.current.set(event.clientX, event.clientY).sub(position.current);
|
||||
position.current.set(event.clientX, event.clientY);
|
||||
|
||||
dissectEvent.emit({
|
||||
rotation: lastDissection.rotation + delta.x / window.innerWidth,
|
||||
offset: lastDissection.offset,
|
||||
rotation:
|
||||
lastDissection.rotation + (4 * delta.current.x) / window.innerWidth,
|
||||
// offset: 0,
|
||||
offset: clamp(
|
||||
lastDissection.offset + (4 * delta.current.y) / window.innerHeight,
|
||||
-5,
|
||||
5,
|
||||
),
|
||||
});
|
||||
}, []);
|
||||
const handlePointerUp = useCallback(() => {
|
||||
@@ -245,26 +245,68 @@ export function SceneProps() {
|
||||
window.removeEventListener('pointerup', handlePointerUp);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
function handleDissectEvent(event: DissectEventData) {
|
||||
clippingPlane.current.normal
|
||||
.set(0, 0, 1)
|
||||
.applyAxisAngle(J_HAT, event.rotation - Math.PI / 2);
|
||||
clippingPlane.current.constant = event.offset;
|
||||
|
||||
if (!dissector.current) return;
|
||||
|
||||
dissector.current.rotation.set(0, event.rotation, 0);
|
||||
dissector.current.position
|
||||
.set(event.offset, 0, 0)
|
||||
.applyAxisAngle(J_HAT, event.rotation);
|
||||
}
|
||||
|
||||
dissectEvent.on(handleDissectEvent);
|
||||
handleDissectEvent(lastDissection);
|
||||
|
||||
return () => {
|
||||
dissectEvent.off(handleDissectEvent);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{display !== TankopediaDisplay.ShootingRange && (
|
||||
<mesh
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
onPointerDown={(event) => {
|
||||
event.stopPropagation();
|
||||
<>
|
||||
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<planeGeometry args={[GRID_SIZE, GRID_SIZE]} />
|
||||
<meshStandardMaterial
|
||||
clippingPlanes={[clippingPlane.current]}
|
||||
map={gridTexture}
|
||||
transparent
|
||||
/>
|
||||
</mesh>
|
||||
|
||||
position.set(event.nativeEvent.clientX, event.nativeEvent.clientY);
|
||||
mutateTankopediaEphemeral((draft) => {
|
||||
draft.controlsEnabled = false;
|
||||
});
|
||||
<group ref={dissector}>
|
||||
<mesh
|
||||
position={[GRID_SIZE / 8, 0, 0]}
|
||||
rotation={[-Math.PI / 2, 0, Math.PI / 2]}
|
||||
onPointerDown={(event) => {
|
||||
if (display !== TankopediaDisplay.Dissector) return;
|
||||
|
||||
window.addEventListener('pointermove', handlePointerMove);
|
||||
window.addEventListener('pointerup', handlePointerUp);
|
||||
}}
|
||||
>
|
||||
<planeGeometry args={[10, 10]} />
|
||||
<meshStandardMaterial ref={material} map={texture} transparent />
|
||||
</mesh>
|
||||
event.stopPropagation();
|
||||
|
||||
position.current.set(
|
||||
event.nativeEvent.clientX,
|
||||
event.nativeEvent.clientY,
|
||||
);
|
||||
mutateTankopediaEphemeral((draft) => {
|
||||
draft.controlsEnabled = false;
|
||||
});
|
||||
|
||||
window.addEventListener('pointermove', handlePointerMove);
|
||||
window.addEventListener('pointerup', handlePointerUp);
|
||||
}}
|
||||
>
|
||||
<planeGeometry args={[GRID_SIZE / 2, GRID_SIZE / 4]} />
|
||||
<meshStandardMaterial map={dragTexture} transparent />
|
||||
</mesh>
|
||||
</group>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* {display === TankopediaDisplay.ShootingRange && (
|
||||
|
||||
@@ -7,6 +7,9 @@ export interface DissectEventData {
|
||||
|
||||
export const dissectEvent = new EventManager<DissectEventData>();
|
||||
|
||||
export const lastDissection: DissectEventData = { rotation: 0, offset: 0 };
|
||||
export const lastDissection: DissectEventData = {
|
||||
rotation: Math.PI / 2,
|
||||
offset: 0,
|
||||
};
|
||||
|
||||
dissectEvent.on((data) => Object.assign(lastDissection, data));
|
||||
Reference in new issue
Block a user