mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: begennings of reload visuals
This commit is contained in:
1 parent
aeaf52d3ac
commit
d8c26ba24a
4 files changed
+199
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
+3
@@ -24,6 +24,7 @@ import { Duel } from '../../../../../../stores/duel';
|
|||||||
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
|
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
|
||||||
import { Info } from './Info';
|
import { Info } from './Info';
|
||||||
import { InfoWithDelta } from './InfoWithDelta';
|
import { InfoWithDelta } from './InfoWithDelta';
|
||||||
|
import { ReloadVisualizer } from './ReloadVisualizer';
|
||||||
import { RicochetVisualizer } from './RicochetVisualizer';
|
import { RicochetVisualizer } from './RicochetVisualizer';
|
||||||
import { StatsTableWrapper } from './StatsTableWrapper';
|
import { StatsTableWrapper } from './StatsTableWrapper';
|
||||||
|
|
||||||
@@ -165,6 +166,8 @@ export function Firepower({ stats }: StatsAcceptorProps) {
|
|||||||
value="intraClip"
|
value="intraClip"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<ReloadVisualizer stats={stats} />
|
||||||
|
|
||||||
<InfoWithDelta stats={stats} decimals={0} value="penetration" />
|
<InfoWithDelta stats={stats} decimals={0} value="penetration" />
|
||||||
{typeof shell.penetration !== 'number' && (
|
{typeof shell.penetration !== 'number' && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
import { Box, Flex } from '@radix-ui/themes';
|
||||||
|
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';
|
||||||
|
|
||||||
|
interface ShellProps {
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Shell({ index, stats }: ShellProps & StatsAcceptorProps) {
|
||||||
|
const bar = useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleReloadUpdate: QuicklimeCallback<ReloadUpdateData> = ({
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
bar.current.style.width = `${data.shells[index] * 100}%`;
|
||||||
|
};
|
||||||
|
|
||||||
|
reloadUpdate.on(handleReloadUpdate);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
reloadUpdate.off(handleReloadUpdate);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: `translate(-50%, -50%) rotate(${(index - Math.floor(stats.shells / 2)) * 10}deg)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
justify="end"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: '50%',
|
||||||
|
marginLeft: 'calc(25% + 2rem)',
|
||||||
|
width: '1.25rem',
|
||||||
|
height: '0.5rem',
|
||||||
|
borderRadius: '0.25rem',
|
||||||
|
overflow: 'hidden',
|
||||||
|
outline: `1px solid ${Var('jade-6')}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
ref={bar}
|
||||||
|
style={{
|
||||||
|
background: Var('jade-9'),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
import { Box, Card } 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 '../HullTraverseVisualizer';
|
||||||
|
import { Shell } from './components/Shell';
|
||||||
|
|
||||||
|
export interface ReloadUpdateData {
|
||||||
|
reload: number;
|
||||||
|
shells: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reloadUpdate = new Quicklime<ReloadUpdateData>();
|
||||||
|
|
||||||
|
export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
|
||||||
|
const reloadCircle = useRef<HTMLDivElement>(null!);
|
||||||
|
const reloadCore = useRef<HTMLDivElement>(null!);
|
||||||
|
const reloadGlow = useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
|
const size = `${stats.shells === 1 ? 66 : 58}%`;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancel = false;
|
||||||
|
|
||||||
|
function frame() {
|
||||||
|
const now = Date.now() / 1000;
|
||||||
|
|
||||||
|
const t = now % stats.shellReload!;
|
||||||
|
const x = t / stats.shellReload!;
|
||||||
|
|
||||||
|
reloadUpdate.dispatch({
|
||||||
|
reload: x,
|
||||||
|
shells: Array(stats.shells).fill(x),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!cancel) requestAnimationFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancel = true;
|
||||||
|
};
|
||||||
|
}, [stats]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleReloadUpdate: QuicklimeCallback<ReloadUpdateData> = ({
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
const reloadAngle = data.reload * 2 * Math.PI;
|
||||||
|
|
||||||
|
reloadCircle.current.style.background = `conic-gradient(${Var('amber-9')} 0 ${reloadAngle}rad, ${Var('red-7')} ${reloadAngle}rad)`;
|
||||||
|
reloadCore.current.style.background = `conic-gradient(${Var('amber-3')} 0 ${reloadAngle}rad, ${Var('red-2')} ${reloadAngle}rad)`;
|
||||||
|
reloadGlow.current.style.background = `conic-gradient(${Var('amber-8')} 0 ${reloadAngle}rad, transparent ${reloadAngle}rad)`;
|
||||||
|
};
|
||||||
|
|
||||||
|
reloadUpdate.on(handleReloadUpdate);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
reloadUpdate.off(handleReloadUpdate);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card variant="classic" mb="6" style={{ aspectRatio: '1 / 1' }}>
|
||||||
|
<Box
|
||||||
|
p="4"
|
||||||
|
position="absolute"
|
||||||
|
top="50%"
|
||||||
|
left="50%"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
className="reload"
|
||||||
|
ref={reloadGlow}
|
||||||
|
style={{
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
filter: 'blur(0.5rem)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
p="1"
|
||||||
|
position="absolute"
|
||||||
|
top="50%"
|
||||||
|
left="50%"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
className="reload"
|
||||||
|
ref={reloadCircle}
|
||||||
|
style={{
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
background: Var('red-7'),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
ref={reloadCore}
|
||||||
|
style={{
|
||||||
|
backgroundColor: Var('red-2'),
|
||||||
|
borderRadius: '50%',
|
||||||
|
}}
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
overflow="hidden"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
background: `radial-gradient(${Var('gray-3')} 25%, transparent)`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<img
|
||||||
|
src="/assets/images/tankopedia/visualizers/reload/caret.png"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
width: '10%',
|
||||||
|
height: '10%',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{times(stats.shells, (index) => (
|
||||||
|
<Shell stats={stats} index={index} key={index} />
|
||||||
|
))}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user