mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: move poses
This commit is contained in:
1 parent
103c1b4338
commit
480fda34ce
4 files changed
+120
-36
No files matched your search
@@ -10,7 +10,11 @@ import { Pose, poseEvent } from '../../../../../core/blitzkrieg/pose';
|
|||||||
import { useTankopedia } from '../../../../../stores/tankopedia';
|
import { useTankopedia } from '../../../../../stores/tankopedia';
|
||||||
import { Duel } from '../page';
|
import { Duel } from '../page';
|
||||||
|
|
||||||
const DISTANCE = 15;
|
const poseDistances: Record<Pose, number> = {
|
||||||
|
[Pose.HullDown]: 15,
|
||||||
|
[Pose.FaceHug]: 5,
|
||||||
|
[Pose.Default]: -1,
|
||||||
|
};
|
||||||
|
|
||||||
interface ControlsProps {
|
interface ControlsProps {
|
||||||
duel: Duel;
|
duel: Duel;
|
||||||
@@ -23,25 +27,33 @@ export function Controls({ duel }: ControlsProps) {
|
|||||||
async () => await modelDefinitions,
|
async () => await modelDefinitions,
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const tankModelDefinition = awaitedModelDefinitions[duel.protagonist.tank.id];
|
const protagonistModelDefinition =
|
||||||
const turretModelDefinition =
|
awaitedModelDefinitions[duel.protagonist.tank.id];
|
||||||
tankModelDefinition.turrets[duel.protagonist.turret.id];
|
const antagonistModelDefinition =
|
||||||
const gunModelDefinition =
|
awaitedModelDefinitions[duel.antagonist.tank.id];
|
||||||
turretModelDefinition.guns[duel.protagonist.gun.id];
|
const protagonistTurretModelDefinition =
|
||||||
const turretOrigin = new Vector3(
|
protagonistModelDefinition.turrets[duel.protagonist.turret.id];
|
||||||
tankModelDefinition.turretOrigin[0],
|
const antagonistTurretModelDefinition =
|
||||||
tankModelDefinition.turretOrigin[1],
|
antagonistModelDefinition.turrets[duel.antagonist.turret.id];
|
||||||
-tankModelDefinition.turretOrigin[2],
|
const protagonistGunModelDefinition =
|
||||||
|
protagonistTurretModelDefinition.guns[duel.protagonist.gun.id];
|
||||||
|
const protagonistTurretOrigin = new Vector3(
|
||||||
|
protagonistModelDefinition.turretOrigin[0],
|
||||||
|
protagonistModelDefinition.turretOrigin[1],
|
||||||
|
-protagonistModelDefinition.turretOrigin[2],
|
||||||
);
|
);
|
||||||
const gunOrigin = new Vector3(
|
const protagonistGunOrigin = new Vector3(
|
||||||
turretModelDefinition.gunOrigin[0],
|
protagonistTurretModelDefinition.gunOrigin[0],
|
||||||
turretModelDefinition.gunOrigin[1],
|
protagonistTurretModelDefinition.gunOrigin[1],
|
||||||
-turretModelDefinition.gunOrigin[2],
|
-protagonistTurretModelDefinition.gunOrigin[2],
|
||||||
);
|
);
|
||||||
|
const antagonistGunHeight =
|
||||||
|
antagonistModelDefinition.turretOrigin[1] +
|
||||||
|
antagonistTurretModelDefinition.gunOrigin[1];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
camera.position.set(-5, 4, -20);
|
camera.position.set(-4, 4, -16);
|
||||||
orbitControls.current?.target.set(0, 1.5, 0);
|
orbitControls.current?.target.set(0, antagonistGunHeight / 2, 0);
|
||||||
|
|
||||||
const unsubscribeTankopedia = useTankopedia.subscribe(
|
const unsubscribeTankopedia = useTankopedia.subscribe(
|
||||||
(state) => state.model.visual.controlsEnabled,
|
(state) => state.model.visual.controlsEnabled,
|
||||||
@@ -51,27 +63,72 @@ export function Controls({ duel }: ControlsProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
function handlePoseEvent(event: Pose) {
|
function handlePoseEvent(event: Pose) {
|
||||||
const [pitch] = applyPitchYawLimits(
|
|
||||||
-Infinity,
|
|
||||||
0,
|
|
||||||
gunModelDefinition.pitch,
|
|
||||||
turretModelDefinition.yaw,
|
|
||||||
);
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case Pose.HullDown: {
|
case Pose.HullDown: {
|
||||||
|
const [pitch] = applyPitchYawLimits(
|
||||||
|
-Infinity,
|
||||||
|
0,
|
||||||
|
protagonistGunModelDefinition.pitch,
|
||||||
|
protagonistTurretModelDefinition.yaw,
|
||||||
|
);
|
||||||
|
|
||||||
camera.position
|
camera.position
|
||||||
.set(0, 0, 0)
|
.set(0, 0, 0)
|
||||||
.add(turretOrigin)
|
.add(protagonistTurretOrigin)
|
||||||
.add(gunOrigin)
|
.add(protagonistGunOrigin)
|
||||||
.add(
|
.add(
|
||||||
new Vector3(
|
new Vector3(
|
||||||
0,
|
0,
|
||||||
DISTANCE * Math.sin(pitch),
|
poseDistances[event] * Math.sin(pitch),
|
||||||
DISTANCE * -Math.cos(pitch),
|
poseDistances[event] * -Math.cos(pitch),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
camera.lookAt(turretOrigin.clone().add(gunOrigin));
|
camera.lookAt(
|
||||||
orbitControls.current?.target.set(0, 1.5, 0);
|
protagonistTurretOrigin.clone().add(protagonistGunOrigin),
|
||||||
|
);
|
||||||
|
orbitControls.current?.target.set(0, antagonistGunHeight, 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Pose.FaceHug: {
|
||||||
|
const [pitch] = applyPitchYawLimits(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
protagonistGunModelDefinition.pitch,
|
||||||
|
protagonistTurretModelDefinition.yaw,
|
||||||
|
);
|
||||||
|
|
||||||
|
camera.position
|
||||||
|
.set(0, 0, 0)
|
||||||
|
.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(protagonistTurretOrigin)
|
||||||
|
.add(protagonistGunOrigin)
|
||||||
|
.add(
|
||||||
|
new Vector3(
|
||||||
|
0,
|
||||||
|
0.5 * poseDistances[event] * Math.sin(pitch),
|
||||||
|
0.5 * poseDistances[event] * -Math.cos(pitch),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Pose.Default: {
|
||||||
|
camera.position.set(-4, 4, -16);
|
||||||
|
orbitControls.current?.target.set(0, antagonistGunHeight / 2, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +139,7 @@ export function Controls({ duel }: ControlsProps) {
|
|||||||
unsubscribeTankopedia();
|
unsubscribeTankopedia();
|
||||||
poseEvent.off(handlePoseEvent);
|
poseEvent.off(handlePoseEvent);
|
||||||
};
|
};
|
||||||
}, [camera]);
|
}, [camera, duel.protagonist.tank.id, duel.antagonist.tank.id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OrbitControls
|
<OrbitControls
|
||||||
|
|||||||
@@ -71,7 +71,29 @@ export function TankSandbox({ duel }: TankSandboxProps) {
|
|||||||
draft.model.physical.pitch = pitch;
|
draft.model.physical.pitch = pitch;
|
||||||
draft.model.physical.yaw = yaw;
|
draft.model.physical.yaw = yaw;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Pose.FaceHug: {
|
||||||
|
mutateTankopedia((draft) => {
|
||||||
|
const [pitch, yaw] = applyPitchYawLimits(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
gunModelDefinition.pitch,
|
||||||
|
turretModelDefinition.yaw,
|
||||||
|
);
|
||||||
|
|
||||||
|
modelTransformEvent.emit({ pitch, yaw });
|
||||||
|
draft.model.physical.pitch = pitch;
|
||||||
|
draft.model.physical.yaw = yaw;
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Pose.Default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +156,7 @@ export function TankSandbox({ duel }: TankSandboxProps) {
|
|||||||
<Canvas
|
<Canvas
|
||||||
shadows
|
shadows
|
||||||
ref={canvas}
|
ref={canvas}
|
||||||
camera={{ fov: 20 }}
|
camera={{ fov: 25 }}
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
>
|
>
|
||||||
<Controls duel={duel} />
|
<Controls duel={duel} />
|
||||||
|
|||||||
@@ -40,14 +40,17 @@ export function Options({ isFullScreen, canvas }: OptionsProps) {
|
|||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item onClick={() => poseEvent.emit(Pose.HullDown)}>
|
||||||
onClick={() => {
|
|
||||||
console.log('called?');
|
|
||||||
poseEvent.emit(Pose.HullDown);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Hull down
|
Hull down
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
||||||
|
<DropdownMenu.Item onClick={() => poseEvent.emit(Pose.FaceHug)}>
|
||||||
|
Face hug
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
|
||||||
|
<DropdownMenu.Item onClick={() => poseEvent.emit(Pose.Default)}>
|
||||||
|
Default
|
||||||
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { EventManager } from './eventManager';
|
|||||||
|
|
||||||
export enum Pose {
|
export enum Pose {
|
||||||
HullDown,
|
HullDown,
|
||||||
|
FaceHug,
|
||||||
|
Default,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const poseEvent = new EventManager<Pose>();
|
export const poseEvent = new EventManager<Pose>();
|
||||||
Reference in new issue
Block a user