feat: more dynamic collision semantics

This commit is contained in:
cha0s 2019-06-05 20:20:02 -05:00
parent 226a71f065
commit 63fdbab66a
2 changed files with 67 additions and 4 deletions

View File

@ -36,9 +36,16 @@ export class World extends AbstractWorld {
const {bodyA, bodyB} = pair;
const entityA = this.entities.get(Body.lookupBody(bodyA));
const entityB = this.entities.get(Body.lookupBody(bodyB));
if (entityA && entityB) {
entityA.emit(eventName, entityB);
entityB.emit(eventName, entityA);
if (
entityA && entityA.is('collider')
&& entityB && entityB.is('collider')
) {
if (entityA.collidesWith(entityB)) {
entityA.emit(eventName, entityB);
}
if (entityB.collidesWith(entityA)) {
entityB.emit(eventName, entityA);
}
}
});
});

View File

@ -1,3 +1,4 @@
import {behaviorItemFromJSON, createContext} from '@avocado/behavior';
import {compose} from '@avocado/core';
import {StateProperty, Trait} from '@avocado/entity';
@ -12,6 +13,8 @@ export class Collider extends decorate(Trait) {
collidesWithGroups: [
'default',
],
collisionEndActions: undefined,
collisionStartActions: undefined,
collisionGroup: 'default',
isSensor: false,
}
@ -29,8 +32,10 @@ export class Collider extends decorate(Trait) {
constructor(entity, params, state) {
super(entity, params, state);
this._collisionActions = [];
this._collisionGroup = this.params.collisionGroup;
this._collidesWithGroups = this.params.collidesWithGroups;
this._doesNotCollideWith = [];
this._isCollidingWith = [];
this._isSensor = this.params.isSensor;
}
@ -55,6 +60,22 @@ export class Collider extends decorate(Trait) {
return this._isSensor;
}
pushActionBundle(paramActions, other) {
const actions = behaviorItemFromJSON(paramActions);
const context = createContext();
context.set('entity', this.entity);
context.set('other', other);
const bundle = {
actions,
context,
};
this._collisionActions.push(bundle);
actions.once('actionsFinished', () => {
const index = this._collisionActions.indexOf(bundle);
this._collisionActions.splice(index, 1);
});
}
listeners() {
return {
@ -62,6 +83,9 @@ export class Collider extends decorate(Trait) {
const index = this._isCollidingWith.indexOf(other);
if (-1 !== index) {
this._isCollidingWith.splice(index, 1);
if (this.params.collisionEndActions) {
this.pushActionBundle(this.params.collisionEndActions, other);
}
}
},
@ -69,6 +93,9 @@ export class Collider extends decorate(Trait) {
const index = this._isCollidingWith.indexOf(other);
if (-1 === index) {
this._isCollidingWith.push(other);
if (this.params.collisionStartActions) {
this.pushActionBundle(this.params.collisionStartActions, other);
}
}
},
@ -83,10 +110,17 @@ export class Collider extends decorate(Trait) {
return {
collidesWith: (entity) => {
const collisionGroup = entity.collisionGroup();
if (-1 !== this._doesNotCollideWith.indexOf(entity)) {
return false;
}
const collisionGroup = entity.collisionGroup;
return -1 !== this._collidesWithGroups.indexOf(collisionGroup);
},
doesNotCollideWith: (entity) => {
return !this.entity.collidesWith(entity);
},
releaseAllCollisions: () => {
for (let i = 0; i < this._isCollidingWith.length; i++) {
const entity = this._isCollidingWith[i];
@ -95,6 +129,28 @@ export class Collider extends decorate(Trait) {
this._isCollidingWith = [];
},
setDoesCollideWith: (entity) => {
const index = this._doesNotCollideWith.indexOf(entity);
if (-1 !== index) {
this._doesNotCollideWith.splice(index, 1);
}
},
setDoesNotCollideWith: (entity) => {
if (-1 === this._doesNotCollideWith.indexOf(entity)) {
this._doesNotCollideWith.push(entity);
}
},
};
}
tick(elapsed) {
if (AVOCADO_SERVER) {
for (let i = 0; i < this._collisionActions.length; ++i) {
const {actions, context} = this._collisionActions[i];
actions.tick(context, elapsed);
}
}
}
}