mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: elevation
This commit is contained in:
1 parent
e6029157aa
commit
6b7f8049fe
6 files changed
+117
-53
No files matched your search
+4
-3
@@ -1,6 +1,6 @@
|
||||
import type { AssaultRanges } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Box, Card, Flex, Text } from '@radix-ui/themes';
|
||||
import { Box, Flex, Text } from '@radix-ui/themes';
|
||||
import { clamp } from 'three/src/math/MathUtils.js';
|
||||
import {
|
||||
fakeLogSquishyHigh,
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
|
||||
import { Var } from '../../../../../../../core/radix/var';
|
||||
import { useLocale } from '../../../../../../../hooks/useLocale';
|
||||
import { VisualizerCard } from '../VisualizerCard';
|
||||
import { AssaultCursor } from './components/Cursor';
|
||||
|
||||
interface Props {
|
||||
@@ -29,7 +30,7 @@ export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) {
|
||||
const { strings } = useLocale();
|
||||
|
||||
return (
|
||||
<Card mb="6" variant="classic" style={{ aspectRatio: '1 / 1' }}>
|
||||
<VisualizerCard>
|
||||
<Flex
|
||||
position="absolute"
|
||||
top="0"
|
||||
@@ -152,6 +153,6 @@ export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) {
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Card>
|
||||
</VisualizerCard>
|
||||
);
|
||||
}
|
||||
+71
-22
@@ -1,14 +1,14 @@
|
||||
import { Card } from '@radix-ui/themes';
|
||||
import { awaitableModelDefinitions } from '../../../../../../../core/awaitables/modelDefinitions';
|
||||
import { DEFAULT_PITCH_TRANSITION } from '../../../../../../../core/blitz/applyPitchYawLimits';
|
||||
import { Duel } from '../../../../../../../stores/duel';
|
||||
import { VisualizerCard } from '../VisualizerCard';
|
||||
|
||||
const MAX_MAG = 20;
|
||||
const ANGLE_COEFFICIENT = 1 / 10;
|
||||
|
||||
const modelDefinition = await awaitableModelDefinitions;
|
||||
|
||||
function mag(x: number) {
|
||||
return (x / MAX_MAG + 1) / 2;
|
||||
return ((2 / Math.PI) * Math.atan(ANGLE_COEFFICIENT * x) + 1) / 2;
|
||||
}
|
||||
|
||||
function c(thetaDeg: number, m = 1) {
|
||||
@@ -34,18 +34,18 @@ export function GunFlexibilityVisualizer() {
|
||||
let d = '';
|
||||
|
||||
// right
|
||||
const ms = mag(p.max);
|
||||
const mo = mag(p.max);
|
||||
if (y) {
|
||||
d += `M ${c(90 - y.max, ms)}`;
|
||||
d += `M ${c(90 - y.max, mo)}`;
|
||||
} else if (b) {
|
||||
d += `M ${c(-90 + b.range / 2 + t, ms)}`;
|
||||
d += `M ${c(-90 + b.range / 2 + t, mo)}`;
|
||||
} else {
|
||||
d += `M ${c(-90 / 2, ms)}`;
|
||||
d += `M ${c(-90 / 2, mo)}`;
|
||||
}
|
||||
if (f) {
|
||||
d += `A ${ms} ${ms} 0 0 0 ${c(90 - f.range / 2 - t, ms)}`;
|
||||
d += `A ${mo} ${mo} 0 0 0 ${c(90 - f.range / 2 - t, mo)}`;
|
||||
} else {
|
||||
d += `A ${ms} ${ms} 0 0 0 ${c(90 / 2, ms)}`;
|
||||
d += `A ${mo} ${mo} 0 0 0 ${c(90 / 2, mo)}`;
|
||||
}
|
||||
|
||||
// front
|
||||
@@ -57,16 +57,16 @@ export function GunFlexibilityVisualizer() {
|
||||
|
||||
// left
|
||||
if (f) {
|
||||
d += `L ${c(90 + f.range / 2 + t, ms)}`;
|
||||
d += `L ${c(90 + f.range / 2 + t, mo)}`;
|
||||
} else {
|
||||
d += `L ${c(90 / 2, ms)}`;
|
||||
d += `L ${c(90 / 2, mo)}`;
|
||||
}
|
||||
if (y) {
|
||||
d += `A ${ms} ${ms} 0 0 0 ${c(90 - y.min, ms)}`;
|
||||
d += `A ${mo} ${mo} 0 0 0 ${c(90 - y.min, mo)}`;
|
||||
} else if (b) {
|
||||
d += `A ${ms} ${ms} 0 0 0 ${c(-90 - b.range / 2 - t, ms)}`;
|
||||
d += `A ${mo} ${mo} 0 0 0 ${c(-90 - b.range / 2 - t, mo)}`;
|
||||
} else {
|
||||
d += `A ${ms} ${ms} 0 0 0 ${c(-90 / 2, ms)}`;
|
||||
d += `A ${mo} ${mo} 0 0 0 ${c(-90 / 2, mo)}`;
|
||||
}
|
||||
|
||||
// back
|
||||
@@ -78,8 +78,53 @@ export function GunFlexibilityVisualizer() {
|
||||
|
||||
d += `Z`;
|
||||
|
||||
// right
|
||||
const mi = mag(p.min);
|
||||
if (y) {
|
||||
d += `M ${c(90 - y.max, mi)}`;
|
||||
} else if (b) {
|
||||
d += `M ${c(-90 + b.range / 2 + t, mi)}`;
|
||||
} else {
|
||||
d += `M ${c(-90 / 2, mi)}`;
|
||||
}
|
||||
if (f) {
|
||||
d += `A ${mi} ${mi} 0 0 0 ${c(90 - f.range / 2 - t, mi)}`;
|
||||
} else {
|
||||
d += `A ${mi} ${mi} 0 0 0 ${c(90 / 2, mi)}`;
|
||||
}
|
||||
|
||||
// front
|
||||
if (f) {
|
||||
const m = mag(f.min);
|
||||
d += `L ${c(90 - f.range / 2, m)}`;
|
||||
d += `A ${m} ${m} 0 0 0 ${c(90 + f.range / 2, m)}`;
|
||||
}
|
||||
|
||||
// left
|
||||
if (f) {
|
||||
d += `L ${c(90 + f.range / 2 + t, mi)}`;
|
||||
} else {
|
||||
d += `L ${c(90 / 2, mi)}`;
|
||||
}
|
||||
if (y) {
|
||||
d += `A ${mi} ${mi} 0 0 0 ${c(90 - y.min, mi)}`;
|
||||
} else if (b) {
|
||||
d += `A ${mi} ${mi} 0 0 0 ${c(-90 - b.range / 2 - t, mi)}`;
|
||||
} else {
|
||||
d += `A ${mi} ${mi} 0 0 0 ${c(-90 / 2, mi)}`;
|
||||
}
|
||||
|
||||
// back
|
||||
if (!y && b) {
|
||||
const m = mag(b.min);
|
||||
d += `L ${c(-90 - b.range / 2, m)}`;
|
||||
d += `A ${m} ${m} 0 0 0 ${c(-90 + b.range / 2, m)}`;
|
||||
}
|
||||
|
||||
d += `Z`;
|
||||
|
||||
return (
|
||||
<Card style={{ aspectRatio: '1 / 1' }} variant="classic">
|
||||
<VisualizerCard>
|
||||
<svg
|
||||
style={{
|
||||
position: 'absolute',
|
||||
@@ -91,19 +136,23 @@ export function GunFlexibilityVisualizer() {
|
||||
viewBox="-1 -1 2 2"
|
||||
>
|
||||
<path
|
||||
stroke="var(--gray-11)"
|
||||
strokeWidth="0.01px"
|
||||
fill="var(--gray-9)"
|
||||
fillRule="evenodd"
|
||||
fill="var(--gray-5)"
|
||||
stroke="var(--gray-7)"
|
||||
strokeWidth="1px"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
d={d}
|
||||
/>
|
||||
|
||||
<path
|
||||
stroke="var(--gray-2)"
|
||||
stroke="var(--gray-10)"
|
||||
fill="transparent"
|
||||
strokeWidth="0.01px"
|
||||
strokeDasharray="0.05 0.01"
|
||||
strokeWidth="1px"
|
||||
strokeDasharray="0.5rem 0.5rem"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
d="M 0.5 0 A 0.5 0.5 0 1 1 -0.5 0 A 0.5 0.5 0 1 1 0.5 0 Z"
|
||||
/>
|
||||
</svg>
|
||||
</Card>
|
||||
</VisualizerCard>
|
||||
);
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,11 @@
|
||||
import { type Datum, type Serie } from '@nivo/line';
|
||||
import { Box, Card } from '@radix-ui/themes';
|
||||
import { Box } from '@radix-ui/themes';
|
||||
import { times } from 'lodash-es';
|
||||
import { Quicklime, type QuicklimeCallback } from 'quicklime';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Var } from '../../../../../../../core/radix/var';
|
||||
import type { StatsAcceptorProps } from '../TraverseVisualizer';
|
||||
import { VisualizerCard } from '../VisualizerCard';
|
||||
import { Shell } from './components/Shell';
|
||||
import { Target } from './components/Target';
|
||||
|
||||
@@ -51,7 +52,6 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
|
||||
}
|
||||
|
||||
function frame() {
|
||||
|
||||
const now = Date.now() / 1000;
|
||||
const dt = now - lastT;
|
||||
let reload;
|
||||
@@ -130,7 +130,7 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card variant="classic" mb="6" style={{ aspectRatio: '1 / 1' }}>
|
||||
<VisualizerCard>
|
||||
<Box position="absolute" top="0" left="0" width="100%" height="100%">
|
||||
<Target />
|
||||
|
||||
@@ -220,6 +220,6 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
|
||||
times(stats.shells, (index) => (
|
||||
<Shell stats={stats} index={index} key={index} />
|
||||
))}
|
||||
</Card>
|
||||
</VisualizerCard>
|
||||
);
|
||||
}
|
||||
+17
-21
@@ -1,12 +1,13 @@
|
||||
import { asset, isExplosive } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Box, Card, Code, Flex, Text } from '@radix-ui/themes';
|
||||
import { Box, Code, Flex, Text } from '@radix-ui/themes';
|
||||
import { useRef, useState } from 'react';
|
||||
import { clamp, degToRad, radToDeg } from 'three/src/math/MathUtils.js';
|
||||
import { Var } from '../../../../../../../core/radix/var';
|
||||
import { useLocale } from '../../../../../../../hooks/useLocale';
|
||||
import { Duel } from '../../../../../../../stores/duel';
|
||||
import type { StatsAcceptorProps } from '../TraverseVisualizer';
|
||||
import { VisualizerCard } from '../VisualizerCard';
|
||||
import { ShellSwitcher } from './components/ShellSwitcher';
|
||||
|
||||
export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
|
||||
@@ -26,13 +27,8 @@ export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
|
||||
|
||||
return (
|
||||
<Flex direction="column" mb="6" align="center">
|
||||
<Card
|
||||
variant="classic"
|
||||
style={{
|
||||
width: '100%',
|
||||
aspectRatio: '1 / 1',
|
||||
touchAction: 'none',
|
||||
}}
|
||||
<VisualizerCard
|
||||
style={{ width: '100%' }}
|
||||
ref={container}
|
||||
onPointerMove={(event) => {
|
||||
if (!container.current || explodes) return;
|
||||
@@ -73,23 +69,23 @@ export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
|
||||
position="absolute"
|
||||
style={{
|
||||
background: `conic-gradient(
|
||||
at 0 50%,
|
||||
at 0 50%,
|
||||
|
||||
${Var('ruby-a2')},
|
||||
${Var('ruby-a1')} ${Math.PI / 2 - ricochet}rad,
|
||||
${Var('ruby-a2')},
|
||||
${Var('ruby-a1')} ${Math.PI / 2 - ricochet}rad,
|
||||
|
||||
${Var('jade-a2')} ${Math.PI / 2 - ricochet}rad,
|
||||
${Var('jade-a4')} ${Math.PI / 2 - normalization}rad,
|
||||
${Var('jade-a2')} ${Math.PI / 2 - ricochet}rad,
|
||||
${Var('jade-a4')} ${Math.PI / 2 - normalization}rad,
|
||||
|
||||
${Var('cyan-a5')} ${Math.PI / 2 - normalization}rad,
|
||||
${Var('cyan-a3')} ${Math.PI / 2 + normalization}rad,
|
||||
${Var('cyan-a5')} ${Math.PI / 2 - normalization}rad,
|
||||
${Var('cyan-a3')} ${Math.PI / 2 + normalization}rad,
|
||||
|
||||
${Var('jade-a2')} ${Math.PI / 2 + normalization}rad,
|
||||
${Var('jade-a4')} ${Math.PI / 2 + ricochet}rad,
|
||||
${Var('jade-a2')} ${Math.PI / 2 + normalization}rad,
|
||||
${Var('jade-a4')} ${Math.PI / 2 + ricochet}rad,
|
||||
|
||||
${Var('ruby-a1')} ${Math.PI / 2 + ricochet}rad,
|
||||
${Var('ruby-a2')} 180deg
|
||||
`,
|
||||
${Var('ruby-a1')} ${Math.PI / 2 + ricochet}rad,
|
||||
${Var('ruby-a2')} 180deg
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -262,7 +258,7 @@ export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Card>
|
||||
</VisualizerCard>
|
||||
|
||||
<ShellSwitcher />
|
||||
</Flex>
|
||||
|
||||
+4
-3
@@ -1,8 +1,9 @@
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Card, Checkbox, Code, Flex, Tabs, Text } from '@radix-ui/themes';
|
||||
import { Checkbox, Code, Flex, Tabs, Text } from '@radix-ui/themes';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
|
||||
import { useLocale } from '../../../../../../../hooks/useLocale';
|
||||
import { VisualizerCard } from '../VisualizerCard';
|
||||
|
||||
export interface StatsAcceptorProps {
|
||||
stats: TankCharacteristics;
|
||||
@@ -58,7 +59,7 @@ export function TraverseVisualizer({ stats }: StatsAcceptorProps) {
|
||||
}, [terrain, turretSpeedDeg, hullSpeedDeg]);
|
||||
|
||||
return (
|
||||
<Card variant="classic" style={{ aspectRatio: '1 / 1' }}>
|
||||
<VisualizerCard>
|
||||
<div
|
||||
ref={hull}
|
||||
style={{
|
||||
@@ -188,6 +189,6 @@ export function TraverseVisualizer({ stats }: StatsAcceptorProps) {
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
</Card>
|
||||
</VisualizerCard>
|
||||
);
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { Card, type CardProps } from '@radix-ui/themes';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
export const VisualizerCard = forwardRef<HTMLDivElement, CardProps>(
|
||||
({ style, ...props }, ref) => {
|
||||
return (
|
||||
<Card
|
||||
ref={ref}
|
||||
variant="classic"
|
||||
mt="4"
|
||||
mb="6"
|
||||
style={{ aspectRatio: '1 / 1', ...style }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user