fun: das a lodda damage
This commit is contained in:
parent
091e19c7de
commit
08dfe8ac29
|
@ -1,4 +1,24 @@
|
|||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Vulnerable extends Component {
|
||||
mergeDiff(original, update) {
|
||||
const merged = {};
|
||||
if (update.damage) {
|
||||
merged.damage = {
|
||||
...original.damage,
|
||||
...update.damage,
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
instanceFromSchema() {
|
||||
const Component = this;
|
||||
return class VulnerableInstance extends super.instanceFromSchema() {
|
||||
damages = {};
|
||||
id = 0;
|
||||
damage(specification) {
|
||||
Component.markChange(this.entity, 'damage', {[this.id++]: specification});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
72
app/react/components/dom/damage.jsx
Normal file
72
app/react/components/dom/damage.jsx
Normal file
|
@ -0,0 +1,72 @@
|
|||
import {useEffect, useState} from 'react';
|
||||
|
||||
import {useRadians} from '@/react/context/radians.js';
|
||||
|
||||
import styles from './damage.module.css';
|
||||
|
||||
export default function Damage({
|
||||
camera,
|
||||
damage,
|
||||
scale,
|
||||
}) {
|
||||
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({
|
||||
hue: Math.random() * 10,
|
||||
x: 1 * (Math.random() - 0.5),
|
||||
y: 150 * (Math.random()),
|
||||
rotation: Math.random() * (Math.PI / 8) - (Math.PI / 16),
|
||||
});
|
||||
const radians = useRadians();
|
||||
useEffect(() => {
|
||||
setHue(15 + (Math.cos(radians * 4) * (5 + randomness.hue)));
|
||||
}, [radians, randomness.hue]);
|
||||
useEffect(() => {
|
||||
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 () => {
|
||||
cancelAnimationFrame(handle);
|
||||
};
|
||||
}, [damage, randomness.x, randomness.y]);
|
||||
|
||||
const {amount, position} = damage;
|
||||
const left = position.x * scale - camera.x + offset.x;
|
||||
const top = position.y * scale - camera.y + offset.y;
|
||||
return (
|
||||
<div
|
||||
className={styles.damage}
|
||||
style={{
|
||||
color: `hsl(${hue} 100% 50%)`,
|
||||
left: `${left}px`,
|
||||
opacity,
|
||||
top: `${top}px`,
|
||||
transform: `scale(${growth}) rotate(${randomness.rotation}rad)`,
|
||||
}}
|
||||
>
|
||||
<p>{amount}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
25
app/react/components/dom/damage.module.css
Normal file
25
app/react/components/dom/damage.module.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
.damage {
|
||||
color: red;
|
||||
overflow-wrap: break-word;
|
||||
position: fixed;
|
||||
margin: 0;
|
||||
margin-right: -66%;
|
||||
text-shadow:
|
||||
0px -1px 0px black,
|
||||
1px 0px 0px black,
|
||||
0px 1px 0px black,
|
||||
-1px 0px 0px black,
|
||||
|
||||
0px -2px 0px black,
|
||||
2px 0px 0px black,
|
||||
0px 2px 0px black,
|
||||
-2px 0px 0px black
|
||||
|
||||
;
|
||||
transform: translate(-50%, -50%);
|
||||
user-select: none;
|
||||
max-width: 66%;
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
22
app/react/components/dom/damages.jsx
Normal file
22
app/react/components/dom/damages.jsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import styles from './damages.module.css';
|
||||
|
||||
import Damage from './damage.jsx';
|
||||
|
||||
export default function Damages({camera, damages, scale}) {
|
||||
const elements = [];
|
||||
for (const key in damages) {
|
||||
elements.push(
|
||||
<Damage
|
||||
camera={camera}
|
||||
damage={damages[key]}
|
||||
key={key}
|
||||
scale={scale}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (0 === elements.length) {
|
||||
return false;
|
||||
}
|
||||
return <div className={styles.damages}>{elements}</div>;
|
||||
}
|
||||
|
4
app/react/components/dom/damages.module.css
Normal file
4
app/react/components/dom/damages.module.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
.damages {
|
||||
font-family: Cookbook, Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 40px;
|
||||
}
|
|
@ -88,6 +88,21 @@ export default function Entities({
|
|||
};
|
||||
}
|
||||
}
|
||||
const {damage} = update.Vulnerable || {};
|
||||
if (damage) {
|
||||
const {damages} = updating[id].Vulnerable;
|
||||
for (const key in damage) {
|
||||
damages[key] = damage[key];
|
||||
damages[key].onClose = () => {
|
||||
setEntities((entities) => ({
|
||||
...entities,
|
||||
[id]: ecs.rebuild(id),
|
||||
}));
|
||||
delete damages[key];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
setEntities((entities) => {
|
||||
for (const id in deleting) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {memo} from 'react';
|
||||
|
||||
import Dialogues from './dialogues.jsx';
|
||||
import Damages from './damages.jsx';
|
||||
|
||||
function Entity({camera, entity, scale}) {
|
||||
return (
|
||||
|
@ -12,6 +13,13 @@ function Entity({camera, entity, scale}) {
|
|||
scale={scale}
|
||||
/>
|
||||
)}
|
||||
{entity.Vulnerable && (
|
||||
<Damages
|
||||
camera={camera}
|
||||
damages={entity.Vulnerable.damages}
|
||||
scale={scale}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const playerEntity = ecs.lookupPlayerEntity(entity.Owned.owner);
|
||||
if (playerEntity !== other && other.Vulnerable) {
|
||||
ecs.destroy(other.id);
|
||||
other.Vulnerable.damage({amount: Math.round(60 + Math.random() * 10), position: other.Position.toJSON()})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user