@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
136 lines (107 loc) • 3.48 kB
JavaScript
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);
}
}