flow: emitter and sound, and some refactor
This commit is contained in:
parent
b8f69732aa
commit
d46bd2a7fa
|
@ -18,6 +18,37 @@ export class Alive extends decorate(Trait) {
|
|||
deathActions: {
|
||||
type: 'actions',
|
||||
traversals: [
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'entity',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'playSound',
|
||||
},
|
||||
{
|
||||
type: 'invoke',
|
||||
args: [
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'entity',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'deathSound',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
|
@ -74,6 +105,7 @@ export class Alive extends decorate(Trait) {
|
|||
},
|
||||
],
|
||||
},
|
||||
deathSound: 'deathSound',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -89,15 +121,20 @@ export class Alive extends decorate(Trait) {
|
|||
this._context.add('entity', this.entity);
|
||||
const actionsJSON = this.params.get('deathActions').toJS();
|
||||
this._deathActions = behaviorItemFromJSON(actionsJSON);
|
||||
this._deathSound = this.params.get('deathSound');
|
||||
const conditionJSON = this.params.get('deathCondition').toJS();
|
||||
this._deathCondition = behaviorItemFromJSON(conditionJSON);
|
||||
this._isDying = false;
|
||||
}
|
||||
|
||||
get deathSound() {
|
||||
return this._deathSound;
|
||||
}
|
||||
|
||||
listeners() {
|
||||
return {
|
||||
|
||||
tookDamage: (damage) => {
|
||||
tookDamage: (damage, source) => {
|
||||
this.entity.life -= damage.amount;
|
||||
// Clamp health between 0 and max.
|
||||
this.entity.life = Math.min(
|
||||
|
@ -112,11 +149,19 @@ export class Alive extends decorate(Trait) {
|
|||
methods() {
|
||||
return {
|
||||
|
||||
die: () => {
|
||||
dieIfPossible: () => {
|
||||
if (this._deathCondition.check(this._context)) {
|
||||
this.entity.forceDeath();
|
||||
}
|
||||
},
|
||||
|
||||
forceDeath: () => {
|
||||
this._isDying = true;
|
||||
this.entity.emit('dying');
|
||||
this._deathActions.on('actionsFinished', () => {
|
||||
if (this.entity.is('existent')) {
|
||||
this.entity.destroy();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -128,10 +173,7 @@ export class Alive extends decorate(Trait) {
|
|||
this._deathActions.tick(this._context, elapsed);
|
||||
}
|
||||
else {
|
||||
if (this._deathCondition.check(this._context)) {
|
||||
// It's a good day to die.
|
||||
this.entity.die();
|
||||
}
|
||||
this.entity.dieIfPossible();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ export class Damaging extends Trait {
|
|||
|
||||
static defaultParams() {
|
||||
return {
|
||||
damagingSound: '',
|
||||
damageSpecs: [],
|
||||
};
|
||||
}
|
||||
|
@ -22,12 +23,17 @@ export class Damaging extends Trait {
|
|||
...damageSpec,
|
||||
};
|
||||
});
|
||||
this._damagingSound = this.params.get('damagingSound');
|
||||
}
|
||||
|
||||
get damageSpecs() {
|
||||
return this._damageSpecs;
|
||||
}
|
||||
|
||||
get damagingSound() {
|
||||
return this._damagingSound;
|
||||
}
|
||||
|
||||
tick(elapsed) {
|
||||
const isCollidingWith = this.entity.isCollidingWith;
|
||||
for (let i = 0; i < isCollidingWith.length; ++i) {
|
||||
|
|
|
@ -1,12 +1,106 @@
|
|||
import * as I from 'immutable';
|
||||
|
||||
import {Trait} from '@avocado/entity';
|
||||
import {behaviorItemFromJSON, createContext} from '@avocado/behavior';
|
||||
import {hasGraphics, TextNodeRenderer} from '@avocado/graphics';
|
||||
|
||||
import {DamageEmitter} from './emitter';
|
||||
|
||||
export class Vulnerable extends Trait {
|
||||
|
||||
static defaultParams() {
|
||||
return {
|
||||
tookDamageActions: {
|
||||
type: 'actions',
|
||||
traversals: [
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'entity',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'emitParticle',
|
||||
},
|
||||
{
|
||||
type: 'invoke',
|
||||
args: [
|
||||
{
|
||||
type: 'literal',
|
||||
value: 'damage',
|
||||
},
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'entity',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'position',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'damage',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'damage',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'from',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'playSound',
|
||||
},
|
||||
{
|
||||
type: 'invoke',
|
||||
args: [
|
||||
{
|
||||
type: 'traversal',
|
||||
steps: [
|
||||
{
|
||||
type: 'key',
|
||||
key: 'damage',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'from',
|
||||
},
|
||||
{
|
||||
type: 'key',
|
||||
key: 'damagingSound',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
static defaultState() {
|
||||
return {
|
||||
damageList: I.Map(),
|
||||
|
@ -16,12 +110,19 @@ export class Vulnerable extends Trait {
|
|||
initialize() {
|
||||
this.damageId = 0;
|
||||
this.damageList = {};
|
||||
this._hasAddedEmitter = false;
|
||||
this._hasAddedEmitterRenderer = false;
|
||||
this._isHydrating = false;
|
||||
this._isInvulnerable = false;
|
||||
this.locks = new Map();
|
||||
if (hasGraphics) {
|
||||
this.emitter = new DamageEmitter();
|
||||
this.setRenderer();
|
||||
this._tookDamageActionsJSON = this.params.get('tookDamageActions').toJS();
|
||||
this.tookDamageActions = [];
|
||||
}
|
||||
|
||||
hydrate() {
|
||||
this._isHydrating = true;
|
||||
this.addEmitter();
|
||||
this.addEmitterRenderer();
|
||||
}
|
||||
|
||||
patchStateStep(key, step) {
|
||||
|
@ -35,7 +136,13 @@ export class Vulnerable extends Trait {
|
|||
case 'damageList':
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
const damage = value[i];
|
||||
this.emitter.emit(this.entity.position, damage);
|
||||
if (this.entity.is('listed')) {
|
||||
damage.from = this.entity.list.findEntity(damage.from);
|
||||
}
|
||||
else {
|
||||
damage.from = undefined;
|
||||
}
|
||||
this.entity.emit('tookDamage', damage, 'client');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -44,6 +151,38 @@ export class Vulnerable extends Trait {
|
|||
}
|
||||
}
|
||||
|
||||
addEmitter() {
|
||||
if (!this._isHydrating) {
|
||||
return;
|
||||
}
|
||||
if (this._hasAddedEmitter) {
|
||||
return;
|
||||
}
|
||||
if (!this.entity.is('emitter')) {
|
||||
return;
|
||||
}
|
||||
this.entity.addEmitter('damage', new DamageEmitter());
|
||||
this._hasAddedEmitter = true;
|
||||
}
|
||||
|
||||
addEmitterRenderer() {
|
||||
if (!this._isHydrating) {
|
||||
return;
|
||||
}
|
||||
if (this._hasAddedEmitterRenderer) {
|
||||
return;
|
||||
}
|
||||
if (!this.entity.is('emitter')) {
|
||||
return;
|
||||
}
|
||||
if (!this.entity.is('staged') || !this.entity.stage) {
|
||||
return;
|
||||
}
|
||||
const renderer = new TextNodeRenderer('.damage', this.entity.stage);
|
||||
this.entity.addEmitterRenderer('damage', renderer);
|
||||
this._hasAddedEmitterRenderer = true;
|
||||
}
|
||||
|
||||
get isInvulnerable() {
|
||||
return this._isInvulnerable;
|
||||
}
|
||||
|
@ -52,38 +191,41 @@ export class Vulnerable extends Trait {
|
|||
this._isInvulnerable = isInvulnerable;
|
||||
}
|
||||
|
||||
setRenderer() {
|
||||
if (this.entity.is('staged') && this.entity.stage) {
|
||||
const renderer = new TextNodeRenderer('.damage', this.entity.stage);
|
||||
this.emitter.addRenderer(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
hooks() {
|
||||
return {
|
||||
|
||||
afterDestructionTickers: () => {
|
||||
return (elapsed) => {
|
||||
if (!hasGraphics) {
|
||||
return true;
|
||||
}
|
||||
this.emitter.tick(elapsed);
|
||||
return !this.emitter.hasParticles();
|
||||
};
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
listeners() {
|
||||
return {
|
||||
|
||||
tookDamage: (damage, source) => {
|
||||
if ('server' === source) {
|
||||
return;
|
||||
}
|
||||
const context = createContext();
|
||||
context.add('entity', this.entity);
|
||||
context.add('damage', damage);
|
||||
const actions = behaviorItemFromJSON(
|
||||
this._tookDamageActionsJSON
|
||||
);
|
||||
const tuple = {
|
||||
context,
|
||||
actions,
|
||||
};
|
||||
this.tookDamageActions.push(tuple);
|
||||
actions.on('actionsFinished', () => {
|
||||
const index = this.tookDamageActions.indexOf(tuple);
|
||||
this.tookDamageActions.splice(tuple);
|
||||
});
|
||||
},
|
||||
|
||||
dying: () => {
|
||||
this._isInvulnerable = true;
|
||||
},
|
||||
|
||||
stageChanged: () => {
|
||||
this.setRenderer();
|
||||
this.addEmitterRenderer();
|
||||
},
|
||||
|
||||
traitsChanged: () => {
|
||||
this.addEmitter();
|
||||
this.addEmitterRenderer();
|
||||
},
|
||||
|
||||
};
|
||||
|
@ -126,9 +268,10 @@ export class Vulnerable extends Trait {
|
|||
isDamage,
|
||||
amount,
|
||||
damageSpec,
|
||||
from: entity.instanceUuid,
|
||||
};
|
||||
this.damageList[entity.instanceUuid].push(damage);
|
||||
this.entity.emit('tookDamage', damage);
|
||||
this.entity.emit('tookDamage', damage, 'server');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -136,8 +279,9 @@ export class Vulnerable extends Trait {
|
|||
}
|
||||
|
||||
tick(elapsed) {
|
||||
if (hasGraphics) {
|
||||
this.emitter.tick(elapsed);
|
||||
for (let i = 0; i < this.tookDamageActions.length; ++i) {
|
||||
const {context, actions} = this.tookDamageActions[i];
|
||||
actions.tick(context, elapsed);
|
||||
}
|
||||
if (this.state.get('damageList').size > 0) {
|
||||
this.state = this.state.set('damageList', I.Map());
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"@avocado/physics": "1.x",
|
||||
"@avocado/resource": "1.x",
|
||||
"@avocado/server": "1.x",
|
||||
"@avocado/sound": "1.x",
|
||||
"@avocado/state": "1.x",
|
||||
"@avocado/timing": "1.x",
|
||||
"@avocado/topdown": "1.x",
|
||||
|
|
BIN
resource/aria-math2.mp3
Executable file
BIN
resource/aria-math2.mp3
Executable file
Binary file not shown.
BIN
resource/ded.wav
Executable file
BIN
resource/ded.wav
Executable file
Binary file not shown.
BIN
resource/fire.wav
Executable file
BIN
resource/fire.wav
Executable file
Binary file not shown.
BIN
resource/shatter.mp3
Executable file
BIN
resource/shatter.mp3
Executable file
Binary file not shown.
BIN
resource/step-grass.ogg
Executable file
BIN
resource/step-grass.ogg
Executable file
Binary file not shown.
|
@ -4,6 +4,16 @@ import {Room} from '@avocado/topdown';
|
|||
function fireJSON(position) {
|
||||
return {
|
||||
traits: {
|
||||
audible: {
|
||||
params: {
|
||||
sounds: {
|
||||
fire: {
|
||||
src: '/fire.wav',
|
||||
volume: 0.05,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
collider: {
|
||||
params: {
|
||||
isSensor: true,
|
||||
|
@ -11,6 +21,7 @@ function fireJSON(position) {
|
|||
},
|
||||
damaging: {
|
||||
params: {
|
||||
damagingSound: 'fire',
|
||||
damageSpecs: [
|
||||
{
|
||||
affinity: 'fire',
|
||||
|
@ -142,6 +153,16 @@ function kittyJSON(position) {
|
|||
}
|
||||
},
|
||||
},
|
||||
audible: {
|
||||
params: {
|
||||
sounds: {
|
||||
deathSound: {
|
||||
src: '/ded.wav',
|
||||
volume: 0.1,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
behaved: {
|
||||
params: {
|
||||
routines: {
|
||||
|
@ -243,6 +264,7 @@ function kittyJSON(position) {
|
|||
direction: 2,
|
||||
},
|
||||
},
|
||||
emitter: {},
|
||||
existent: {},
|
||||
visible: {},
|
||||
mobile: {
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -106,6 +106,12 @@
|
|||
dependencies:
|
||||
socket.io "2.2.0"
|
||||
|
||||
"@avocado/sound@1.x":
|
||||
version "1.0.0"
|
||||
resolved "https://npm.i12e.cha0s.io/@avocado%2fsound/-/sound-1.0.0.tgz#348939934234e1966dcc92bee1bae4829924c95d"
|
||||
dependencies:
|
||||
howler "2.1.2"
|
||||
|
||||
"@avocado/state@1.x":
|
||||
version "1.0.2"
|
||||
resolved "https://npm.i12e.cha0s.io/@avocado%2fstate/-/state-1.0.2.tgz#aef7928bcd512874a31567c7133759708ae6b32f"
|
||||
|
@ -2385,6 +2391,10 @@ homedir-polyfill@^1.0.1:
|
|||
dependencies:
|
||||
parse-passwd "^1.0.0"
|
||||
|
||||
howler@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://npm.i12e.cha0s.io/howler/-/howler-2.1.2.tgz#8433a09d8fe84132a3e726e05cb2bd352ef8bd49"
|
||||
|
||||
hpack.js@^2.1.6:
|
||||
version "2.1.6"
|
||||
resolved "https://npm.i12e.cha0s.io/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
|
||||
|
|
Loading…
Reference in New Issue
Block a user