var slib = window.slib = window.slib || {};var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); /** * sLib * Base TS game lib, S for simple, standard, stable, and Sean; * 通用基础库,设计理念为所有项目共用的一些基础方法,不于具体业务相关联,纯TS实现,不对外部及任何引擎有依赖 * @author Sean */ /** * sLib * Base TS game lib, S for simple, standard, stable, and Sean; * 通用基础库,设计理念为所有项目共用的一些基础方法,不于具体业务相关联,纯TS实现,不对外部及任何引擎有依赖 * @author Sean */ (function (slib) { var LIB_NAME = "[slib]"; /**控制logI,logW,logE输出的开关 */ slib.LOG_ENABLE = true; function logI(message) { if (message === void 0) { message = ""; } var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } slib.LOG_ENABLE && console.info(LIB_NAME, StringUtil.format.apply(StringUtil, __spreadArray([message], args, false))); } slib.logI = logI; function logW(message) { if (message === void 0) { message = ""; } var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } slib.LOG_ENABLE && console.warn(LIB_NAME, StringUtil.format.apply(StringUtil, __spreadArray([message], args, false))); } slib.logW = logW; function logE(message) { if (message === void 0) { message = ""; } var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } slib.LOG_ENABLE && console.error(LIB_NAME, StringUtil.format.apply(StringUtil, __spreadArray([message], args, false))); } slib.logE = logE; var StringUtil = /** @class */ (function () { function StringUtil() { } /** * 是否为无效字符串,null或undefined都会返回true * @param str */ StringUtil.isEmpty = function (str) { return TypeUtil.isUndefinedOrNull(str) || str.length == 0; }; /** * 格式化,类似c++的sprintf * @param text * @param formatParam */ StringUtil.format = function (text) { var formatParam = []; for (var _i = 1; _i < arguments.length; _i++) { formatParam[_i - 1] = arguments[_i]; } if (text) { return StringUtil.formatWithArray(text, formatParam); } return ""; }; StringUtil.formatWithArray = function (text, formatParam, paramCnt) { var maxParamCnt = formatParam.length; if (typeof paramCnt != "undefined" && paramCnt < maxParamCnt) { maxParamCnt = paramCnt; } return text.replace(/(\{\d+\})/g, function (substr) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var index = Number(substr.substr(1, substr.length - 2)); if (index >= 0 && index < maxParamCnt) { return formatParam[index]; } return substr; }); }; /** * 获取字符串长度,中文字当2个字符 * @static * @param {string} str * @return {*} {number} * @memberof StringUtil */ StringUtil.getStringLen = function (str) { var len = 0, charCode = 0; for (var i = 0; i < str.length; i++) { charCode = str.charCodeAt(i); if (charCode >= 0 && charCode <= 128) len += 1; else len += 2; } return len; }; /** * 将指定的秒数转换为 hh:mm:ss 的字符串 * @param sec 秒数 */ StringUtil.formatTimeBySecs = function (secs) { var hour = Math.floor(secs / 3600); var min = Math.floor((secs - (hour * 3600)) / 60); var sec = Math.floor(secs % 60); var hourStr = (hour < 10 ? '0' : '') + hour.toString(); var minStr = (min < 10 ? '0' : '') + min.toString(); var secStr = (sec < 10 ? '0' : '') + sec.toString(); return hourStr + ':' + minStr + ':' + secStr; }; return StringUtil; }()); slib.StringUtil = StringUtil; var TypeUtil = /** @class */ (function () { function TypeUtil() { } /**是否为undefined或null */ TypeUtil.isUndefinedOrNull = function (obj) { return (typeof obj) === 'undefined' || obj == null; }; return TypeUtil; }()); slib.TypeUtil = TypeUtil; var ArrayUtil = /** @class */ (function () { function ArrayUtil() { } /** * 从目标数组中删掉指定的元素 * @param list 目标数组 * @param element 要删除的元素 * @returns 要删除的元素,若不在目标数组中,则返回null */ ArrayUtil.removeElement = function (list, element) { var index = list.indexOf(element); if (index >= 0) { list.splice(index, 1); } else { return null; } }; return ArrayUtil; }()); slib.ArrayUtil = ArrayUtil; var MathUtil = /** @class */ (function () { function MathUtil() { } /** * 获得[n-m)区间中的一个随机整数,包括n,不包括m */ MathUtil.getRandom = function (n, m) { return n + Math.floor(Math.random() * (m - n)); }; /**是否为有效数据,null,undefined,NaN,null皆为无效 */ MathUtil.isValidNumber = function (num) { return !TypeUtil.isUndefinedOrNull(num) && num != NaN; }; /** * 限制value的值在min和max之间, 如果value小于min,返回min。 如果value大于max,返回max,否则返回value */ MathUtil.clamp = function (value, min, max) { return value < min ? min : (value > max ? max : value); }; /** * 插值 * @param min 最小值 * @param max 最大值 * @param t 系数 * @returns 所求值 */ MathUtil.lerp = function (min, max, t) { if (t > 0 && t < 1) { return (max - min) * t + min; } else { return t <= 0 ? min : max; } }; /** * 将弧度转化为角度 * @param rad 弧度 */ MathUtil.getDegreeByRadian = function (rad) { return rad * 180 / Math.PI; }; /** * 将角度转化为弧度 * @param degree 角度 */ MathUtil.getRadianByDegree = function (degree) { return degree * Math.PI / 180; }; /** * 根据向量求角度 * @param x * @param y * @returns 返回值为与x轴的夹角,带正负号,正值为x轴逆时针方向,负值为x轴顺时针方向 */ MathUtil.getDegByVec = function (x, y) { var rad = Math.atan2(y, x); return rad * 180 / Math.PI; }; /** * 根据向量求弧度 * @param x * @param y * @returns 返回值为与x轴的夹角,带正负号,正值为x轴逆时针方向,负值为x轴顺时针方向 */ MathUtil.getRadianByVec = function (x, y) { return Math.atan2(y, x); }; /**根据向量求角度,返回值在 [0,360]之间,代表从x轴逆时针方向旋转的角度 */ MathUtil.get360DegByVec = function (x, y) { var deg = this.getDegByVec(x, y); if (deg < 0) { deg = 360 + deg; } return deg; }; /**根据向量求弧度,返回值在 [0,2Pi]之间,代表从x轴逆时针方向旋转的弧度 */ MathUtil.get2PiRadianByVec = function (x, y) { var rad = this.getRadianByVec(x, y); if (rad < 0) { rad += (Math.PI * 2); } return rad; }; /** * 根据权重列表进行一次随机,返回命中的索引 * @param list 权重列表 * @returns 命中的索引 */ MathUtil.randomTestByWeightList = function (list) { var total = 0; var pointList = []; for (var i = 0; i < list.length; ++i) { var point = slib.math.Vector.get(); point.setValue(total, total + list[i] - 1); pointList.push(point); total += list[i]; } var r = this.getRandom(0, total); var index = -1; for (var i = 0; i < pointList.length; ++i) { if (r >= pointList[i].x && r <= pointList[i].y) { index = i; break; } } for (var i = 0; i < pointList.length; ++i) { slib.math.Vector.recover(pointList[i]); } pointList.length = 0; return index; }; return MathUtil; }()); slib.MathUtil = MathUtil; })(slib || (slib = {})); (function (slib) { var astar; (function (astar) { /**格子节点 */ var GridNode = /** @class */ (function () { //#endregion /** * * @param x * @param y * @param weight 权重,计算G值时使用此值,越大代表移动代价越高,0表示为障碍物 */ function GridNode(x, y, weight) { //#region 内部使用,外部无需关注 /**是否已遍历过,内部使用,外部无需关注 */ this.visited = false; /**父节点 内部使用,外部无需关注 */ this.parent = null; /**是否在关闭列表中 内部使用,外部无需关注*/ this.closed = false; /**内部使用,外部无需关注 */ this.h = 0; /**内部使用,外部无需关注 */ this.g = 0; /**内部使用,外部无需关注 */ this.f = 0; this._x = x; this._y = y; this.weight = weight; } Object.defineProperty(GridNode.prototype, "x", { get: function () { return this._x; }, enumerable: false, configurable: true }); Object.defineProperty(GridNode.prototype, "y", { get: function () { return this._y; }, enumerable: false, configurable: true }); /**内部使用,外部无需关注 */ GridNode.prototype.cleanNode = function () { this.f = 0; this.g = 0; this.h = 0; this.visited = false; this.closed = false; this.parent = null; }; Object.defineProperty(GridNode.prototype, "isWall", { /**是否是障碍物 */ get: function () { return this.weight === 0; }, enumerable: false, configurable: true }); /**移动代价,用于计算G值 */ GridNode.prototype.getCost = function (fromNeighbor) { // Take diagonal weight into consideration. if (fromNeighbor && fromNeighbor.x != this.x && fromNeighbor.y != this.y) { // return this._weight * 1.41421; return this.weight * 1.4; } return this.weight; }; GridNode.prototype.toString = function () { return '[GridNode x:' + this._x.toString() + ", y:" + this._y.toString() + "]"; }; return GridNode; }()); astar.GridNode = GridNode; /**A星格子网格类 */ var Graph = /** @class */ (function () { /** * * @param gridIn 权重的二维数组,格式为[x][y],第一个下标为列数,第二个下表为行数 * @param diagonal 是否允许斜向移动 */ function Graph(gridIn, diagonal) { if (diagonal === void 0) { diagonal = false; } this._neighborsRet = []; // this._nodes = []; this._diagonal = diagonal; this._grid = []; for (var x = 0; x < gridIn.length; ++x) { this._grid[x] = []; for (var y = 0, col = gridIn[x]; y < col.length; ++y) { var node = new GridNode(x, y, col[y]); this._grid[x][y] = node; node.cleanNode(); } } this._dirtyNodes = []; } Object.defineProperty(Graph.prototype, "diagonal", { get: function () { return this._diagonal; }, enumerable: false, configurable: true }); Object.defineProperty(Graph.prototype, "grid", { get: function () { return this._grid; }, enumerable: false, configurable: true }); Graph.prototype.cleanDirty = function () { for (var i = 0; i < this._dirtyNodes.length; i++) { this._dirtyNodes[i].cleanNode(); } this._dirtyNodes = []; }; Graph.prototype.markDirty = function (node) { this._dirtyNodes.push(node); }; /** * 获取目标格子相邻的格子 * @param node * @returns 注意返回的数组为唯一实例,会随着下一次调用改变,请及时处理 */ Graph.prototype.neighbors = function (node) { var ret = this._neighborsRet; ret = []; var x = node.x; var y = node.y; var grid = this.grid; // West if (grid[x - 1] && grid[x - 1][y]) { ret.push(grid[x - 1][y]); } // East if (grid[x + 1] && grid[x + 1][y]) { ret.push(grid[x + 1][y]); } // South if (grid[x] && grid[x][y - 1]) { ret.push(grid[x][y - 1]); } // North if (grid[x] && grid[x][y + 1]) { ret.push(grid[x][y + 1]); } if (this.diagonal) { // Southwest if (grid[x - 1] && grid[x - 1][y - 1]) { ret.push(grid[x - 1][y - 1]); } // Southeast if (grid[x + 1] && grid[x + 1][y - 1]) { ret.push(grid[x + 1][y - 1]); } // Northwest if (grid[x - 1] && grid[x - 1][y + 1]) { ret.push(grid[x - 1][y + 1]); } // Northeast if (grid[x + 1] && grid[x + 1][y + 1]) { ret.push(grid[x + 1][y + 1]); } } return ret; }; return Graph; }()); astar.Graph = Graph; function pathTo(node) { var curr = node; var path = []; while (curr.parent) { path.unshift(curr); curr = curr.parent; } return path; } astar.pathTo = pathTo; var AStar = /** @class */ (function () { function AStar() { } /** * * @param graph 寻路网格 * @param start 起点 * @param end 终点 * @param closest 当目标点不可到达时,是否寻路至最近的点 * @param heuristic 启发函数,用于在寻路时估计当前格子到终点的距离,即计算H值,默认使用manhattan方法 * @returns 找不到路径时返回null */ AStar.prototype.search = function (graph, start, end, closest, heuristic) { if (closest === void 0) { closest = false; } if (heuristic === void 0) { heuristic = null; } graph.cleanDirty(); heuristic = heuristic || heuristics.manhattan; var openHeap = this.getHeap(); var closestNode = start; start.h = heuristic(start, end); graph.markDirty(start); openHeap.push(start); //遍历open列表 while (openHeap.size > 0) { //取出一个f值最小的节点 var currentNode = openHeap.pop(); //到达终点了 if (currentNode === end) { return pathTo(end); } //放入close列表,尝试向周围行走 currentNode.closed = true; var neighbors = graph.neighbors(currentNode); for (var i = 0, il = neighbors.length; i < il; i++) { var neighbor = neighbors[i]; if (neighbor.closed || neighbor.isWall) { continue; //已经行走过,或是不能行走,跳过 } var gScore = currentNode.g + neighbor.getCost(currentNode); //当前行走节点的g值 + 走到这个格子花费的g值 var beenVisited = neighbor.visited; if (!beenVisited || gScore < neighbor.g) { neighbor.visited = true; //标记一下,已经被父节点尝试过 neighbor.parent = currentNode; neighbor.h = neighbor.h || heuristic(neighbor, end); neighbor.g = gScore; neighbor.f = neighbor.g + neighbor.h; graph.markDirty(neighbor); if (closest) { if (neighbor.h < closestNode.h || (neighbor.h === closestNode.h) && neighbor.g < closestNode.g) { //距离更小 或是 更容易走到, 更新最近的节点 closestNode = neighbor; } } if (!beenVisited) { openHeap.push(neighbor); //待探索的格子,加入到open列表中 } else { openHeap.rescoreElement(neighbor, true); //g值变小了,父节点更新了,重排二叉堆 } } } } if (closest) { return pathTo(closestNode); } return null; }; AStar.prototype.getHeap = function () { return new slib.math.BinaryHeap(function (node) { return node.f; }); }; return AStar; }()); astar.AStar = AStar; var heuristics; (function (heuristics) { function manhattan(pos0, pos1) { return Math.abs(pos1.x - pos0.x) + Math.abs(pos1.y - pos0.y); } heuristics.manhattan = manhattan; })(heuristics = astar.heuristics || (astar.heuristics = {})); })(astar = slib.astar || (slib.astar = {})); })(slib || (slib = {})); (function (slib) { var comp; (function (comp) { /**摇杆数据模型,设计思路为,传入摇杆半径和按压点,可获得摇杆坐标和力度数据 * 使用方法,设置半径和基准点,当操作摇杆时调用tap接口传入按压点,释放时调用release接口,修改基准点时调用setStartPos接口,所有坐标都需要与基准点在同一坐标系下 */ var JoyStick = /** @class */ (function () { /** * @param radius 最大半径 */ function JoyStick(radius, startX, startY) { if (radius === void 0) { radius = 100; } if (startX === void 0) { startX = 0; } if (startY === void 0) { startY = 0; } this.destroyed = false; this._startX = 0; this._startY = 0; this._radius = 100; this._stickX = 0; this._stickY = 0; this._tapping = false; this._radius = radius; this.setStartPos(startX, startY); } Object.defineProperty(JoyStick.prototype, "startX", { /**基准点X */ get: function () { return this._startX; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "startY", { /**基准点Y */ get: function () { return this._startY; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "radius", { get: function () { return this._radius; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "strengthX", { /**X轴方向力度,正负代表方向,范围 0-1 */ get: function () { return (this._stickX - this._startX) / this._radius; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "strengthY", { /**Y轴方向力度,正负代表方向,范围 0-1 */ get: function () { return (this._stickY - this._startY) / this._radius; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "stickX", { /**摇杆坐标X */ get: function () { return this._stickX; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "stickY", { /**摇杆坐标Y */ get: function () { return this._stickY; }, enumerable: false, configurable: true }); Object.defineProperty(JoyStick.prototype, "tapping", { /**是否在按压中 */ get: function () { return this._tapping; }, enumerable: false, configurable: true }); /**修改摇杆基准点 */ JoyStick.prototype.setStartPos = function (posX, posY) { this._startX = posX; this._startY = posY; if (this._tapping) { this.tap(this._stickX, this._stickY); //重新刷新下 } else { this._stickX = this._startX; this._stickY = this._startY; } }; JoyStick.prototype.tap = function (tapX, tapY) { this._tapping = true; var vec = slib.math.Vector.get().setValue(tapX - this._startX, tapY - this._startY); if (vec.x * vec.x + vec.y * vec.y > this._radius * this._radius) { //效果等价于比较距离,用平方数比较可以减少一次开方运算 vec.normalize(); vec.scale(this._radius); } this._stickX = this._startX + vec.x; this._stickY = this._startY + vec.y; slib.math.Vector.recover(vec); // console.log("start", this._startX, this._startY, "stick", this._stickX, this._stickY); }; JoyStick.prototype.release = function () { if (this._tapping) { this._tapping = false; this._stickX = this._startX; this._stickY = this._startY; } }; JoyStick.prototype.destroy = function () { this.destroyed = true; }; return JoyStick; }()); comp.JoyStick = JoyStick; })(comp = slib.comp || (slib.comp = {})); })(slib || (slib = {})); (function (slib) { var config; (function (config) { /**配置基类 */ var ConfigBase = /** @class */ (function () { function ConfigBase() { } return ConfigBase; }()); config.ConfigBase = ConfigBase; })(config = slib.config || (slib.config = {})); })(slib || (slib = {})); (function (slib) { var config; (function (config) { /**配置管理器,使用方法:setTable 后 parse, 即可获取数据 */ var ConfigManager = /** @class */ (function () { function ConfigManager() { this._map = null; this.m_temp = new Map(); } Object.defineProperty(ConfigManager.prototype, "map", { /**所有的配置都在这里 */ get: function () { return this._map; }, enumerable: false, configurable: true }); /** * 传入配置表数据,传入后需调用parse方法,将传入的数据解析为对应的类 * @param name 表的名字,区分表用 * @param data 数据数组,json导出为数组形式,解析后的object * @param cls 对应的类 */ ConfigManager.prototype.setTable = function (name, data, cls) { this.m_temp.set(name, { data: data, cls: cls }); }; /**获取某张表的配置数量 */ ConfigManager.prototype.getTableCount = function (name) { return this._map[name]["#count"]; }; /**获取某张表的最大ID */ ConfigManager.prototype.getTableMaxID = function (name) { return this._map[name]["#maxId"]; }; /**解析后将清空所有缓存的数据 */ ConfigManager.prototype.parse = function () { var _this = this; this._map = {}; this.m_temp.forEach(function (value, key, map) { //单张表处理 var cls = value.cls; var loaded = value.data; if (!_this._map[key]) { _this._map[key] = {}; } var maxId = 0; for (var j = 0; j < loaded.length; ++j) { //单个数据处理 var item = new cls(); for (var key_1 in loaded[j]) { if (Object.prototype.hasOwnProperty.call(loaded[j], key_1)) { var element = loaded[j][key_1]; item[key_1] = element; } } _this._map[key][item.ID] = item; if (item.ID > maxId) { maxId = item.ID; } } _this._map[key]["#count"] = loaded.length; _this._map[key]["#maxId"] = maxId; }, this); this.m_temp.clear(); }; /** * 根据表名和ID取出数据 * @param tableName * @param id * @returns 找不到则返回null */ ConfigManager.prototype.getConfig = function (tableName, id) { if (this._map[tableName] && this._map[tableName][id]) { return this._map[tableName][id]; } else { return null; } }; return ConfigManager; }()); config.ConfigManager = ConfigManager; })(config = slib.config || (slib.config = {})); })(slib || (slib = {})); (function (slib) { var pool; (function (pool) { /**池元素基类,若继承此基类,则不可在构造函数中传入参数,避免池管理器创建对象时出错 */ var PoolUnit = /** @class */ (function () { function PoolUnit() { this.inPool = false; } /**从池中取出时的初始化接口,建议子类复写,在此时初始化数据 */ PoolUnit.prototype.onInitFromPool = function () { this.inPool = false; }; /**回收到池中时调用的接口,建议子类复写,在此时清除内部相关引用 */ PoolUnit.prototype.onRecoverToPool = function () { this.inPool = true; }; return PoolUnit; }()); pool.PoolUnit = PoolUnit; })(pool = slib.pool || (slib.pool = {})); })(slib || (slib = {})); (function (slib) { var pool; (function (pool) { var PoolManager = /** @class */ (function () { function PoolManager(T) { this._pool = []; this._warnNum = 200; this._class = T; } Object.defineProperty(PoolManager.prototype, "warnNum", { /**警告数量,若池中元素数量超过设定值则打印警告,默认为200 */ get: function () { return this._warnNum; }, enumerable: false, configurable: true }); /** * 设置警告数量,查看warnNum属性 * @param num */ PoolManager.prototype.setWarnNum = function (num) { this._warnNum = num; }; PoolManager.prototype.getUnit = function () { if (this._pool.length >= this._warnNum) { slib.logW("pool:{0}, unit num warn:{1}", this._class.name, this._pool.length); } var target = null; for (var i = 0; i < this._pool.length; ++i) { if (this._pool[i].inPool) { target = this._pool[i]; break; } } if (target == null) { target = new this._class(); this._pool.push(target); } target.onInitFromPool(); return target; }; /**注意,若不是由PoolManager创建的,也会回收到池中 */ PoolManager.prototype.recoverUnit = function (unit) { unit.onRecoverToPool(); if (this._pool.indexOf(unit) < 0) { this._pool.push(unit); } }; return PoolManager; }()); pool.PoolManager = PoolManager; })(pool = slib.pool || (slib.pool = {})); })(slib || (slib = {})); /// /// /// /// (function (slib) { var event; (function (event_1) { var Listener = /** @class */ (function (_super) { __extends(Listener, _super); function Listener() { return _super !== null && _super.apply(this, arguments) || this; } Listener.prototype.onRecoverToPool = function () { _super.prototype.onRecoverToPool.call(this); this.thisObj = null; this.callBack = null; }; return Listener; }(slib.pool.PoolUnit)); /**事件派发器 */ var EventDispatcher = /** @class */ (function () { function EventDispatcher() { this._map = new Map(); } EventDispatcher.prototype.addEventListener = function (event, callBack, thisObj) { if (!this._map.has(event)) { this._map.set(event, []); } var list = this._map.get(event); var listener = EventDispatcher._pool.getUnit(); listener.thisObj = thisObj; listener.callBack = callBack; list.push(listener); }; EventDispatcher.prototype.removeEventListener = function (event, callBack) { var list = this._map.get(event); if (list) { for (var i = 0; i < list.length; ++i) { if (list[i].callBack == callBack) { var listener = list[i]; list.splice(i, 1); EventDispatcher._pool.recoverUnit(listener); break; } } } }; EventDispatcher.prototype.dispatchEvent = function (event, arg) { var list = this._map.get(event); if (list) { for (var i = 0; i < list.length; ++i) { if (arg) { //TODO 若此时移除了监听,会造成循环错乱 list[i].callBack.call(list[i].thisObj, arg); } else { list[i].callBack.call(list[i].thisObj); } } } }; /**清除所有监听 */ EventDispatcher.prototype.clearAll = function () { for (var key in this._map) { var list = this._map.get(key); for (var i = 0; i < list.length; ++i) { EventDispatcher._pool.recoverUnit(list[i]); } list.length = 0; this._map.delete[key]; } }; EventDispatcher._pool = new slib.pool.PoolManager(Listener); return EventDispatcher; }()); event_1.EventDispatcher = EventDispatcher; })(event = slib.event || (slib.event = {})); })(slib || (slib = {})); (function (slib) { var frame; (function (frame) { var Battle = /** @class */ (function () { function Battle() { this.destroyed = false; this._battleLastTime = 0; this._moduleList = []; this._lazyUpdateDelta = 0; this._lazyUpdateFlag = true; } Object.defineProperty(Battle.prototype, "battleLastTime", { /**战斗持续时间 */ get: function () { return this._battleLastTime; }, enumerable: false, configurable: true }); Battle.prototype.addModule = function (module) { this._moduleList.push(module); }; Battle.prototype.init = function () { for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.initModule(); } }; Battle.prototype.start = function () { this._battleLastTime = 0; for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.startModule(); } }; Battle.prototype.update = function (delta) { this._battleLastTime += delta; for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.update(delta); } for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.lateUpdate(delta); } this._lazyUpdateDelta += delta; this._lazyUpdateFlag = !this._lazyUpdateFlag; if (this._lazyUpdateFlag) { for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.lazyUpdate(this._lazyUpdateDelta); } this._lazyUpdateDelta = 0; } }; Battle.prototype.stop = function () { for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.stopModule(); } }; Battle.prototype.destroy = function () { for (var i = 0; i < this._moduleList.length; i++) { var element = this._moduleList[i]; element.destroy(); } this._moduleList.length = 0; }; return Battle; }()); frame.Battle = Battle; })(frame = slib.frame || (slib.frame = {})); })(slib || (slib = {})); (function (slib) { var frame; (function (frame) { var BattleBaseModule = /** @class */ (function () { function BattleBaseModule(battle) { this._battle = battle; } Object.defineProperty(BattleBaseModule.prototype, "battle", { get: function () { return this._battle; }, enumerable: false, configurable: true }); BattleBaseModule.prototype.initModule = function () { }; BattleBaseModule.prototype.startModule = function () { }; BattleBaseModule.prototype.stopModule = function () { }; BattleBaseModule.prototype.update = function (delta) { }; /**在所有module的update结束后进行 */ BattleBaseModule.prototype.lateUpdate = function (delta) { }; /**两帧调用一次,可处理一些并不需要频繁更新的逻辑 */ BattleBaseModule.prototype.lazyUpdate = function (delta) { }; BattleBaseModule.prototype.destroy = function () { this._battle = null; }; return BattleBaseModule; }()); frame.BattleBaseModule = BattleBaseModule; })(frame = slib.frame || (slib.frame = {})); })(slib || (slib = {})); (function (slib) { var frame; (function (frame) { /**可控制心跳的timer */ var FrameTimer = /** @class */ (function () { function FrameTimer() { this._intervalCount = 0; this._running = false; } Object.defineProperty(FrameTimer.prototype, "running", { /**是否正在运行 */ get: function () { return this._running; }, enumerable: false, configurable: true }); /** * @param interval 间隔,需要与update中传入的参数为同一单位 * @param callBack * @param callBackThisObj * @param count 0为无限 */ FrameTimer.prototype.init = function (interval, callBack, callBackThisObj, count) { if (count === void 0) { count = 1; } this._interval = interval; this._callBack = callBack; this._callBackThisObj = callBackThisObj; this._count = count; }; FrameTimer.prototype.start = function () { this._running = true; }; FrameTimer.prototype.update = function (delta) { if (!this._running) return; this._intervalCount += delta; if (this._intervalCount >= this._interval) { this._intervalCount -= this._interval; if (this._count >= 1) { --this._count; if (this._count == 0) { this._running = false; } this._callBack.call(this._callBackThisObj); } else if (this._count == 0) { this._callBack.call(this._callBackThisObj); } } }; FrameTimer.prototype.stop = function () { this._running = false; }; FrameTimer.prototype.destroy = function () { this._running = false; this._callBack = null; this._callBackThisObj = null; }; return FrameTimer; }()); frame.FrameTimer = FrameTimer; })(frame = slib.frame || (slib.frame = {})); })(slib || (slib = {})); (function (slib) { var math; (function (math) { /**最小二叉堆,根节点为最小值,父节点总是小于或等于子节点,在一个频繁修改的数组中,若总是需要获取最小值,使用二叉堆性能较高 */ var BinaryHeap = /** @class */ (function () { /** * * @param scoreFunction 排序值函数,二叉树根据此函数返回的值进行排序 */ function BinaryHeap(scoreFunction) { this._content = []; this._scoreFunction = scoreFunction; } Object.defineProperty(BinaryHeap.prototype, "size", { /**所有节点数量 */ get: function () { return this._content.length; }, enumerable: false, configurable: true }); /**添加节点 */ BinaryHeap.prototype.push = function (element) { this._content.push(element); this.sinkDown(this._content.length - 1); }; /**取最小值节点 */ BinaryHeap.prototype.pop = function () { var result = this._content[0]; var end = this._content.pop(); //末尾数据 if (this._content.length > 0) { this._content[0] = end; //将末尾数据插入头部 this.bubbleUp(0); } return result; }; /**删除所有子节点 */ BinaryHeap.prototype.clear = function () { this._content.length = 0; }; /**移除某个节点,二叉堆会在移除的节点处重新排序 */ BinaryHeap.prototype.remove = function (node) { var i = this._content.indexOf(node); if (i > -1) { //目标节点在二叉堆中 var end = this._content.pop(); if (end == node) { //移除的是最后一个节点,什么都不用做 } else { this._content[i] = end; //将最后一个节点填充到删除的位置 var reduce = (this._scoreFunction(end) < this._scoreFunction(node)); //是否变小了 if (reduce) { this.sinkDown(i); } else { this.bubbleUp(i); } } } }; /** * 某个节点的值改变了,重排二叉堆 * @param node 需要重排的节点 * @param reduce true表示减小,false表示增加 */ BinaryHeap.prototype.rescoreElement = function (node, reduce) { if (reduce === void 0) { reduce = true; } if (reduce) { this.sinkDown(this._content.indexOf(node)); } else { this.bubbleUp(this._content.indexOf(node)); } }; /**从索引n开始向上查找,将大的父节点下沉 */ BinaryHeap.prototype.sinkDown = function (n) { var element = this._content[n]; while (n > 0) { var parentN = ((n + 1) >> 1) - 1; //父节点坐标 var parent_1 = this._content[parentN]; if (this._scoreFunction(element) < this._scoreFunction(parent_1)) { this._content[parentN] = element; this._content[n] = parent_1; n = parentN; } else { break; //已经符合,不需要继续排序了 } } }; /**从索引n开始向下查找,将小的子节点上浮 */ BinaryHeap.prototype.bubbleUp = function (n) { var length = this._content.length; var element = this._content[n]; var elemScore = this._scoreFunction(element); while (true) { var child2N = (n + 1) << 1; var child1N = child2N - 1; var swap = null; var child1Score = null; if (child1N < length) { //如果子节点1存在 var child1 = this._content[child1N]; child1Score = this._scoreFunction(child1); if (child1Score < elemScore) { //子节点小,需要上浮 swap = child1N; } } if (child2N < length) { //如果子节点2存在 var child2 = this._content[child2N]; var child2Score = this._scoreFunction(child2); if (child2Score < (swap == null ? elemScore : child1Score)) { //子节点小,需要上浮 swap = child2N; } } if (swap != null) { this._content[n] = this._content[swap]; this._content[swap] = element; n = swap; } else { //不需要交换,结束 break; } } }; return BinaryHeap; }()); math.BinaryHeap = BinaryHeap; })(math = slib.math || (slib.math = {})); })(slib || (slib = {})); (function (slib) { var math; (function (math) { /**2d向量简易封装 */ var Vector = /** @class */ (function (_super) { __extends(Vector, _super); function Vector(x, y) { var _this = _super.call(this) || this; _this._x = 0; _this._y = 0; _this._x = x; _this._y = y; return _this; } /**从对象池中获取 */ Vector.get = function () { if (!this._inited) { this._inited = true; this._poolManager.setWarnNum(9999); } return this._poolManager.getUnit(); }; Vector.recover = function (p) { this._poolManager.recoverUnit(p); }; Object.defineProperty(Vector.prototype, "x", { get: function () { return this._x; }, enumerable: false, configurable: true }); Object.defineProperty(Vector.prototype, "y", { get: function () { return this._y; }, enumerable: false, configurable: true }); Object.defineProperty(Vector.prototype, "magnitude", { /**模长 */ get: function () { return Math.sqrt(this.sqrMagnitude); }, enumerable: false, configurable: true }); Object.defineProperty(Vector.prototype, "sqrMagnitude", { /**模长的平方数,在需要比较向量长度时,可比较两向量的模长平方数,省去开方计算 */ get: function () { return this._x * this._x + this._y * this._y; }, enumerable: false, configurable: true }); Vector.prototype.setValue = function (valueX, valueY) { this.setX(valueX); this.setY(valueY); return this; // this._x = x; // this._y = y; }; Vector.prototype.setX = function (valueX) { if (slib.MathUtil.isValidNumber(valueX)) { this._x = valueX; } }; Vector.prototype.setY = function (valueY) { if (slib.MathUtil.isValidNumber(valueY)) { this._y = valueY; } }; /**当x,y都为0时,不会产生变化 */ Vector.prototype.normalize = function () { if (this._x != 0 || this._y != 0) { this.scale(1 / this.magnitude); } }; Vector.prototype.scale = function (value) { this._x *= value; this._y *= value; }; Vector._poolManager = new slib.pool.PoolManager(Vector); Vector._inited = false; return Vector; }(slib.pool.PoolUnit)); math.Vector = Vector; })(math = slib.math || (slib.math = {})); })(slib || (slib = {})); /**2d移动模型 */ /**2d移动模型 */ (function (slib) { var move2d; (function (move2d) { var Dir; (function (Dir) { Dir[Dir["LEFT"] = 0] = "LEFT"; Dir[Dir["RIGHT"] = 1] = "RIGHT"; Dir[Dir["UP"] = 2] = "UP"; Dir[Dir["DOWN"] = 3] = "DOWN"; })(Dir = move2d.Dir || (move2d.Dir = {})); /**2d移动模型,可根据设置速度、加速度、方向进行移动,需由外部调用update接口更新 */ var ActorMove2d = /** @class */ (function () { function ActorMove2d(x, y) { this.destroyed = false; this._speed = 0; this._accelerate = 0; this._dirNormal = new slib.math.Vector(0, 0); this._stepVec = new slib.math.Vector(0, 0); /**步进模长 每次调用onFrameUpdate后更新*/ this._stepLen = 0; this._pos = new slib.math.Vector(0, 0); this.active = true; this._pos.setValue(x, y); } Object.defineProperty(ActorMove2d.prototype, "speed", { /**速度 */ get: function () { return this._speed; }, enumerable: false, configurable: true }); Object.defineProperty(ActorMove2d.prototype, "accelerate", { /**加速度*/ get: function () { return this._accelerate; }, enumerable: false, configurable: true }); Object.defineProperty(ActorMove2d.prototype, "dirNormal", { /**方向法向量 */ get: function () { return this._dirNormal; }, enumerable: false, configurable: true }); Object.defineProperty(ActorMove2d.prototype, "stepVec", { /**步进向量 每次调用onFrameUpdate后更新*/ get: function () { return this._stepVec; }, enumerable: false, configurable: true }); Object.defineProperty(ActorMove2d.prototype, "pos", { get: function () { return this._pos; }, enumerable: false, configurable: true }); /**设置前进方向 */ ActorMove2d.prototype.setDir = function (x, y) { this._dirNormal.setValue(x, y); this._dirNormal.normalize(); }; /**直接设置前进方向的法向量,可节省一次归一运算 */ ActorMove2d.prototype.setDirNormal = function (x, y) { this._dirNormal.setValue(x, y); }; /**步进接口,更新一帧数据 * @param delta 单位秒 */ ActorMove2d.prototype.update = function (delta) { if (!this.active) return; //先更新速度 if (this._accelerate != 0) { var speedDelta = delta * this._accelerate; this._speed += speedDelta; this._speed < 0 && (this._speed = 0); } // let realDis = 0; if ((this._dirNormal.x != 0 || this._dirNormal.y != 0) && this._speed > 0) { //需要进行位移 var dis = delta * this._speed; this._stepVec.setValue(this._dirNormal.x, this._dirNormal.y); this._stepVec.scale(dis); this._stepLen = this._stepVec.magnitude; this.setPos(this._pos.x + this._stepVec.x, this._pos.y + this._stepVec.y); this.callBallBack(this._stepLen); } else { this._stepVec.setValue(0, 0); this._stepLen = 0; } }; /**手动设置位置,不会触发位移回调 */ ActorMove2d.prototype.setPos = function (x, y) { this._pos.setValue(x, y); }; /** * 当调用onFrameUpdate时会触发此接口,调用posChangeCallBack,子类可复写此方法,控制调用的时机 * @param dis 前进的距离 */ ActorMove2d.prototype.callBallBack = function (dis) { if (this._posChangeCallBack) { this._posChangeCallBack.call(this._posChangeCallBackThisObj, dis); } }; /** * 绑定位移回调函数,在产生位移时才会触发回调 * @param func 回调函数,参数 dis:number,前进的距离 */ ActorMove2d.prototype.bindPosChangeCallback = function (callBack, thisObj) { this._posChangeCallBack = callBack; this._posChangeCallBackThisObj = thisObj; }; /** * 设置速度,若设置负值,速度会变为0 * @param value */ ActorMove2d.prototype.setSpeed = function (value) { if (this._speed != value) { this._speed = value; if (this._speed < 0) { this._speed = 0; } } }; /**设置加速度,若设置负值,则产生减速效果 */ ActorMove2d.prototype.setAcceleration = function (value) { if (value != this._accelerate) { this._accelerate = value; } }; ActorMove2d.prototype.destroy = function () { this.destroyed = true; slib.math.Vector.recover(this._stepVec); this._stepVec = null; this._posChangeCallBack = null; this._posChangeCallBackThisObj = null; slib.math.Vector.recover(this.dirNormal); this._dirNormal = null; slib.math.Vector.recover(this._pos); this._pos = null; }; return ActorMove2d; }()); move2d.ActorMove2d = ActorMove2d; })(move2d = slib.move2d || (slib.move2d = {})); })(slib || (slib = {})); (function (slib) { var move2d; (function (move2d) { /**在ActorMove2d的基础上改为根据路径列表前进,setDir接口会失效 */ var ActorMove2dPath = /** @class */ (function (_super) { __extends(ActorMove2dPath, _super); function ActorMove2dPath() { var _this = _super !== null && _super.apply(this, arguments) || this; _this._pathIndex = -1; _this._changePointCallBack = null; _this._changePointCallBackThisObj = null; _this._posChangeCallBackFlag = false; return _this; } Object.defineProperty(ActorMove2dPath.prototype, "pathList", { get: function () { return this._pathList; }, enumerable: false, configurable: true }); Object.defineProperty(ActorMove2dPath.prototype, "pathIndex", { /**当前正在追逐的节点索引 */ get: function () { return this._pathIndex; }, enumerable: false, configurable: true }); /** * 注意,若设置了加速度,只在行走时加速度才参与计算 * @param value 加速度 */ ActorMove2dPath.prototype.setAcceleration = function (value) { _super.prototype.setAcceleration.call(this, value); }; /** * 设置路径列表,若路径点与当前位置相同,则会跳到下一个路径点,直到位置不同 * @param pathList 传入的路径列表,内部只会引用此数组,不修改其中的数据 */ ActorMove2dPath.prototype.start = function (pathList) { if (pathList && pathList.length > 0) { this._pathList = pathList; this._pathIndex = -1; do { this.checkNextPathPoint(); } while (this._curTarget && this.pos.x == this._curTarget.x && this.pos.y == this._curTarget.y); //就在当前位置上,切换下一点 if (this._curTarget == null) { slib.logW("pathlist donot contain valid pos"); } } }; /** * 绑定路径点切换时的回调函数,当走过一个点时会触发一次,若出发后此实例的pathIndex属性为-1,则表示路径已走完 * @param callBack * @param thisObj */ ActorMove2dPath.prototype.bindPointChangeCallBack = function (callBack, thisObj) { this._changePointCallBack = callBack; this._changePointCallBackThisObj = thisObj; }; ActorMove2dPath.prototype.setDir = function () { //屏蔽此方法,避免外部修改方向 }; ActorMove2dPath.prototype.stop = function () { this._curTarget = null; this._pathIndex = -1; _super.prototype.setDir.call(this, 0, 0); }; ActorMove2dPath.prototype.gotoPathPoint = function (moveLen) { if (this._curTarget) { /**目标点距离 平方数 */ var targetLenSqr = (this._curTarget.x - this.pos.x) * (this._curTarget.x - this.pos.x) + (this._curTarget.y - this.pos.y) * (this._curTarget.y - this.pos.y); var moveLenSqr = moveLen * moveLen; if (moveLenSqr >= targetLenSqr) { //超过了目标点 this.setPos(this._curTarget.x, this._curTarget.y); //移动到目标点 this.checkNextPathPoint(); //切换下一目标点 this.onGoToNextPoint(); return Math.sqrt(targetLenSqr); } else { //到不了目标点 var step = slib.math.Vector.get(); step.setValue(this.dirNormal.x, this.dirNormal.y); step.scale(moveLen); this.setPos(this.pos.x + step.x, this.pos.y + step.y); slib.math.Vector.recover(step); return moveLen; } } return 0; }; ActorMove2dPath.prototype.update = function (delta) { if (this._curTarget && this.speed > 0) { this._posChangeCallBackFlag = false; var tempPos = slib.math.Vector.get(); tempPos.setValue(this.pos.x, this.pos.y); _super.prototype.update.call(this, delta); //先让计算父类位移 this.setPos(tempPos.x, tempPos.y); //重置位置 slib.math.Vector.recover(tempPos); var stepCount = this._stepLen; //要把它走完或是走到终点 var moveLen = 0; while (stepCount > 0) { var stepLen = this.gotoPathPoint(stepCount); stepCount -= stepLen; moveLen += stepLen; if (stepLen == 0) { break; //没有路径点了 } } this._posChangeCallBackFlag = true; this.callBallBack(moveLen); } }; ActorMove2dPath.prototype.callBallBack = function (dis) { if (this._posChangeCallBackFlag) { _super.prototype.callBallBack.call(this, dis); } }; /** * 当前路径点切换时调用 * @returns true为成功,false为路径点已走完了 */ ActorMove2dPath.prototype.checkNextPathPoint = function () { this._pathIndex += 1; if (this._pathIndex >= 0 && this._pathIndex < this._pathList.length) { this._curTarget = this._pathList[this._pathIndex]; _super.prototype.setDir.call(this, this._curTarget.x - this.pos.x, this._curTarget.y - this.pos.y); return true; } else { this.stop(); return false; } }; /**当前路径点切换时调用,供子类复写,第一个点不会触发 */ ActorMove2dPath.prototype.onGoToNextPoint = function () { if (this._changePointCallBack) { this._changePointCallBack.call(this._changePointCallBackThisObj); } }; ActorMove2dPath.prototype.destroy = function () { this.stop(); _super.prototype.destroy.call(this); this._pathList = null; this._curTarget = null; this._changePointCallBack = null; this._changePointCallBackThisObj = null; }; return ActorMove2dPath; }(move2d.ActorMove2d)); move2d.ActorMove2dPath = ActorMove2dPath; })(move2d = slib.move2d || (slib.move2d = {})); })(slib || (slib = {})); /**状态机相关 */ /**状态机相关 */ (function (slib) { var sm; (function (sm) { /** * 单个状态基类 */ var SMBaseState = /** @class */ (function () { function SMBaseState() { this.isDestroy = false; this.map = new Map(); } Object.defineProperty(SMBaseState.prototype, "id", { get: function () { return this.m_stateId; }, set: function (value) { this.m_stateId = value; }, enumerable: false, configurable: true }); Object.defineProperty(SMBaseState.prototype, "isRunning", { get: function () { return this.stateMachine.getCurrentStateID() == this.m_stateId; }, enumerable: false, configurable: true }); /** * 定义事件和状态的跳转关系 * @param trans 事件类型 * @param id 状态类型 */ SMBaseState.prototype.addTransition = function (trans, id) { if (trans == SMBaseState.nullTransitionId || id == SMBaseState.nullStateId || this.map.has(trans)) { return; } this.map.set(trans, id); }; SMBaseState.prototype.deleteTransition = function (trans) { if (trans == SMBaseState.nullTransitionId) { return; } if (this.map.has(trans)) { this.map.delete(trans); } }; SMBaseState.prototype.getOutputState = function (trans) { return this.map.has(trans) ? this.map.get(trans) : SMBaseState.nullStateId; }; /**状态被触发时的调用 */ SMBaseState.prototype.onEnter = function (data) { if (data === void 0) { data = null; } }; /**离开状态的调用,状态机destory时,也会调用当前状态的onLeave接口 */ SMBaseState.prototype.onLeave = function () { }; SMBaseState.prototype.onReason = function (transID, data) { if (data === void 0) { data = null; } var shouldChange = false; if (this.getOutputState(transID) != SMBaseState.nullStateId) { shouldChange = true; } if (shouldChange) { this.stateMachine.performTransition(transID, data); } }; SMBaseState.prototype.onUpdate = function (data) { if (data === void 0) { data = null; } }; /**状态机destro时触发 */ SMBaseState.prototype.onDestory = function () { this.stateMachine = null; }; SMBaseState.prototype.onGetDebugInfomation = function () { return null; }; SMBaseState.nullTransitionId = -1; SMBaseState.nullStateId = -1; return SMBaseState; }()); sm.SMBaseState = SMBaseState; })(sm = slib.sm || (slib.sm = {})); })(slib || (slib = {})); (function (slib) { var sm; (function (sm) { /** * 状态机控制类 */ var XStateMachine = /** @class */ (function () { function XStateMachine() { this.m_states = []; //#endregion } XStateMachine.prototype.getCurrentStateID = function () { return this.m_currentStateID; }; XStateMachine.prototype.performTransition = function (trans, data) { if (data === void 0) { data = null; } if (trans == sm.SMBaseState.nullTransitionId) { return; } var id = this.m_currentState.getOutputState(trans); if (id == sm.SMBaseState.nullStateId) { return; } var prevState = this.m_currentState; var newState = null; for (var i = 0; i < this.m_states.length; i++) { var element = this.m_states[i]; if (element.id == id) { newState = element; break; } } if (newState == null) { slib.logW("invalid state id:{0}", id); } prevState.onLeave(); this.m_oldStateID = this.m_currentStateID; this.m_currentStateID = id; this.m_currentState = newState; if (this.m_currentState != null) { this.m_currentState.lastStateId = this.m_oldStateID; } this.m_currentState.onEnter(data); this.onStateChange(); if (this.m_currentStateID != this.m_currentState.id) { slib.logW("set state failed"); } }; XStateMachine.prototype.addState = function (s) { if (this.m_states.length == 0) { this.m_states.push(s); this.m_currentState = s; this.m_currentStateID = s.id; return; } for (var i = 0; i < this.m_states.length; i++) { var element = this.m_states[i]; if (element.id == s.id) { return; } } this.m_states.push(s); }; XStateMachine.prototype.getStateById = function (id) { var _state = null; for (var i = 0; i < this.m_states.length; i++) { var element = this.m_states[i]; if (element.id == id) { _state = element; break; } } return _state; }; XStateMachine.prototype.onStateChange = function () { }; XStateMachine.prototype.destory = function () { this.onDestory(); }; XStateMachine.prototype.onDestory = function () { if (this.m_currentState != null) { this.m_currentState.isDestroy = true; this.m_currentState.onLeave(); this.m_currentState = null; this.m_currentStateID = 0; } if (this.m_states != null) { for (var i = 0; i < this.m_states.length; i++) { var element = this.m_states[i]; element.onDestory(); } } }; return XStateMachine; }()); sm.XStateMachine = XStateMachine; })(sm = slib.sm || (slib.sm = {})); })(slib || (slib = {}));