UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

136 lines (107 loc) 3.48 kB
import { assert } from "../../../../core/assert.js"; import { weightedRandomFromArray } from "../../../../core/collection/array/weightedRandomFromArray.js"; import { seededRandom } from "../../../../core/math/random/seededRandom.js"; import { Behavior } from "../Behavior.js"; import { WeightedElement } from "./WeightedElement.js"; /** * Picks a random behavior to execute. * The selection is done during initialization, and that selected behavior will then run to completion. * NOTE: Weights are relative, so they don't need to add up to any specific value. * * @example * const behavior = WeightedRandomBehavior.from([ * WeightedElement.from(A, 1), // A is some behavior * WeightedElement.from(B, 70), // B is some behavior * ]); // B will be 70 times more likely to be picked than A * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class WeightedRandomBehavior extends Behavior { /** * * @type {WeightedElement<Behavior>[]} elements * @private */ __elements = []; /** * * @type {function(): number} * @private */ __random = seededRandom(91512); /** * * @type {Behavior|undefined} * @private */ __selected = undefined; /** * * @param {number} v */ setRandomSeed(v) { this.__random.setCurrentSeed(v); } /** * * @param {WeightedElement<Behavior>[]} elements Must not be empty */ setElements(elements) { assert.defined(elements, 'elements'); assert.isArray(elements, 'elements'); assert.greaterThan(elements.length, 0, 'elements.length === 0'); this.__elements = []; const count = elements.length; for (let i = 0; i < count; i++) { const element = elements[i]; this.addElement(element); } } /** * * @param {WeightedElement<Behavior>} e */ addElement(e) { assert.defined(e, 'element'); assert.notNull(e, 'element'); assert.isObject(e, 'element'); assert.equal(e.isWeightedElement, true, 'element.isWeightedElement !== true'); assert.equal(e.data.isBehavior, true, 'element.data.isWeightedElement !== true'); this.__elements.push(e); } /** * * @param {WeightedElement<Behavior>[]} elements * @returns {WeightedRandomBehavior} */ static from(elements) { assert.defined(elements, 'elements'); const r = new WeightedRandomBehavior(); r.setElements(elements); return r; } __select() { /** * * @type {WeightedElement<Behavior>|undefined} */ const weightedElement = weightedRandomFromArray(this.__elements, this.__random, WeightedElement.getWeight); const selected = weightedElement.data; assert.equal(selected.isBehavior, true, 'selected.isBehavior !== true'); this.__selected = selected; } initialize(context) { super.initialize(context); this.__select(); this.__selected.initialize(context); } finalize() { super.finalize(); this.__selected.finalize(); this.__selected = undefined; } tick(timeDelta) { return this.__selected.tick(timeDelta); } }