game_actor_component_collision_component.js
import ActorComponent from "./actor_component.js";
import Bounds from "../../vector/bounds.js";
import Triangle from "../../vector/triangle.js";
/**
* @module CollisionComponent
* @fileoverview Contains CollisionComponent class.
*/
/**
* @class
* @extends ActorComponent
* Handles collision checks.
*/
class CollisionComponent extends ActorComponent {
/**
* Create a new collision component.
* @param {Bounds} bounds Bounding box for collision
* @param {string[]} layers Layers to collide with
* @param {string[]} ignoreLayers Layers to ignore
* @constructor
*/
constructor({
bounds = new Bounds(),
layers = ["default"],
ignoreLayers = []
} = {}) {
super();
this.triangles = [];
this._bounds = bounds.copy();
this.layers = new Set(layers);
this.ignoreLayers = new Set(ignoreLayers);
this.triangles.push(
new Triangle(this._bounds.min, this._bounds.topRight, this._bounds.max),
new Triangle(this._bounds.min, this._bounds.bottomLeft, this._bounds.max)
);
}
init() {
if (this.actor.initialized)
this.actor.findOverlappingChunks();
}
//
// Getters
//
/**
* Get the bounds of the collision.
* @returns {Bounds} Bounding box of collision
*/
get bounds() {
return this._bounds.copy();
}
//
// Checks
//
/**
* Check if the collision should occur with another component based on layers
* @param {CollisionComponent} other Collision component to check with
* @returns {boolean} Whether collision can occur
* @private
*/
_checkLayers(other) {
const blacklist1 = new Set([...this.ignoreLayers].filter(a => other.layers.has(a)));
if (blacklist1.size > 0)
return false;
const blacklist2 = new Set([...other.ignoreLayers].filter(a => this.layers.has(a)));
if (blacklist2.size > 0)
return false;
const whitelist = new Set([...other.layers].filter(a => other.layers.has(a)));
return whitelist.size > 0;
}
/**
* Check for collision with another component.
* @param {CollisionComponent} other Collision component to check with
* @returns {Object} Object containing collision result
* @param {Vec2} pos The position to attempt to move to
*/
check(other, pos) {
const result = {
result: false
};
if (!this._checkLayers(other))
return result;
for (let t1 of this.triangles) {
t1 = t1.transform(this.actor.getTransformMatrix());
for (let t2 of other.triangles) {
const mat = other.actor.getTransformMatrix(false);
mat3.multiply(mat, pos.toTranslationMatrix(), mat);
t2 = t2.transform(mat);
const r = t1.check(t2);
if (r.result) {
r.actor = this.actor;
this.actor.doEvent("collide", other.actor);
other.actor.doEvent("collide", this.actor);
return r;
}
}
}
return result;
}
drawDebug(ctx) {
const transform = this.actor.getTransformMatrix(false);
for (const triangle of this.triangles)
triangle.transform(transform).drawDebug(ctx);
}
}
export default CollisionComponent;