UNPKG

phaser3-rex-plugins

Version:
596 lines (485 loc) 17 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.rexstatemanagerplugin = factory()); })(this, (function () { 'use strict'; var EventEmitterMethods = { setEventEmitter(eventEmitter, EventEmitterClass) { if (EventEmitterClass === undefined) { EventEmitterClass = Phaser.Events.EventEmitter; // Use built-in EventEmitter class by default } this._privateEE = (eventEmitter === true) || (eventEmitter === undefined); this._eventEmitter = (this._privateEE) ? (new EventEmitterClass()) : eventEmitter; return this; }, destroyEventEmitter() { if (this._eventEmitter && this._privateEE) { this._eventEmitter.shutdown(); } return this; }, getEventEmitter() { return this._eventEmitter; }, on() { if (this._eventEmitter) { this._eventEmitter.on.apply(this._eventEmitter, arguments); } return this; }, once() { if (this._eventEmitter) { this._eventEmitter.once.apply(this._eventEmitter, arguments); } return this; }, off() { if (this._eventEmitter) { this._eventEmitter.off.apply(this._eventEmitter, arguments); } return this; }, emit(event) { if (this._eventEmitter && event) { this._eventEmitter.emit.apply(this._eventEmitter, arguments); } return this; }, addListener() { if (this._eventEmitter) { this._eventEmitter.addListener.apply(this._eventEmitter, arguments); } return this; }, removeListener() { if (this._eventEmitter) { this._eventEmitter.removeListener.apply(this._eventEmitter, arguments); } return this; }, removeAllListeners() { if (this._eventEmitter) { this._eventEmitter.removeAllListeners.apply(this._eventEmitter, arguments); } return this; }, listenerCount() { if (this._eventEmitter) { return this._eventEmitter.listenerCount.apply(this._eventEmitter, arguments); } return 0; }, listeners() { if (this._eventEmitter) { return this._eventEmitter.listeners.apply(this._eventEmitter, arguments); } return []; }, eventNames() { if (this._eventEmitter) { return this._eventEmitter.eventNames.apply(this._eventEmitter, arguments); } return []; }, }; var GetValue = function (source, key, defaultValue, altSource) { var isValidSource = source && (typeof source === 'object' || typeof source === 'function'); var isValidAltSource = altSource && (typeof altSource === 'object' || typeof altSource === 'function'); if (!isValidSource && !isValidAltSource) { return defaultValue; } var keyPath = String(key); // Shortcut: // If obj[keyPath] can be read (including prototype chain), return it directly. // This also supports literal keys like "a.b". if (isValidSource && (keyPath in source)) { return source[keyPath]; } if (isValidAltSource && (keyPath in altSource)) { return altSource[keyPath]; } // If there is no dot, we already know it's missing. if (keyPath.indexOf('.') === -1) { return defaultValue; } var keys = keyPath.split('.'); // 1) Try source path first if (isValidSource) { var sourceResult = WalkPath(source, keys, defaultValue); if (sourceResult.found) { return sourceResult.value; } } // 2) Then try altSource path if (isValidAltSource) { var altSourceResult = WalkPath(altSource, keys, defaultValue); if (altSourceResult.found) { return altSourceResult.value; } } return defaultValue; }; var WalkPath = function (source, keys, defaultValue) { var parent = source; var value = defaultValue; var found; for (var index = 0, cnt = keys.length; index < cnt; index++) { var partKey = keys[index]; if (parent && (typeof parent === 'object' || typeof parent === 'function')) { found = (partKey in parent); } else { found = false; } if (!found) { WalkPathResult.found = false; return WalkPathResult; } value = parent[partKey]; parent = value; } WalkPathResult.found = true; WalkPathResult.value = value; return WalkPathResult; }; var WalkPathResult = {}; class StateManagerBase { constructor(config) { this._states = {}; this._stateLock = false; this.enable = true; this._start = undefined; this._state = undefined; this._prevState = undefined; // Event emitter var eventEmitter = GetValue(config, 'eventEmitter', undefined); var EventEmitterClass = GetValue(config, 'EventEmitterClass', undefined); this.setEventEmitter(eventEmitter, EventEmitterClass); } shutdown() { this.destroyEventEmitter(); } destroy() { this.shutdown(); } toJSON() { return { curState: this.state, prevState: this.prevState, enable: this.enable, start: this._start }; } setEnable(e) { if (e === undefined) { e = true; } this.enable = e; return this; } toggleEnable() { this.setEnable(!this.enable); return this; } getState(name) { return this._states[name]; } addState(name, state) { if (typeof (name) !== 'string') { state = name; name = state.name; } this._states[name] = state; return this; } addStates(states) { if (Array.isArray(states)) { for (var i = 0, cnt = states.length; i < cnt; i++) { this.addState(states[i]); } } else { for (var name in states) { this.addState(name, states[name]); } } return this; } removeState(name) { if (this._states.hasOwnProperty(name)) { delete this._states[name]; } return this; } removeAllStates() { for (var name in this._states) { delete this._states[name]; } return this; } set state(newState) { if (!this.enable || this._stateLock) { return; } if (this._state === newState) { return; } this._prevState = this._state; this._state = newState; this._stateLock = true; // Lock state this.emit('statechange', this); if (this._prevState != null) { var state = this.getState(this._prevState); if (state && state.exit) { state.exit(this); } this.emit(`exit_${this._prevState}`, this); } this._stateLock = false; if (this._state != null) { var state = this.getState(this._state); if (state && state.enter) { state.enter(this); } this.emit(`enter_${this._state}`, this); } } get state() { return this._state; } get prevState() { return this._prevState; } get stateList() { return Object.keys(this._states); } start(state) { this._start = state; this._prevState = undefined; this._state = state; // Won't fire statechange events return this; } goto(nextState) { if (nextState != null) { this.state = nextState; } return this; } next() { var state = this.getState(this.state); if (!state || !state.next) { return this; } var nextState; if (typeof (state.next) === 'string') { nextState = state.next; } else { nextState = state.next(this); } this.goto(nextState); return this; } runMethod(methodName, a1, a2, a3, a4, a5) { var state = this.getState(this.state); if (!state) { return undefined; } var fn = state[methodName]; if (!fn) { return undefined; } // Copy from eventemitter3 var len = arguments.length; switch (len) { case 1: return fn(this); case 2: return fn(this, a1); case 3: return fn(this, a1, a2); case 4: return fn(this, a1, a2, a3); case 5: return fn(this, a1, a2, a3, a4); case 6: return fn(this, a1, a2, a3, a4, a5); } var args = Array.prototype.slice.call(arguments); args[0] = this; return fn.apply(undefined, args); } } Object.assign( StateManagerBase.prototype, EventEmitterMethods ); var HasListener = function (eventEmitter, eventName, fn, context, once) { if (once === undefined) { once = false; } var listeners = eventEmitter._events[eventName]; if (!listeners) { return false; } for (var i = 0, cnt = listeners.length; i < cnt; i++) { var listener = listeners[i]; if ((listener.fn === fn) && (listener.context === context) && (listener.once === once) ) { return true; } } return false; }; class StateManager extends StateManagerBase { constructor(config) { super(config); this._scene = GetValue(config, 'scene', undefined); } shutdown() { this.stopUpdate(); this.stopPreUpdate(); this.stopPostUpdate(); this._scene = undefined; super.shutdown(); } getScene() { return this._scene; } update(time, delta) { this.runMethod('update', time, delta); } preupdate(time, delta) { this.runMethod('preupdate', time, delta); } postupdate(time, delta) { this.runMethod('postupdate', time, delta); } startUpdate(scene) { if (!scene) { scene = this._scene; } var eventEmitter = scene.sys.events; if (HasListener(eventEmitter, 'update', this.update, this)) { return this; } this._scene = scene; eventEmitter.on('update', this.update, this); return this; } stopUpdate() { if (!this._scene) { return this; } this._scene.sys.events.off('update', this.update, this); return this; } startPreUpdate(scene) { if (!scene) { scene = this._scene; } var eventEmitter = scene.sys.events; if (HasListener(eventEmitter, 'preupdate', this.preupdate, this)) { return this; } this._scene = scene; eventEmitter.on('preupdate', this.preupdate, this); return this; } stopOreUpdate() { if (!this._scene) { return this; } this._scene.sys.events.off('preupdate', this.preupdate, this); return this; } startPostUpdate(scene) { if (!scene) { scene = this._scene; } var eventEmitter = scene.sys.events; if (HasListener(eventEmitter, 'postupdate', this.postupdate, this)) { return this; } this._scene = scene; eventEmitter.on('postupdate', this.postupdate, this); return this; } stopPostUpdate() { if (!this._scene) { return this; } this._scene.sys.events.off('postupdate', this.postupdate, this); return this; } } var IsNil = function (value) { return value === null || value === undefined; }; var IsObjectLike = function (value) { return value !== null && typeof value === 'object'; }; var NormalizePath = function (path, delimiter) { if (Array.isArray(path)) ; else if (typeof path !== 'string') { path = []; } else if (path.trim() === '') { path = []; } else { path = path.split(delimiter).filter(Boolean); } return path; }; /** * Set a nested value into target by path (mutates target). * * - If keys is a string and does NOT contain delimiter, write directly. * - Intermediate non-plain-object values are always overwritten with {}. * * @param {object} target * @param {string|string[]} keys * @param {*} value * @param {string} [delimiter='.'] * @returns {object} the same target reference */ var SetValue = function (target, keys, value, delimiter = '.') { if (!IsObjectLike(target)) { return target; } // Invalid key: no-op; don't replace root if (IsNil(keys) || keys === '' || (Array.isArray(keys) && keys.length === 0)) { return target; } // Fast path: single key if ( (typeof keys === 'string' && keys.indexOf(delimiter) === -1) || (typeof keys === 'number') ) { target[keys] = value; return target; } var pathSegments = NormalizePath(keys, delimiter); if (pathSegments.length === 0) { return target; } var cursor = target; var pathSegmentsCount = pathSegments.length; for (var index = 0; index < pathSegmentsCount - 1; index++) { var segment = pathSegments[index]; var next = cursor[segment]; if (!IsObjectLike(next)) { // Force overwrite intermediates cursor[segment] = {}; } cursor = cursor[segment]; } cursor[pathSegments[pathSegmentsCount - 1]] = value; return target; }; class StateManagerPlugin extends Phaser.Plugins.BasePlugin { constructor(pluginManager) { super(pluginManager); } start() { var eventEmitter = this.game.events; eventEmitter.on('destroy', this.destroy, this); } add(config) { return new StateManager(config); } } SetValue(window, 'RexPlugins.StateManager', StateManager); return StateManagerPlugin; }));