perf: damage rendering in CSS
This commit is contained in:
parent
ebf62613ef
commit
2b91a49997
|
@ -1,72 +1,43 @@
|
||||||
import {useEffect, useState} from 'react';
|
import {memo, useEffect, useState} from 'react';
|
||||||
|
|
||||||
import {useRadians} from '@/react/context/radians.js';
|
|
||||||
|
|
||||||
import styles from './damage.module.css';
|
import styles from './damage.module.css';
|
||||||
|
|
||||||
export default function Damage({
|
function Damage({
|
||||||
camera,
|
camera,
|
||||||
damage,
|
damage,
|
||||||
scale,
|
scale,
|
||||||
|
zIndex,
|
||||||
}) {
|
}) {
|
||||||
const [hue, setHue] = useState(0);
|
|
||||||
const [opacity, setOpacity] = useState(0.5);
|
|
||||||
const [growth, setGrowth] = useState(0.25);
|
|
||||||
const [offset, setOffset] = useState({x: 0, y: 0});
|
|
||||||
const [randomness] = useState({
|
const [randomness] = useState({
|
||||||
hue: Math.random() * 10,
|
radians: Math.random() * (Math.PI / 16) - (Math.PI / 32),
|
||||||
x: 1 * (Math.random() - 0.5),
|
x: 1 * (Math.random() - 0.5),
|
||||||
y: 150 * (Math.random()),
|
y: Math.random(),
|
||||||
rotation: Math.random() * (Math.PI / 8) - (Math.PI / 16),
|
})
|
||||||
});
|
|
||||||
const radians = useRadians();
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHue(15 + (Math.cos(radians * 4) * (5 + randomness.hue)));
|
const handle = setTimeout(() => {
|
||||||
}, [radians, randomness.hue]);
|
damage.onClose();
|
||||||
useEffect(() => {
|
}, 1_500);
|
||||||
let handle;
|
|
||||||
let accumulated = 0;
|
|
||||||
let last = Date.now();
|
|
||||||
function float() {
|
|
||||||
const elapsed = (Date.now() - last) / 1000;
|
|
||||||
accumulated += elapsed;
|
|
||||||
last = Date.now();
|
|
||||||
if (accumulated < 0.25) {
|
|
||||||
setOpacity(0.5 + accumulated * 2)
|
|
||||||
}
|
|
||||||
if (accumulated < 0.5) {
|
|
||||||
setGrowth(0.25 + (accumulated * 1.5))
|
|
||||||
setOffset({
|
|
||||||
x: 80 * (accumulated * randomness.x),
|
|
||||||
y: -((80 + randomness.y) * (accumulated)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (accumulated >= 1.5) {
|
|
||||||
damage.onClose();
|
|
||||||
}
|
|
||||||
handle = requestAnimationFrame(float);
|
|
||||||
}
|
|
||||||
handle = requestAnimationFrame(float);
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelAnimationFrame(handle);
|
clearTimeout(handle);
|
||||||
};
|
};
|
||||||
}, [damage, randomness.x, randomness.y]);
|
}, [damage]);
|
||||||
|
|
||||||
const {amount, position} = damage;
|
const {amount, position} = damage;
|
||||||
const left = position.x * scale - camera.x + offset.x;
|
|
||||||
const top = position.y * scale - camera.y + offset.y;
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.damage}
|
className={styles.damage}
|
||||||
style={{
|
style={{
|
||||||
color: `hsl(${hue} 100% 50%)`,
|
'--magnitude': Math.max(1, Math.floor(Math.log10(amount))),
|
||||||
left: `${left}px`,
|
'--positionX': `${position.x * scale - camera.x}px`,
|
||||||
opacity,
|
'--positionY': `${position.y * scale - camera.y}px`,
|
||||||
top: `${top}px`,
|
'--randomnessX': randomness.x,
|
||||||
transform: `scale(${growth}) rotate(${randomness.rotation}rad)`,
|
'--randomnessY': randomness.y,
|
||||||
|
rotate: `${randomness.radians}rad`,
|
||||||
|
zIndex,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p>{amount}</p>
|
<p>{amount}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default memo(Damage);
|
||||||
|
|
|
@ -1,25 +1,110 @@
|
||||||
|
@property --hue {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
@property --opacity {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
@property --scale {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
@property --offsetX {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
@property --offsetY {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
@property --randomnessX {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
@property --randomnessY {
|
||||||
|
initial-value: 0;
|
||||||
|
inherits: false;
|
||||||
|
syntax: '<number>';
|
||||||
|
}
|
||||||
|
|
||||||
.damage {
|
.damage {
|
||||||
color: red;
|
--hue: 0;
|
||||||
overflow-wrap: break-word;
|
--opacity: 0.75;
|
||||||
position: fixed;
|
--randomnessX: 0;
|
||||||
margin: 0;
|
--randomnessY: 0;
|
||||||
margin-right: -66%;
|
--scale: 0.35;
|
||||||
text-shadow:
|
--background: hsl(var(--hue) 100% 12.5%);
|
||||||
0px -1px 0px black,
|
--foreground: hsl(var(--hue) 100% 50%);
|
||||||
1px 0px 0px black,
|
animation:
|
||||||
0px 1px 0px black,
|
fade 1.5s linear forwards,
|
||||||
-1px 0px 0px black,
|
grow 1.5s ease-in forwards,
|
||||||
|
move 1.5s cubic-bezier(0.5, 1, 0.89, 1),
|
||||||
0px -2px 0px black,
|
shimmer 250ms infinite ease-in-out
|
||||||
2px 0px 0px black,
|
;
|
||||||
0px 2px 0px black,
|
color: var(--foreground);
|
||||||
-2px 0px 0px black
|
font-size: calc(10px + (var(--magnitude) * 12px));
|
||||||
|
opacity: var(--opacity);
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
position: absolute;
|
||||||
|
margin: 0;
|
||||||
|
text-shadow:
|
||||||
|
0px -1px 0px var(--background),
|
||||||
|
1px 0px 0px var(--background),
|
||||||
|
0px 1px 0px var(--background),
|
||||||
|
-1px 0px 0px var(--background),
|
||||||
|
0px -2px 0px var(--background),
|
||||||
|
2px 0px 0px var(--background),
|
||||||
|
0px 2px 0px var(--background),
|
||||||
|
-2px 0px 0px var(--background)
|
||||||
|
;
|
||||||
|
scale: var(--scale);
|
||||||
|
translate:
|
||||||
|
calc(-50% + (1px * var(--offsetX)) + var(--positionX))
|
||||||
|
calc(-50% + (1px * var(--offsetY)) + var(--positionY))
|
||||||
;
|
;
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
max-width: 66%;
|
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes move {
|
||||||
|
0% {
|
||||||
|
--offsetX: 0;
|
||||||
|
--offsetY: 0;
|
||||||
|
}
|
||||||
|
33%, 91.6% {
|
||||||
|
--offsetX: calc(80 * var(--randomnessX));
|
||||||
|
--offsetY: calc(-1 * (10 + var(--randomnessY) * 90));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade {
|
||||||
|
0% { --opacity: 0.75; }
|
||||||
|
25% { --opacity: 1; }
|
||||||
|
91.6% { --opacity: 1; }
|
||||||
|
100% { --opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes grow {
|
||||||
|
0% { --scale: 0.35; }
|
||||||
|
33% { --scale: 1; }
|
||||||
|
45% { --scale: 1; }
|
||||||
|
40% { --scale: 1.5; }
|
||||||
|
45% { --scale: 1; }
|
||||||
|
91.6% { --scale: 1; }
|
||||||
|
95% { --scale: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% { --hue: 0 }
|
||||||
|
50% { --hue: 30 }
|
||||||
|
100% { --hue: 0 }
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ export default function Damages({camera, damages, scale}) {
|
||||||
damage={damages[key]}
|
damage={damages[key]}
|
||||||
key={key}
|
key={key}
|
||||||
scale={scale}
|
scale={scale}
|
||||||
|
zIndex={key}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
.damages {
|
.damages {
|
||||||
font-family: Cookbook, Georgia, 'Times New Roman', Times, serif;
|
font-family: Joystix, 'Courier New', Courier, monospace;
|
||||||
font-size: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,3 +31,8 @@ body {
|
||||||
font-family: "Cookbook";
|
font-family: "Cookbook";
|
||||||
src: url("/assets/fonts/Cookbook.woff") format("woff");
|
src: url("/assets/fonts/Cookbook.woff") format("woff");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Joystix";
|
||||||
|
src: url("/assets/fonts/Joystix.ttf") format("ttf");
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ export const {
|
||||||
log10,
|
log10,
|
||||||
max,
|
max,
|
||||||
min,
|
min,
|
||||||
|
pow,
|
||||||
round,
|
round,
|
||||||
sign,
|
sign,
|
||||||
sin,
|
sin,
|
||||||
|
@ -317,6 +318,10 @@ export function removeCollinear([...vertices]) {
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const smoothstep = (x) => x * x * (3 - 2 * x);
|
||||||
|
|
||||||
|
export const smootherstep = (x) => x * x * x * (x * (x * 6 - 15) + 10);
|
||||||
|
|
||||||
export function transform(
|
export function transform(
|
||||||
vertices,
|
vertices,
|
||||||
{
|
{
|
||||||
|
|
BIN
public/assets/fonts/Joystix.ttf
Normal file
BIN
public/assets/fonts/Joystix.ttf
Normal file
Binary file not shown.
|
@ -1,4 +1,11 @@
|
||||||
const playerEntity = ecs.lookupPlayerEntity(entity.Owned.owner);
|
const playerEntity = ecs.lookupPlayerEntity(entity.Owned.owner);
|
||||||
if (playerEntity !== other && other.Vulnerable) {
|
if (playerEntity !== other && other.Vulnerable) {
|
||||||
other.Vulnerable.damage({amount: Math.round(60 + Math.random() * 10), position: other.Position.toJSON()})
|
const magnitude = Math.floor(Math.random() * 3)
|
||||||
|
other.Vulnerable.damage({
|
||||||
|
amount: Math.floor(
|
||||||
|
Math.pow(10, magnitude)
|
||||||
|
+ Math.random() * (Math.pow(10, magnitude + 1) - Math.pow(10, magnitude)),
|
||||||
|
),
|
||||||
|
position: other.Position.toJSON(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user