feat: effective and persistent angle

This commit is contained in:
tresabhi committed 2025-05-15 23:21:01 -05:00
1 parent bbe682fa73
commit 5b8da36fb8
11 files changed
+77 -33

No files matched your search

+4 -2
View File
@@ -12,7 +12,8 @@
"deg": "%s1°",
"hp": "%s1hp",
"x": "x%s1",
"percentage": "%s1%"
"percentage": "%s1%",
"deg_s": "%s1°/s"
},
"gun_types": {
@@ -885,7 +886,8 @@
"turret": "Turret",
"hard": "Hard",
"medium": "Medium",
"soft": "Soft"
"soft": "Soft",
"effective": "Effective"
},
"ricochet": {
@@ -7,9 +7,9 @@ import { awaitableProvisionDefinitions } from '../../../../../../core/awaitables
import { useEquipment } from '../../../../../../hooks/useEquipment';
import { useLocale } from '../../../../../../hooks/useLocale';
import { Duel } from '../../../../../../stores/duel';
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
import { InfoWithDelta } from './InfoWithDelta';
import { StatsTableWrapper } from './StatsTableWrapper';
import type { StatsAcceptorProps } from './TraverseVisualizer';
const provisionDefinitions = await awaitableProvisionDefinitions;
@@ -21,11 +21,11 @@ import { useEquipment } from '../../../../../../hooks/useEquipment';
import { useLocale } from '../../../../../../hooks/useLocale';
import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefinition';
import { Duel } from '../../../../../../stores/duel';
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
import { Info } from './Info';
import { InfoWithDelta } from './InfoWithDelta';
import { RicochetVisualizer } from './RicochetVisualizer';
import { StatsTableWrapper } from './StatsTableWrapper';
import type { StatsAcceptorProps } from './TraverseVisualizer';
export function Firepower({ stats }: StatsAcceptorProps) {
const mutateDuel = Duel.useMutation();
@@ -1,13 +0,0 @@
@keyframes spin {
from {
transform: translate(-50%, -50%) rotate(0deg);
}
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.hull-traverse-visualizer {
animation: spin linear infinite;
}
@@ -1,12 +1,12 @@
import { Heading } from '@radix-ui/themes';
import { useLocale } from '../../../../../../hooks/useLocale';
import {
HullTraverseVisualizer,
type StatsAcceptorProps,
} from './HullTraverseVisualizer';
import { Info } from './Info';
import { InfoWithDelta } from './InfoWithDelta';
import { StatsTableWrapper } from './StatsTableWrapper';
import {
TraverseVisualizer,
type StatsAcceptorProps,
} from './TraverseVisualizer';
export function Maneuverability({ stats }: StatsAcceptorProps) {
const { strings } = useLocale();
@@ -130,7 +130,7 @@ export function Maneuverability({ stats }: StatsAcceptorProps) {
value="hullTraverseSoftTerrain"
/>
<HullTraverseVisualizer stats={stats} />
<TraverseVisualizer stats={stats} />
</StatsTableWrapper>
);
}
@@ -3,7 +3,7 @@ import type { QuicklimeCallback } from 'quicklime';
import { useEffect, useRef } from 'react';
import { reloadUpdate, type ReloadUpdateData } from '..';
import { Var } from '../../../../../../../../core/radix/var';
import type { StatsAcceptorProps } from '../../HullTraverseVisualizer';
import type { StatsAcceptorProps } from '../../TraverseVisualizer';
import { ShellBorder } from './ShellBorder';
interface ShellProps {
@@ -4,7 +4,7 @@ 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 '../HullTraverseVisualizer';
import type { StatsAcceptorProps } from '../TraverseVisualizer';
import { Shell } from './components/Shell';
import { Target } from './components/Target';
@@ -6,7 +6,7 @@ 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 '../HullTraverseVisualizer';
import type { StatsAcceptorProps } from '../TraverseVisualizer';
import { ShellSwitcher } from './components/ShellSwitcher';
export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
@@ -1,9 +1,9 @@
import { Heading } from '@radix-ui/themes';
import { useLocale } from '../../../../../../hooks/useLocale';
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
import { Info } from './Info';
import { InfoWithDelta } from './InfoWithDelta';
import { StatsTableWrapper } from './StatsTableWrapper';
import type { StatsAcceptorProps } from './TraverseVisualizer';
import { ViewRangeVisualizer } from './ViewRangeVisualizer';
export function Survivability({ stats }: StatsAcceptorProps) {
@@ -1,8 +1,8 @@
import { Card, Checkbox, Flex, Tabs, Text } from '@radix-ui/themes';
import { useRef, useState } from 'react';
import { literals } from '@blitzkit/i18n';
import { Card, 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 './index.css';
export interface StatsAcceptorProps {
stats: TankCharacteristics;
@@ -10,7 +10,7 @@ export interface StatsAcceptorProps {
type Terrain = 'Hard' | 'Medium' | 'Soft';
export function HullTraverseVisualizer({ stats }: StatsAcceptorProps) {
export function TraverseVisualizer({ stats }: StatsAcceptorProps) {
const hull = useRef<HTMLDivElement>(null);
const turret = useRef<HTMLImageElement>(null);
const [terrain, setTerrain] = useState<Terrain>('Hard');
@@ -19,12 +19,46 @@ export function HullTraverseVisualizer({ stats }: StatsAcceptorProps) {
const { strings } = useLocale();
const isTurretless =
stats.azimuthLeft !== undefined || stats.azimuthRight !== undefined;
const turretAngle = useRef(0);
const hullAngle = useRef(0);
const turretSpeedDeg = rotateTurret ? stats.turretTraverseSpeed : 0;
const hullSpeedDeg = rotateHull ? stats[`hullTraverse${terrain}Terrain`] : 0;
useEffect(() => {
let cancel = false;
const turretSpeedRad = turretSpeedDeg * (Math.PI / 180);
const hullTraverseRad = hullSpeedDeg * (Math.PI / 180);
let lastT = Date.now() / 1000;
function frame() {
if (!turret.current || !hull.current) return;
const t = Date.now() / 1000;
const dt = t - lastT;
lastT = t;
turretAngle.current =
(turretAngle.current + turretSpeedRad * dt) % (2 * Math.PI);
hullAngle.current =
(hullAngle.current + hullTraverseRad * dt) % (2 * Math.PI);
turret.current.style.transform = `translate(-50%, -50%) rotate(${-turretAngle.current}rad)`;
hull.current.style.transform = `translate(-50%, -50%) rotate(${-hullAngle.current}rad)`;
if (!cancel) requestAnimationFrame(frame);
}
frame();
return () => {
cancel = true;
};
}, [terrain, turretSpeedDeg, hullSpeedDeg]);
return (
<Card variant="classic" style={{ aspectRatio: '1 / 1' }}>
<div
ref={hull}
className="hull-traverse-visualizer"
style={{
position: 'absolute',
top: '50%',
@@ -50,7 +84,6 @@ export function HullTraverseVisualizer({ stats }: StatsAcceptorProps) {
<img
draggable="false"
ref={turret}
className="hull-traverse-visualizer"
style={{
width: '27rem',
height: '27rem',
@@ -95,12 +128,34 @@ export function HullTraverseVisualizer({ stats }: StatsAcceptorProps) {
</Tabs.Root>
</Flex>
<Flex
gap="2"
position="absolute"
left="50%"
bottom="7"
style={{
transform: 'translateX(-50%)',
}}
>
<Text color="gray" size="1">
{strings.website.tools.tankopedia.visualizers.rotator.effective}
</Text>
<Code size="1" variant="ghost">
{literals(strings.common.units.deg_s, [
`${(turretSpeedDeg + hullSpeedDeg).toFixed(1)}`,
])}
</Code>
</Flex>
{!isTurretless && (
<Flex
position="absolute"
top="4"
left="50%"
width="100%"
px="5"
gap="5"
justify="center"
style={{
transform: 'translateX(-50%)',
userSelect: 'none',
@@ -4,7 +4,7 @@ import { Box, Card, Code, Flex, Slider, Tabs, Text } from '@radix-ui/themes';
import { useRef, useState } from 'react';
import { Var } from '../../../../../../core/radix/var';
import { useLocale } from '../../../../../../hooks/useLocale';
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
import type { StatsAcceptorProps } from './TraverseVisualizer';
const maps = [
{