fun: life and death
This commit is contained in:
parent
fb747b38e6
commit
5c619b26c0
53
app/ecs/components/alive.js
Normal file
53
app/ecs/components/alive.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import Component from '@/ecs/component.js';
|
||||||
|
|
||||||
|
export default class Alive extends Component {
|
||||||
|
instanceFromSchema() {
|
||||||
|
const {ecs} = this;
|
||||||
|
return class AliveInstance extends super.instanceFromSchema() {
|
||||||
|
$$dead = false;
|
||||||
|
acceptDamage(amount) {
|
||||||
|
const health = Math.min(this.maxHealth, Math.max(0, this.health + amount));
|
||||||
|
this.health = health;
|
||||||
|
if (0 === health) {
|
||||||
|
this.die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die() {
|
||||||
|
if (this.$$dead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$$dead = true;
|
||||||
|
const {Ticking} = ecs.get(this.entity);
|
||||||
|
if (Ticking) {
|
||||||
|
const ticker = this.$$death.ticker();
|
||||||
|
ecs.addDestructionDependency(this.entity.id, ticker);
|
||||||
|
Ticking.add(ticker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async load(instance) {
|
||||||
|
// heavy handed...
|
||||||
|
if ('undefined' !== typeof window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.$$death = await this.ecs.readScript(
|
||||||
|
instance.deathScript,
|
||||||
|
{
|
||||||
|
ecs: this.ecs,
|
||||||
|
entity: this.ecs.get(instance.entity),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (0 === instance.maxHealth) {
|
||||||
|
instance.maxHealth = instance.health;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static properties = {
|
||||||
|
deathScript: {
|
||||||
|
defaultValue: '/assets/misc/death-default.js',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
health: {type: 'uint32'},
|
||||||
|
maxHealth: {type: 'uint32'},
|
||||||
|
};
|
||||||
|
}
|
|
@ -20,10 +20,17 @@ export default class Vulnerable extends Component {
|
||||||
instanceFromSchema() {
|
instanceFromSchema() {
|
||||||
const Component = this;
|
const Component = this;
|
||||||
return class VulnerableInstance extends super.instanceFromSchema() {
|
return class VulnerableInstance extends super.instanceFromSchema() {
|
||||||
damages = {};
|
|
||||||
id = 0;
|
id = 0;
|
||||||
Types = DamageTypes;
|
Types = DamageTypes;
|
||||||
damage(specification) {
|
damage(specification) {
|
||||||
|
const {Alive} = Component.ecs.get(this.entity);
|
||||||
|
if (Alive) {
|
||||||
|
switch (specification.type) {
|
||||||
|
case DamageTypes.PAIN: {
|
||||||
|
Alive.acceptDamage(specification.amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Component.markChange(this.entity, 'damage', {[this.id++]: specification});
|
Component.markChange(this.entity, 'damage', {[this.id++]: specification});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,7 +34,7 @@ function Damage({
|
||||||
<div
|
<div
|
||||||
className={styles.damage}
|
className={styles.damage}
|
||||||
style={{
|
style={{
|
||||||
'--magnitude': Math.max(1, Math.floor(Math.log10(amount))),
|
'--magnitude': Math.max(1, Math.floor(Math.log10(Math.abs(amount)))),
|
||||||
'--positionX': `${position.x * scale - camera.x}px`,
|
'--positionX': `${position.x * scale - camera.x}px`,
|
||||||
'--positionY': `${position.y * scale - camera.y}px`,
|
'--positionY': `${position.y * scale - camera.y}px`,
|
||||||
'--randomnessX': randomness.x,
|
'--randomnessX': randomness.x,
|
||||||
|
@ -44,7 +44,7 @@ function Damage({
|
||||||
zIndex,
|
zIndex,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p>{amount}</p>
|
<p>{Math.abs(amount)}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,20 +92,42 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fade {
|
@keyframes fade {
|
||||||
0% { --opacity: 0.75; }
|
0% {
|
||||||
25% { --opacity: 1; }
|
--opacity: 0.75;
|
||||||
91.6% { --opacity: 1; }
|
}
|
||||||
100% { --opacity: 0; }
|
25% {
|
||||||
|
--opacity: 1;
|
||||||
|
}
|
||||||
|
91.6% {
|
||||||
|
--opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
--opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes grow {
|
@keyframes grow {
|
||||||
0% { --scale: 0.35; }
|
0% {
|
||||||
33% { --scale: 1; }
|
--scale: 0.35;
|
||||||
45% { --scale: 1; }
|
}
|
||||||
40% { --scale: 1.5; }
|
33% {
|
||||||
45% { --scale: 1; }
|
--scale: 1;
|
||||||
91.6% { --scale: 1; }
|
}
|
||||||
95% { --scale: 0; }
|
45% {
|
||||||
|
--scale: 1;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
--scale: 1.5;
|
||||||
|
}
|
||||||
|
45% {
|
||||||
|
--scale: 1;
|
||||||
|
}
|
||||||
|
91.6% {
|
||||||
|
--scale: 1;
|
||||||
|
}
|
||||||
|
95% {
|
||||||
|
--scale: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pain {
|
@keyframes pain {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {usePacket} from '@/react/context/client.js';
|
||||||
import {useEcs, useEcsTick} from '@/react/context/ecs.js';
|
import {useEcs, useEcsTick} from '@/react/context/ecs.js';
|
||||||
import {parseLetters} from '@/util/dialogue.js';
|
import {parseLetters} from '@/util/dialogue.js';
|
||||||
|
|
||||||
|
import Damages from './damages.jsx';
|
||||||
import Entity from './entity.jsx';
|
import Entity from './entity.jsx';
|
||||||
|
|
||||||
export default function Entities({
|
export default function Entities({
|
||||||
|
@ -14,6 +15,7 @@ export default function Entities({
|
||||||
}) {
|
}) {
|
||||||
const [ecs] = useEcs();
|
const [ecs] = useEcs();
|
||||||
const [entities, setEntities] = useState({});
|
const [entities, setEntities] = useState({});
|
||||||
|
const [damages, setDamages] = useState({});
|
||||||
usePacket('EcsChange', async () => {
|
usePacket('EcsChange', async () => {
|
||||||
setEntities({});
|
setEntities({});
|
||||||
}, [setEntities]);
|
}, [setEntities]);
|
||||||
|
@ -90,17 +92,18 @@ export default function Entities({
|
||||||
}
|
}
|
||||||
const {damage} = update.Vulnerable || {};
|
const {damage} = update.Vulnerable || {};
|
||||||
if (damage) {
|
if (damage) {
|
||||||
const {damages} = updating[id].Vulnerable;
|
|
||||||
for (const key in damage) {
|
for (const key in damage) {
|
||||||
damages[key] = damage[key];
|
const composite = [id, key].join('-');
|
||||||
damages[key].onClose = () => {
|
damage[key].onClose = () => {
|
||||||
setEntities((entities) => ({
|
setDamages((damages) => {
|
||||||
...entities,
|
const {[composite]: _, ...rest} = damages; // eslint-disable-line no-unused-vars
|
||||||
[id]: ecs.rebuild(id),
|
return rest;
|
||||||
}));
|
})
|
||||||
delete damages[key];
|
|
||||||
};
|
};
|
||||||
|
setDamages((damages) => ({
|
||||||
|
...damages,
|
||||||
|
[composite]: damage[key],
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +131,11 @@ export default function Entities({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{renderables}
|
{renderables}
|
||||||
|
<Damages
|
||||||
|
camera={camera}
|
||||||
|
damages={damages}
|
||||||
|
scale={scale}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {memo} from 'react';
|
import {memo} from 'react';
|
||||||
|
|
||||||
import Dialogues from './dialogues.jsx';
|
import Dialogues from './dialogues.jsx';
|
||||||
import Damages from './damages.jsx';
|
|
||||||
|
|
||||||
function Entity({camera, entity, scale}) {
|
function Entity({camera, entity, scale}) {
|
||||||
return (
|
return (
|
||||||
|
@ -13,13 +12,6 @@ function Entity({camera, entity, scale}) {
|
||||||
scale={scale}
|
scale={scale}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{entity.Vulnerable && (
|
|
||||||
<Damages
|
|
||||||
camera={camera}
|
|
||||||
damages={entity.Vulnerable.damages}
|
|
||||||
scale={scale}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,7 @@ export default async function createHomestead(id) {
|
||||||
VisibleAabb: {},
|
VisibleAabb: {},
|
||||||
});
|
});
|
||||||
const kitty = {
|
const kitty = {
|
||||||
|
Alive: {health: 100},
|
||||||
Behaving: {
|
Behaving: {
|
||||||
routines: {
|
routines: {
|
||||||
initial: '/assets/kitty/initial.js',
|
initial: '/assets/kitty/initial.js',
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const playerEntity = ecs.lookupPlayerEntity(entity.Owned.owner);
|
const playerEntity = ecs.lookupPlayerEntity(entity.Owned.owner);
|
||||||
if (playerEntity !== other && other.Vulnerable) {
|
if (playerEntity !== other && other.Vulnerable) {
|
||||||
const magnitude = Math.floor(Math.random() * 3)
|
const magnitude = Math.floor(Math.random() * 2)
|
||||||
other.Vulnerable.damage({
|
other.Vulnerable.damage({
|
||||||
amount: Math.floor(
|
amount: -Math.floor(
|
||||||
Math.pow(10, magnitude)
|
Math.pow(10, magnitude)
|
||||||
+ Math.random() * (Math.pow(10, magnitude + 1) - Math.pow(10, magnitude)),
|
+ Math.random() * (Math.pow(10, magnitude + 1) - Math.pow(10, magnitude)),
|
||||||
),
|
),
|
||||||
|
|
19
public/assets/misc/death-default.js
Normal file
19
public/assets/misc/death-default.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
const {Sprite, Ticking} = entity;
|
||||||
|
if (Sprite) {
|
||||||
|
const {promise} = transition(
|
||||||
|
entity.Sprite,
|
||||||
|
{
|
||||||
|
scaleX: {
|
||||||
|
duration: 0.25,
|
||||||
|
magnitude: -entity.Sprite.scaleX,
|
||||||
|
},
|
||||||
|
scaleY: {
|
||||||
|
duration: 0.25,
|
||||||
|
magnitude: entity.Sprite.scaleY * 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Ticking.add(promise);
|
||||||
|
await promise;
|
||||||
|
ecs.destroy(entity.id);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user