UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

302 lines (229 loc) • 5.67 kB
import { assert } from "../../../core/assert.js"; import { isArrayEqualStrict } from "../../../core/collection/array/isArrayEqualStrict.js"; import { computeStringHash } from "../../../core/primitives/strings/computeStringHash.js"; /** * Stores textual tags, useful for tagging entities. */ export class Tag { /** * @private * @type {string[]} */ values = []; /** * * @returns {number} */ get count() { return this.values.length; } /** * * @param {number} i * @returns {string} */ get(i) { assert.isNonNegativeInteger(i, 'i'); return this.values[i]; } clear() { this.values.splice(0, this.values.length); } /** * Once the tag is added to the dataset it should be considered immutable, hence why this method is protected * @param {string} value * @returns {boolean} */ add(value) { assert.isString(value, 'value'); if (this.contains(value)) { return false; } this.values.push(value); return true; } /** * Add multiple tags * @param {string[]} values */ addAll(values) { assert.isArray(values,'values'); const n = values.length; for (let i = 0; i < n; i++) { const value = values[i]; this.add(value); } } /** * * @returns {string} */ getFirst() { return this.values[0]; } /** * * @param {string} value * @returns {boolean} */ contains(value) { assert.isString(value, 'value'); return this.values.indexOf(value) !== -1; } /** * * @param {string[]} values */ containsAll(values) { assert.isArray(values, 'values'); const search_value_count = values.length; const these_values = this.values; const these_values_count = these_values.length; let i = 0, j = 0; main: for (; i < search_value_count; i++) { const v = values[i]; for (j = 0; j < these_values_count; j++) { const tag = these_values[j]; if (tag === v) { continue main; } } //tag not found return false; } return true; } /** * * @param {string[]} values * @returns {boolean} */ containsOneOf(values) { const s0 = this.values; const s1 = values; const n0 = s0.length; const n1 = s1.length; for (let i = 0; i < n0; i++) { const v0 = s0[i]; for (let j = 0; j < n1; j++) { const v1 = s1[j]; if (v0 === v1) { return true; } } } return false; } /** * NOTE: do not modify this value * @returns {string[]} */ getValues() { return this.values; } /** * * @param {function(string)} visitor * @param {*} [thisArg] */ traverse(visitor, thisArg) { this.values.forEach(visitor, thisArg); } /** * * @return {number} */ hash() { let hash = 0; const values = this.values; const n = values.length; for (let i = 0; i < n; i++) { const value = values[i]; hash = ((hash << 5) - hash) + computeStringHash(value); hash |= 0; // Convert to 32bit integer } return hash; } /** * * @param {Tag} other * @return {boolean} */ equals(other) { return isArrayEqualStrict(this.values, other.values); } toJSON() { return this.values; } /** * * @param {string[]|string} json */ fromJSON(json) { this.clear(); if (typeof json === "string") { this.add(json); } else { assert.isArray(json, 'json'); const n = json.length; for (let i = 0; i < n; i++) { this.add(json[i]); } } } /** * Find all entities that contain specified tags. Entity must have every tag to qualify * @param {string[]} tags * @param {EntityComponentDataset} ecd * @returns {number[]} entities */ static find(tags, ecd) { /** * * @type {number[]} */ const result = []; ecd.traverseComponents(Tag, (tag, entity) => { if (tag.containsAll(tags)) { result.push(entity); } }); return result; } /** * * @param {string} tag * @returns {Tag} */ static fromOne(tag) { const r = new Tag(); r.add(tag); return r; } /** * * @param json * @returns {Tag} */ static fromJSON(json) { const r = new Tag(); r.fromJSON(json); return r; } /** * Utility constructor * @param {string} label * @return {Tag} */ static from(...label){ const r = new Tag(); r.addAll(label); return r; } } /** * @readonly * @type {string} */ Tag.typeName = "Tag"; export default Tag;