Skip to content

Commit ec1aec0

Browse files
committed
feat(game-status): add health, mana, conc, stamina, and spirit game status bars
1 parent 4c925ef commit ec1aec0

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import { useEuiTheme } from '@elastic/eui';
2+
import type { ReactElement, ReactNode } from 'react';
3+
import { useMemo, useState } from 'react';
4+
import type { GameEvent } from '../../../common/game/types.js';
5+
import { GameEventType } from '../../../common/game/types.js';
6+
import { useSubscribe } from '../../hooks/pubsub.jsx';
7+
8+
export const GameStatusBars: React.FC = (): ReactNode => {
9+
const { euiTheme } = useEuiTheme();
10+
11+
const [health, setHealth] = useState<number>(100);
12+
const [mana, setMana] = useState<number>(100);
13+
const [concentration, setConcentration] = useState<number>(100);
14+
const [stamina, setStamina] = useState<number>(100);
15+
const [spirit, setSpirit] = useState<number>(100);
16+
17+
useSubscribe(['game:event'], (gameEvent: GameEvent) => {
18+
if (gameEvent.type === GameEventType.VITALS) {
19+
switch (gameEvent.vitalId) {
20+
case 'health':
21+
setHealth(gameEvent.value);
22+
break;
23+
case 'mana':
24+
setMana(gameEvent.value);
25+
break;
26+
case 'concentration':
27+
setConcentration(gameEvent.value);
28+
break;
29+
case 'stamina':
30+
setStamina(gameEvent.value);
31+
break;
32+
case 'spirit':
33+
setSpirit(gameEvent.value);
34+
break;
35+
}
36+
}
37+
});
38+
39+
const healthStatusBar = useMemo((): ReactElement => {
40+
return (
41+
<GameStatusBar
42+
title="Health"
43+
value={health}
44+
fillColor="#750E21"
45+
textColor={euiTheme.colors.text}
46+
/>
47+
);
48+
}, [health, euiTheme]);
49+
50+
const manaStatusBar = useMemo((): ReactElement => {
51+
return (
52+
<GameStatusBar
53+
title="Mana"
54+
value={mana}
55+
fillColor="#4477CE"
56+
textColor={euiTheme.colors.text}
57+
/>
58+
);
59+
}, [mana, euiTheme]);
60+
61+
const concentrationStatusBar = useMemo((): ReactElement => {
62+
return (
63+
<GameStatusBar
64+
title="Concentration"
65+
value={concentration}
66+
fillColor="#19376D"
67+
textColor={euiTheme.colors.text}
68+
/>
69+
);
70+
}, [concentration, euiTheme]);
71+
72+
const staminaStatusBar = useMemo((): ReactElement => {
73+
return (
74+
<GameStatusBar
75+
title="Stamina"
76+
value={stamina}
77+
fillColor="#006A67"
78+
textColor={euiTheme.colors.text}
79+
/>
80+
);
81+
}, [stamina, euiTheme]);
82+
83+
const spiritStatusBar = useMemo((): ReactElement => {
84+
return (
85+
<GameStatusBar
86+
title="Spirit"
87+
value={spirit}
88+
fillColor="#6A1E55"
89+
textColor={euiTheme.colors.text}
90+
/>
91+
);
92+
}, [spirit, euiTheme]);
93+
94+
const statusBars = useMemo((): ReactElement => {
95+
return (
96+
<div
97+
css={{
98+
display: 'flex',
99+
alignItems: 'center',
100+
alignContent: 'center',
101+
padding: '5px',
102+
gap: '5px',
103+
}}
104+
>
105+
{healthStatusBar}
106+
{manaStatusBar}
107+
{concentrationStatusBar}
108+
{staminaStatusBar}
109+
{spiritStatusBar}
110+
</div>
111+
);
112+
}, [
113+
healthStatusBar,
114+
manaStatusBar,
115+
concentrationStatusBar,
116+
staminaStatusBar,
117+
spiritStatusBar,
118+
]);
119+
120+
return statusBars;
121+
};
122+
123+
GameStatusBars.displayName = 'GameStatusBars';
124+
125+
interface GameStatusBarProps {
126+
title: string;
127+
value: number;
128+
fillColor: string;
129+
textColor: string;
130+
}
131+
132+
const GameStatusBar: React.FC<GameStatusBarProps> = (
133+
props: GameStatusBarProps
134+
): ReactNode => {
135+
const { title, value, fillColor, textColor } = props;
136+
137+
const { euiTheme } = useEuiTheme();
138+
139+
return (
140+
<div
141+
css={{
142+
display: 'flex',
143+
justifyContent: 'center',
144+
alignItems: 'center',
145+
alignContent: 'center',
146+
position: 'relative',
147+
width: '100%',
148+
height: '25px',
149+
border: euiTheme.border.thin,
150+
borderColor: fillColor,
151+
borderRadius: euiTheme.border.radius.small,
152+
userSelect: 'none',
153+
}}
154+
>
155+
<div
156+
style={{
157+
position: 'absolute',
158+
left: 0,
159+
width: `${value}%`,
160+
height: '100%',
161+
backgroundColor: fillColor,
162+
// borderColor: fillColor,
163+
// borderRadius: euiTheme.border.radius.small,
164+
}}
165+
/>
166+
<div
167+
style={{
168+
position: 'absolute',
169+
width: '100%',
170+
height: '100%',
171+
textAlign: 'center',
172+
lineHeight: euiTheme.size.l,
173+
fontSize: euiTheme.size.m,
174+
color: textColor,
175+
}}
176+
>
177+
{title} {value}%
178+
</div>
179+
</div>
180+
);
181+
};
182+
183+
GameStatusBar.displayName = 'GameStatusBar';

0 commit comments

Comments
 (0)