mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: pitch limits
This commit is contained in:
1 parent
56d8392f12
commit
a6e8dd6632
5 files changed
+316
-142
No files matched your search
Binary file not shown.
+22
-21
@@ -408,26 +408,26 @@ if (allTargets || targets?.includes('definitions')) {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('Committing tank definitions...');
|
console.log('Committing definitions...');
|
||||||
await commitMultipleFiles(
|
// await commitMultipleFiles(
|
||||||
'tresabhi',
|
// 'tresabhi',
|
||||||
'blitzkrieg-assets',
|
// 'blitzkrieg-assets',
|
||||||
'main',
|
// 'main',
|
||||||
'definitions',
|
// 'definitions',
|
||||||
[
|
// [
|
||||||
{
|
// {
|
||||||
content: JSON.stringify(tankDefinitions),
|
// content: JSON.stringify(tankDefinitions),
|
||||||
encoding: 'utf-8',
|
// encoding: 'utf-8',
|
||||||
path: 'definitions/tanks.json',
|
// path: 'definitions/tanks.json',
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
content: JSON.stringify(modelDefinitions),
|
// content: JSON.stringify(modelDefinitions),
|
||||||
encoding: 'utf-8',
|
// encoding: 'utf-8',
|
||||||
path: 'definitions/models.json',
|
// path: 'definitions/models.json',
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
true,
|
// true,
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -587,8 +587,9 @@ if (allTargets || targets?.includes('tankModels')) {
|
|||||||
|
|
||||||
// if (id !== 15697) continue; // chieftain TODO: investigate vertices stream over read
|
// if (id !== 15697) continue; // chieftain TODO: investigate vertices stream over read
|
||||||
// if (id !== 24609) continue; // concept 1b
|
// if (id !== 24609) continue; // concept 1b
|
||||||
|
if (id !== 16401) continue; // waffle
|
||||||
// if (id !== 7425) continue; // isu 152
|
// if (id !== 7425) continue; // isu 152
|
||||||
if (id !== 10369) continue; // mino
|
// if (id !== 10369) continue; // mino
|
||||||
// if (id !== 4417) continue; // amx m4 mle
|
// if (id !== 4417) continue; // amx m4 mle
|
||||||
// if (id !== 7297) continue; // 60tp
|
// if (id !== 7297) continue; // 60tp
|
||||||
// if (id !== 1) continue; // t-34
|
// if (id !== 1) continue; // t-34
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||||
import { clamp } from 'lodash';
|
import { clamp } from 'lodash';
|
||||||
import { RefObject, useRef } from 'react';
|
import { RefObject, forwardRef, useImperativeHandle, useRef } from 'react';
|
||||||
import { Group, Mesh, Object3D, Vector3 } from 'three';
|
import { Group, Mesh, Object3D, Vector3 } from 'three';
|
||||||
import {
|
import {
|
||||||
PitchLimits,
|
PitchLimits,
|
||||||
@@ -12,8 +12,8 @@ import { normalizeAnglePI } from '../../../../../core/math/normalizeAngle180';
|
|||||||
interface GunContainerProps {
|
interface GunContainerProps {
|
||||||
turretOrigin: Vector3;
|
turretOrigin: Vector3;
|
||||||
gunOrigin: Vector3;
|
gunOrigin: Vector3;
|
||||||
gunPitch: number;
|
pitch: number;
|
||||||
turretYaw: number;
|
yaw: number;
|
||||||
objects: Object3D[];
|
objects: Object3D[];
|
||||||
model: number;
|
model: number;
|
||||||
yawLimits?: YawLimits;
|
yawLimits?: YawLimits;
|
||||||
@@ -23,113 +23,178 @@ interface GunContainerProps {
|
|||||||
turretContainer: RefObject<Group>;
|
turretContainer: RefObject<Group>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GunContainer({
|
export const GunContainer = forwardRef<Group, GunContainerProps>(
|
||||||
gunOrigin,
|
(
|
||||||
turretOrigin,
|
{
|
||||||
gunPitch,
|
gunOrigin,
|
||||||
turretYaw,
|
turretOrigin,
|
||||||
objects,
|
pitch,
|
||||||
yawLimits,
|
yaw,
|
||||||
onPitchStart,
|
objects,
|
||||||
turretContainer,
|
yawLimits,
|
||||||
pitchLimits,
|
onPitchStart,
|
||||||
model,
|
turretContainer,
|
||||||
onPitchEnd,
|
pitchLimits,
|
||||||
}: GunContainerProps) {
|
model,
|
||||||
const canvas = useThree((state) => state.gl.domElement);
|
onPitchEnd,
|
||||||
const gunContainer = useRef<Group>(null);
|
}: GunContainerProps,
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const canvas = useThree((state) => state.gl.domElement);
|
||||||
|
const gunContainer = useRef<Group>(null);
|
||||||
|
|
||||||
return (
|
useImperativeHandle(ref, () => gunContainer.current!);
|
||||||
<group
|
|
||||||
position={new Vector3()
|
|
||||||
.sub(turretOrigin)
|
|
||||||
.sub(gunOrigin)
|
|
||||||
.applyAxisAngle(new Vector3(1, 0, 0), gunPitch)
|
|
||||||
.add(turretOrigin)
|
|
||||||
.add(gunOrigin)}
|
|
||||||
rotation={[gunPitch, 0, 0]}
|
|
||||||
ref={gunContainer}
|
|
||||||
>
|
|
||||||
{objects.map((object) => {
|
|
||||||
const isCurrentMantlet =
|
|
||||||
object.name === `gun_${model.toString().padStart(2, '0')}_mask`;
|
|
||||||
const isCurrentGun =
|
|
||||||
object.name === `gun_${model.toString().padStart(2, '0')}`;
|
|
||||||
const isVisible = isCurrentGun || isCurrentMantlet;
|
|
||||||
let draftMantletPitch = 0;
|
|
||||||
let draftTurretYaw = 0;
|
|
||||||
|
|
||||||
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
|
return (
|
||||||
event.stopPropagation();
|
<group
|
||||||
|
position={new Vector3()
|
||||||
|
.sub(turretOrigin)
|
||||||
|
.sub(gunOrigin)
|
||||||
|
.applyAxisAngle(new Vector3(1, 0, 0), pitch)
|
||||||
|
.add(turretOrigin)
|
||||||
|
.add(gunOrigin)}
|
||||||
|
rotation={[pitch, 0, 0]}
|
||||||
|
ref={gunContainer}
|
||||||
|
>
|
||||||
|
{objects.map((object) => {
|
||||||
|
const isCurrentMantlet =
|
||||||
|
object.name === `gun_${model.toString().padStart(2, '0')}_mask`;
|
||||||
|
const isCurrentGun =
|
||||||
|
object.name === `gun_${model.toString().padStart(2, '0')}`;
|
||||||
|
const isVisible = isCurrentGun || isCurrentMantlet;
|
||||||
|
let draftPitch = 0;
|
||||||
|
let draftYaw = 0;
|
||||||
|
|
||||||
onPitchStart();
|
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
|
||||||
draftMantletPitch = gunPitch;
|
event.stopPropagation();
|
||||||
draftTurretYaw = turretYaw;
|
|
||||||
window.addEventListener('pointermove', handlePointerMove);
|
onPitchStart();
|
||||||
window.addEventListener('pointerup', handlePointerUp);
|
draftPitch = pitch;
|
||||||
}
|
draftYaw = yaw;
|
||||||
function handlePointerMove(event: PointerEvent) {
|
window.addEventListener('pointermove', handlePointerMove);
|
||||||
if (yawLimits) {
|
window.addEventListener('pointerup', handlePointerUp);
|
||||||
draftTurretYaw = clamp(
|
}
|
||||||
draftTurretYaw + event.movementX * (Math.PI / canvas.width),
|
function handlePointerMove(event: PointerEvent) {
|
||||||
-yawLimits.max * (Math.PI / 180),
|
if (yawLimits) {
|
||||||
-yawLimits.min * (Math.PI / 180),
|
draftYaw = clamp(
|
||||||
|
draftYaw + event.movementX * (Math.PI / canvas.width),
|
||||||
|
-yawLimits.max * (Math.PI / 180),
|
||||||
|
-yawLimits.min * (Math.PI / 180),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draftYaw += event.movementX * ((2 * Math.PI) / canvas.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lowerPitch = -pitchLimits.max * (Math.PI / 180);
|
||||||
|
let upperPitch = -pitchLimits.min * (Math.PI / 180);
|
||||||
|
const transition = (pitchLimits.transition ?? 10) * (Math.PI / 180);
|
||||||
|
|
||||||
|
if (pitchLimits.back) {
|
||||||
|
const range = pitchLimits.back.range * (Math.PI / 180);
|
||||||
|
const yawRotatedAbs = Math.abs(
|
||||||
|
normalizeAnglePI(draftYaw - Math.PI),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (yawRotatedAbs <= range + transition) {
|
||||||
|
if (yawRotatedAbs <= range) {
|
||||||
|
// inside range
|
||||||
|
lowerPitch = -pitchLimits.back.max * (Math.PI / 180);
|
||||||
|
upperPitch = -pitchLimits.back.min * (Math.PI / 180);
|
||||||
|
} else {
|
||||||
|
// inside transition
|
||||||
|
const transitionProgress =
|
||||||
|
(yawRotatedAbs - range) / transition;
|
||||||
|
const maxInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.back.max +
|
||||||
|
transitionProgress * pitchLimits.max;
|
||||||
|
const minInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.back.min +
|
||||||
|
transitionProgress * pitchLimits.min;
|
||||||
|
|
||||||
|
lowerPitch = -maxInterpolatedPitch * (Math.PI / 180);
|
||||||
|
upperPitch = -minInterpolatedPitch * (Math.PI / 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pitchLimits.front) {
|
||||||
|
const range = pitchLimits.front.range * (Math.PI / 180);
|
||||||
|
const yawAbs = Math.abs(normalizeAnglePI(draftYaw));
|
||||||
|
|
||||||
|
if (yawAbs <= range + transition) {
|
||||||
|
if (yawAbs <= range) {
|
||||||
|
// inside range
|
||||||
|
lowerPitch = -pitchLimits.front.max * (Math.PI / 180);
|
||||||
|
upperPitch = -pitchLimits.front.min * (Math.PI / 180);
|
||||||
|
} else {
|
||||||
|
// inside transition
|
||||||
|
const transitionProgress = (yawAbs - range) / transition;
|
||||||
|
const maxInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.front.max +
|
||||||
|
transitionProgress * pitchLimits.max;
|
||||||
|
const minInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.front.min +
|
||||||
|
transitionProgress * pitchLimits.min;
|
||||||
|
|
||||||
|
lowerPitch = -maxInterpolatedPitch * (Math.PI / 180);
|
||||||
|
upperPitch = -minInterpolatedPitch * (Math.PI / 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draftPitch = clamp(
|
||||||
|
draftPitch - event.movementY * (Math.PI / canvas.height),
|
||||||
|
lowerPitch,
|
||||||
|
upperPitch,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
draftTurretYaw += event.movementX * ((2 * Math.PI) / canvas.width);
|
if (gunContainer.current) {
|
||||||
|
gunContainer.current.position
|
||||||
|
.set(0, 0, 0)
|
||||||
|
.sub(turretOrigin)
|
||||||
|
.sub(gunOrigin)
|
||||||
|
.applyAxisAngle(new Vector3(1, 0, 0), draftPitch)
|
||||||
|
.add(turretOrigin)
|
||||||
|
.add(gunOrigin);
|
||||||
|
gunContainer.current.rotation.x = draftPitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (turretContainer.current) {
|
||||||
|
turretContainer.current.position
|
||||||
|
.set(0, 0, 0)
|
||||||
|
.sub(turretOrigin)
|
||||||
|
.applyAxisAngle(new Vector3(0, 0, 1), draftYaw)
|
||||||
|
.add(turretOrigin);
|
||||||
|
turretContainer.current.rotation.z = draftYaw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
draftMantletPitch = clamp(
|
function handlePointerUp() {
|
||||||
draftMantletPitch - event.movementY * (Math.PI / canvas.height),
|
onPitchEnd(
|
||||||
-pitchLimits.max * (Math.PI / 180),
|
normalizeAnglePI(draftPitch),
|
||||||
-pitchLimits.min * (Math.PI / 180),
|
normalizeAnglePI(draftYaw),
|
||||||
|
);
|
||||||
|
window.removeEventListener('pointermove', handlePointerMove);
|
||||||
|
window.removeEventListener('pointerup', handlePointerUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
visible={isVisible}
|
||||||
|
onPointerDown={handlePointerDown}
|
||||||
|
children={resolveJsxTree(object)}
|
||||||
|
key={object.uuid}
|
||||||
|
castShadow
|
||||||
|
receiveShadow
|
||||||
|
geometry={(object as Mesh).geometry}
|
||||||
|
material={(object as Mesh).material}
|
||||||
|
position={object.position}
|
||||||
|
rotation={object.rotation}
|
||||||
|
scale={object.scale}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
})}
|
||||||
if (gunContainer.current) {
|
</group>
|
||||||
gunContainer.current.position
|
);
|
||||||
.set(0, 0, 0)
|
},
|
||||||
.sub(turretOrigin)
|
);
|
||||||
.sub(gunOrigin)
|
|
||||||
.applyAxisAngle(new Vector3(1, 0, 0), draftMantletPitch)
|
|
||||||
.add(turretOrigin)
|
|
||||||
.add(gunOrigin);
|
|
||||||
gunContainer.current.rotation.x = draftMantletPitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (turretContainer.current) {
|
|
||||||
turretContainer.current.position
|
|
||||||
.set(0, 0, 0)
|
|
||||||
.sub(turretOrigin)
|
|
||||||
.applyAxisAngle(new Vector3(0, 0, 1), draftTurretYaw)
|
|
||||||
.add(turretOrigin);
|
|
||||||
turretContainer.current.rotation.z = draftTurretYaw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handlePointerUp() {
|
|
||||||
onPitchEnd(
|
|
||||||
normalizeAnglePI(draftMantletPitch),
|
|
||||||
normalizeAnglePI(draftTurretYaw),
|
|
||||||
);
|
|
||||||
window.removeEventListener('pointermove', handlePointerMove);
|
|
||||||
window.removeEventListener('pointerup', handlePointerUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isVisible) return null;
|
|
||||||
return (
|
|
||||||
<mesh
|
|
||||||
visible={isVisible}
|
|
||||||
onPointerDown={handlePointerDown}
|
|
||||||
children={resolveJsxTree(object)}
|
|
||||||
key={object.uuid}
|
|
||||||
castShadow
|
|
||||||
receiveShadow
|
|
||||||
geometry={(object as Mesh).geometry}
|
|
||||||
material={(object as Mesh).material}
|
|
||||||
position={object.position}
|
|
||||||
rotation={object.rotation}
|
|
||||||
scale={object.scale}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,28 +1,49 @@
|
|||||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||||
import { ReactNode, forwardRef, useImperativeHandle, useRef } from 'react';
|
import { clamp } from 'lodash';
|
||||||
|
import {
|
||||||
|
ReactNode,
|
||||||
|
RefObject,
|
||||||
|
forwardRef,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef,
|
||||||
|
} from 'react';
|
||||||
import { Group, Mesh, Object3D, Vector3 } from 'three';
|
import { Group, Mesh, Object3D, Vector3 } from 'three';
|
||||||
|
import {
|
||||||
|
PitchLimits,
|
||||||
|
YawLimits,
|
||||||
|
} from '../../../../../core/blitzkrieg/modelDefinitions';
|
||||||
import { resolveJsxTree } from '../../../../../core/blitzkrieg/resolveJsxTree';
|
import { resolveJsxTree } from '../../../../../core/blitzkrieg/resolveJsxTree';
|
||||||
import { normalizeAnglePI } from '../../../../../core/math/normalizeAngle180';
|
import { normalizeAnglePI } from '../../../../../core/math/normalizeAngle180';
|
||||||
|
|
||||||
interface TurretContainerProps {
|
interface TurretContainerProps {
|
||||||
origin: Vector3;
|
turretOrigin: Vector3;
|
||||||
|
gunOrigin: Vector3;
|
||||||
objects: Object3D[];
|
objects: Object3D[];
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
yaw: number;
|
yaw: number;
|
||||||
|
pitch: number;
|
||||||
model: number;
|
model: number;
|
||||||
|
yawLimits?: YawLimits;
|
||||||
|
pitchLimits: PitchLimits;
|
||||||
onYawStart: () => void;
|
onYawStart: () => void;
|
||||||
onYawEnd: (yaw: number) => void;
|
onYawEnd: (pitch: number, yaw: number) => void;
|
||||||
|
gunContainer: RefObject<Group>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TurretContainer = forwardRef(
|
export const TurretContainer = forwardRef(
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
origin,
|
gunContainer,
|
||||||
|
turretOrigin,
|
||||||
yaw,
|
yaw,
|
||||||
children,
|
children,
|
||||||
objects,
|
objects,
|
||||||
|
yawLimits,
|
||||||
model,
|
model,
|
||||||
onYawEnd,
|
onYawEnd,
|
||||||
|
pitch,
|
||||||
|
gunOrigin,
|
||||||
|
pitchLimits,
|
||||||
onYawStart,
|
onYawStart,
|
||||||
}: TurretContainerProps,
|
}: TurretContainerProps,
|
||||||
ref,
|
ref,
|
||||||
@@ -35,9 +56,9 @@ export const TurretContainer = forwardRef(
|
|||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
position={new Vector3()
|
position={new Vector3()
|
||||||
.sub(origin)
|
.sub(turretOrigin)
|
||||||
.applyAxisAngle(new Vector3(0, 0, 1), yaw)
|
.applyAxisAngle(new Vector3(0, 0, 1), yaw)
|
||||||
.add(origin)}
|
.add(turretOrigin)}
|
||||||
rotation={[0, 0, yaw]}
|
rotation={[0, 0, yaw]}
|
||||||
ref={turretContainer}
|
ref={turretContainer}
|
||||||
>
|
>
|
||||||
@@ -46,6 +67,7 @@ export const TurretContainer = forwardRef(
|
|||||||
const isCurrentTurret =
|
const isCurrentTurret =
|
||||||
object.name === `turret_${model.toString().padStart(2, '0')}`;
|
object.name === `turret_${model.toString().padStart(2, '0')}`;
|
||||||
const isVisible = isCurrentTurret;
|
const isVisible = isCurrentTurret;
|
||||||
|
let draftPitch = 0;
|
||||||
let draftYaw = 0;
|
let draftYaw = 0;
|
||||||
|
|
||||||
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
|
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
|
||||||
@@ -53,6 +75,7 @@ export const TurretContainer = forwardRef(
|
|||||||
|
|
||||||
if (isTurret) {
|
if (isTurret) {
|
||||||
draftYaw = yaw;
|
draftYaw = yaw;
|
||||||
|
draftPitch = pitch;
|
||||||
|
|
||||||
onYawStart();
|
onYawStart();
|
||||||
window.addEventListener('pointermove', handlePointerMove);
|
window.addEventListener('pointermove', handlePointerMove);
|
||||||
@@ -60,19 +83,97 @@ export const TurretContainer = forwardRef(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handlePointerMove(event: PointerEvent) {
|
function handlePointerMove(event: PointerEvent) {
|
||||||
draftYaw += event.movementX * ((2 * Math.PI) / canvas.width);
|
if (yawLimits) {
|
||||||
|
draftYaw = clamp(
|
||||||
|
draftYaw + event.movementX * (Math.PI / canvas.width),
|
||||||
|
-yawLimits.max * (Math.PI / 180),
|
||||||
|
-yawLimits.min * (Math.PI / 180),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draftYaw += event.movementX * ((2 * Math.PI) / canvas.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lowerPitch = -pitchLimits.max * (Math.PI / 180);
|
||||||
|
let upperPitch = -pitchLimits.min * (Math.PI / 180);
|
||||||
|
const transition = (pitchLimits.transition ?? 10) * (Math.PI / 180);
|
||||||
|
|
||||||
|
if (pitchLimits.back) {
|
||||||
|
const range = pitchLimits.back.range * (Math.PI / 180);
|
||||||
|
const yawRotatedAbs = Math.abs(
|
||||||
|
normalizeAnglePI(draftYaw - Math.PI),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (yawRotatedAbs <= range + transition) {
|
||||||
|
if (yawRotatedAbs <= range) {
|
||||||
|
// inside range
|
||||||
|
lowerPitch = -pitchLimits.back.max * (Math.PI / 180);
|
||||||
|
upperPitch = -pitchLimits.back.min * (Math.PI / 180);
|
||||||
|
} else {
|
||||||
|
// inside transition
|
||||||
|
const transitionProgress =
|
||||||
|
(yawRotatedAbs - range) / transition;
|
||||||
|
const maxInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.back.max +
|
||||||
|
transitionProgress * pitchLimits.max;
|
||||||
|
const minInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.back.min +
|
||||||
|
transitionProgress * pitchLimits.min;
|
||||||
|
|
||||||
|
lowerPitch = -maxInterpolatedPitch * (Math.PI / 180);
|
||||||
|
upperPitch = -minInterpolatedPitch * (Math.PI / 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pitchLimits.front) {
|
||||||
|
const range = pitchLimits.front.range * (Math.PI / 180);
|
||||||
|
const yawAbs = Math.abs(normalizeAnglePI(draftYaw));
|
||||||
|
|
||||||
|
if (yawAbs <= range + transition) {
|
||||||
|
if (yawAbs <= range) {
|
||||||
|
// inside range
|
||||||
|
lowerPitch = -pitchLimits.front.max * (Math.PI / 180);
|
||||||
|
upperPitch = -pitchLimits.front.min * (Math.PI / 180);
|
||||||
|
} else {
|
||||||
|
// inside transition
|
||||||
|
const transitionProgress = (yawAbs - range) / transition;
|
||||||
|
const maxInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.front.max +
|
||||||
|
transitionProgress * pitchLimits.max;
|
||||||
|
const minInterpolatedPitch =
|
||||||
|
(1 - transitionProgress) * pitchLimits.front.min +
|
||||||
|
transitionProgress * pitchLimits.min;
|
||||||
|
|
||||||
|
lowerPitch = -maxInterpolatedPitch * (Math.PI / 180);
|
||||||
|
upperPitch = -minInterpolatedPitch * (Math.PI / 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draftPitch = clamp(draftPitch, lowerPitch, upperPitch);
|
||||||
|
|
||||||
|
if (gunContainer.current) {
|
||||||
|
gunContainer.current.position
|
||||||
|
.set(0, 0, 0)
|
||||||
|
.sub(turretOrigin)
|
||||||
|
.sub(gunOrigin)
|
||||||
|
.applyAxisAngle(new Vector3(1, 0, 0), draftPitch)
|
||||||
|
.add(turretOrigin)
|
||||||
|
.add(gunOrigin);
|
||||||
|
gunContainer.current.rotation.x = draftPitch;
|
||||||
|
}
|
||||||
|
|
||||||
if (turretContainer.current) {
|
if (turretContainer.current) {
|
||||||
turretContainer.current.position
|
turretContainer.current.position
|
||||||
.set(0, 0, 0)
|
.set(0, 0, 0)
|
||||||
.sub(origin)
|
.sub(turretOrigin)
|
||||||
.applyAxisAngle(new Vector3(0, 0, 1), draftYaw)
|
.applyAxisAngle(new Vector3(0, 0, 1), draftYaw)
|
||||||
.add(origin);
|
.add(turretOrigin);
|
||||||
turretContainer.current.rotation.z = draftYaw;
|
turretContainer.current.rotation.z = draftYaw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handlePointerUp() {
|
function handlePointerUp() {
|
||||||
onYawEnd(normalizeAnglePI(draftYaw));
|
onYawEnd(normalizeAnglePI(draftPitch), normalizeAnglePI(draftYaw));
|
||||||
window.removeEventListener('pointermove', handlePointerMove);
|
window.removeEventListener('pointermove', handlePointerMove);
|
||||||
window.removeEventListener('pointerup', handlePointerUp);
|
window.removeEventListener('pointerup', handlePointerUp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,22 +163,29 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TurretContainer
|
<TurretContainer
|
||||||
|
gunOrigin={gunOrigin}
|
||||||
ref={turretContainer}
|
ref={turretContainer}
|
||||||
objects={gltf.scene.children[0].children}
|
objects={gltf.scene.children[0].children}
|
||||||
model={turretModelDefinition.model}
|
model={turretModelDefinition.model}
|
||||||
onYawStart={() => setControlsEnabled(false)}
|
onYawStart={() => setControlsEnabled(false)}
|
||||||
onYawEnd={(yaw) => {
|
yawLimits={turretModelDefinition.yaw}
|
||||||
|
pitchLimits={gunModelDefinition.pitch}
|
||||||
|
pitch={gunPitch}
|
||||||
|
onYawEnd={(pitch, yaw) => {
|
||||||
setControlsEnabled(true);
|
setControlsEnabled(true);
|
||||||
|
setGunPitch(pitch);
|
||||||
setTurretYaw(yaw);
|
setTurretYaw(yaw);
|
||||||
}}
|
}}
|
||||||
origin={turretOrigin}
|
gunContainer={gunContainer}
|
||||||
|
turretOrigin={turretOrigin}
|
||||||
yaw={turretYaw}
|
yaw={turretYaw}
|
||||||
>
|
>
|
||||||
<GunContainer
|
<GunContainer
|
||||||
|
ref={gunContainer}
|
||||||
onPitchStart={() => setControlsEnabled(false)}
|
onPitchStart={() => setControlsEnabled(false)}
|
||||||
pitchLimits={gunModelDefinition.pitch}
|
pitchLimits={gunModelDefinition.pitch}
|
||||||
turretContainer={turretContainer}
|
turretContainer={turretContainer}
|
||||||
turretYaw={turretYaw}
|
yaw={turretYaw}
|
||||||
onPitchEnd={(pitch, yaw) => {
|
onPitchEnd={(pitch, yaw) => {
|
||||||
setControlsEnabled(true);
|
setControlsEnabled(true);
|
||||||
setGunPitch(pitch);
|
setGunPitch(pitch);
|
||||||
@@ -186,7 +193,7 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
}}
|
}}
|
||||||
yawLimits={turretModelDefinition.yaw}
|
yawLimits={turretModelDefinition.yaw}
|
||||||
gunOrigin={gunOrigin}
|
gunOrigin={gunOrigin}
|
||||||
gunPitch={gunPitch}
|
pitch={gunPitch}
|
||||||
model={gunModelDefinition.model}
|
model={gunModelDefinition.model}
|
||||||
objects={gltf.scene.children[0].children}
|
objects={gltf.scene.children[0].children}
|
||||||
turretOrigin={turretOrigin}
|
turretOrigin={turretOrigin}
|
||||||
|
|||||||
Reference in new issue
Block a user