feat: life bar

This commit is contained in:
cha0s 2022-05-03 09:29:09 -05:00
parent e8ae1ef73f
commit 2eebb77ddf
4 changed files with 155 additions and 1 deletions

View File

@ -0,0 +1,56 @@
import {usePropertyChange} from '@avocado/react';
import {PropTypes, React} from '@flecks/react';
import styles from './index.module.scss';
function Health({selfEntity}) {
const life = usePropertyChange(selfEntity, 'life');
const maxLife = usePropertyChange(selfEntity, 'maxLife');
const filled = life / maxLife;
let color = 'white';
if (filled < 0.25) {
color = `rgb(${255}, ${(255 * 4) * filled}, 0)`;
}
else if (filled < 0.5) {
color = `rgb(${255}, ${255}, ${(255 * 4) * (filled - 0.25)})`;
}
const duration = filled < 0.25 ? Math.max(0.5, (filled / 0.125)) : 0;
return (
<div
className={styles.health}
style={{
'--filled': filled,
}}
>
<p className={styles.text}>
<span
className={styles.life}
style={{
animationDuration: `${duration}s`,
color,
}}
>
{life}
</span>
</p>
<div className={styles.meterWrapper}>
<div className={styles.meter}>
<div className={styles.fill} />
</div>
</div>
<p className={styles.text}>
<span className={styles.maxLife}>{maxLife}</span>
</p>
</div>
);
}
Health.defaultProps = {};
Health.displayName = 'Health';
Health.propTypes = {
selfEntity: PropTypes.shape({}).isRequired,
};
export default Health;

View File

@ -0,0 +1,83 @@
@import '../../../../../scss/graphics.scss';
.health {
--border-width: 3px;
--height: 300px;
--width: 30px;
align-items: center;
display: flex;
font-family: joystix;
flex-direction: column;
opacity: 0.8;
padding: 20px;
position: absolute;
left: 0;
top: 0;
}
.health span {
display: block;
text-align: center;
}
.life {
animation: lifeFlicker infinite;
animation-duration: 500ms;
font-size: 2em;
@include shadow-text(2px, black, 0px);
}
.maxLife {
@include shadow-text(1px, black, 0px);
}
@keyframes lifeFlicker {
0% {
opacity: 1;
}
30% {
opacity: 1;
}
45% {
opacity: 0.5;
}
50% {
opacity: 0;
}
55% {
opacity: 0.5;
}
70% {
opacity: 1;
}
}
.meterWrapper {
border-radius: 20px;
border: var(--border-width) solid black;
height: var(--height);
overflow: hidden;
position: relative;
width: var(--width);
}
.meter {
bottom: 0;
height: calc(var(--height) * var(--filled) - (2 * var(--border-width)));
overflow: hidden;
position: absolute;
width: 100%;
}
.fill {
background-image: linear-gradient(to top, red 0%, yellow 50%, green 100%);
box-shadow: inset 0 0 calc(0.66 * var(--width)) rgba(0, 0, 0, 0.8);
height: calc(var(--height) - (2 * var(--border-width)));
position: relative;
top: calc(-1 * var(--height) * (1 - var(--filled)));
}
.text {
margin-bottom: 10px;
}

View File

@ -12,6 +12,7 @@ import {
useRoom,
useSelfEntity,
} from '../../../../hooks';
import Health from './health';
import Hotbar from './hotbar';
import styles from './index.module.scss';
@ -47,7 +48,12 @@ const PlayUi = () => {
ref={ref}
room={room}
/>
{selfEntity && <Hotbar selfEntity={selfEntity} />}
{selfEntity && (
<>
<Health selfEntity={selfEntity} />
<Hotbar selfEntity={selfEntity} />
</>
)}
</div>
);
};

View File

@ -6,3 +6,12 @@
$size -#{$size} $radius $color
;
}
@mixin shadow-text($size, $color, $radius: $size) {
text-shadow:
-#{$size} -#{$size} $radius $color,
$size $size $radius $color,
-#{$size} $size $radius $color,
$size -#{$size} $radius $color
;
}