@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
177 lines (152 loc) • 3.65 kB
JavaScript
import Signal from "../../events/signal/Signal.js";
/**
* Structure with event signals for observing changes.
* Implemented using an Array
*/
class ArraySet {
/**
* @readonly
*/
on = {
added: new Signal(),
removed: new Signal()
};
/**
* @private
* @type {T[]}
*/
data = [];
length = 0;
/**
*
* @returns {number}
*/
get size(){
return this.length;
}
/**
*
* @param {Array.<T>} [array=[]]
* @template T
* @constructor
* @property {{added: Signal, removed: Signal}} on
*/
constructor(array) {
if (array !== undefined) {
this.addAll(array);
}
}
/**
*
* @param {T} el
*/
contains(el) {
return this.data.indexOf(el) !== -1;
}
/**
*
* @param {T} el
*/
add(el) {
if (!this.contains(el)) {
this.data.push(el);
this.length++;
this.on.added.dispatch(el);
return true;
} else {
//element already exists
return false;
}
}
/**
*
* @param {T} el
*/
remove(el) {
const index = this.data.indexOf(el);
if (index !== -1) {
this.__removeByIndex(index, el);
return true;
} else {
//element not found
return false;
}
}
/**
*
* @param {Number} index
* @param {T} el
* @private
*/
__removeByIndex(index, el) {
this.data.splice(index, 1);
this.length--;
this.on.removed.dispatch(el);
}
/**
*
* @returns {boolean}
*/
isEmpty() {
return this.length <= 0;
}
/**
* Remove all elements from the set
*/
clear() {
while (!this.isEmpty()) {
this.remove(this.data[0]);
}
}
/**
*
* @param {Array.<T>} elements
*/
addAll(elements) {
const count = elements.length;
for (let i = 0; i < count; i++) {
this.add(elements[i]);
}
}
/**
* Performs a diff on the set and provided collection, elements in the set but not in input are removed and elements in the input but not in the set are added.
* @param {Array.<T>} source
*/
setFromArray(source) {
const data = this.data;
const sourceCopy = source.slice();
for (let i = data.length - 1; i >= 0; i--) {
const element = data[i];
const sourceIndex = sourceCopy.indexOf(element);
if (sourceIndex === -1) {
//element is in the set currently, but not in the collection which we are trying to copy
this.__removeByIndex(i, element);
} else {
//source element is already in the set
sourceCopy.splice(sourceIndex, 1);
}
}
//add the rest to selection
for (let i = 0, l = sourceCopy.length; i < l; i++) {
this.add(sourceCopy[i]);
}
}
/**
*
* @param {function(el:T)} visitor
* @param {*} [thisArg]
*/
forEach(visitor, thisArg) {
for (let i = 0; i < this.length; i++) {
visitor.call(thisArg, this.data[i]);
}
}
/**
*
* @returns {T[]}
*/
asArray() {
return this.data;
}
}
export default ArraySet;