接上回,我们看到map的初始化,代码如下:
Map.prototype.init = function(opts) { var weightMap = opts.weightMap || false; var map = require(this.mapPath); if(!map) { logger.error('Load map failed! '); } else { this.configMap(map); this.id = opts.id; this.width = opts.width; this.height = opts.height; this.tileW = 20; this.tileH = 20; this.rectW = Math.ceil(this.width/this.tileW); this.rectH = Math.ceil(this.height/this.tileH); this.pathCache = new PathCache({limit:1000}); this.pfinder = buildFinder(this); if(weightMap) { //Use cache map first var path = process.cwd() + '/tmp/map.json'; var maps = fs.existsSync(path)?require(path) : {}; if(!!maps[this.id]){ this.collisions = maps[this.id].collisions; this.weightMap = this.getWeightMap(this.collisions); }else{ this.initWeightMap(); this.initCollisons(); maps[this.id] = {version : Date.now(), collisions : this.collisions}; fs.writeFileSync(path, JSON.stringify(maps)); } } } };
上回看到了this.configMap(map);这句的就是把地图配置文件读取存入this.map变量中,接下来,从opts中取出地图的id/width/height,那么这些值是从哪里来的呢?还记得之前app.js中的 world.init(dataApi.area.all()) 吗?重新看下之前的代码
// Configure for area server app.configure('production|development', 'area', function(){ app.filter(pomelo.filters.serial()); app.before(playerFilter()); var areaId = app.get('curServer').area; if(!areaId || areaId < 0) { throw new Error('load area config failed'); } world.init(dataApi.area.all()); area.init(dataApi.area.findById(areaId)); });
这里面实际上还先执行了dataApi.area.all(),该方法位于./app/util/dataApi.js, 内容如下:
/** * find all item * * @return {array} * @api public */ Data.prototype.all = function() { return this.data; }; module.exports = { area: new Data(area), character: new Data(character), equipment: new Data(equipment), experience: new Data(experience), npc: new Data(npc), role: new Data(role), talk: new Data(talk), item: new Data(item), fightskill: new Data(fightskill), task: new Data(task) };
实际上它返回的就是new Data(area),该方法对应的引用是var area = require('../../config/data/area');打开改路径下的文件,文件内容如下,
["id","name","areaName","level","width","height","path","towerWidth","towerHeight"],
["1","desert","沙漠",0,4200,2800,"/config/map/desert.json",300,300],
这里定义了前面opts用到的id/width/height等数值。搞清楚了数值来源后我们继续回到map.ini中 看下面代码:
this.tileW = 20; this.tileH = 20; this.rectW = Math.ceil(this.width/this.tileW); this.rectH = Math.ceil(this.height/this.tileH);
这一段很简单,就是定义地图的tile为20*20构成,然后再计算出地图的总的tile宽度与高度。
this.pathCache = new PathCache({limit:1000}); this.pfinder = buildFinder(this);
然后是这两句,我们先看第一句this.pathCache = new PathCache({limit:1000}); PathCache构造方法位于./app/util/pathCache.js文件,代码如下:
var PathCache = function(opts) { this.id = id++; this.limit = opts.limit||30000; this.size = 0; this.queue = new PriorityQueue(comparator); this.cache = {}; };
这里面主要调用到的是new PriorityQueue(comparator); 其中comparator是一个比较大小的function,先看代码:
var comparator = function(a, b) { return a.time < b.time; };
内容很简单,比较两个值的形成时间,a时间比b时间早则返回true,具体有什么用,请接着我们继续看PriorityQueue该方法位于pomelo-collection模块中的./lib/PriorityQueue.js文件中,这是一个独立的模块,
var PriorityQueue = function(comparator){ this.init(comparator); } var pro = PriorityQueue.prototype; pro.init = function(comparator){ this._comparator = typeof(comparator)=='function'?comparator:this._defaultComparator; this._queue = []; this._tailPos = 0; }
调用自己的init方法,初始化了比较方法,如果传入的参数不是一个function时,则采用默认的比较方法,这里不是采用默认方法,所以暂时不看默认方法;
看到这里大家可能比较疑惑,这个PriorityQueue到底是个什么东西,实际上它就是一个顺序队列,它能够保证每次提供给你最早加入队列中的路径被取出并删除。
通过这种机制保证了pathCache在预先设定的limit范围内保存寻路路径的缓存,避免缓存无限制增长,这里我们的limit就是前面提到的pathCache = new PathCache({limit:1000});指定的1000这个数值。具体的代码暂时不分析了,等后面用到时在详细说明.
好了,这篇就到这来,下一篇开始说明buildFinder(this);
大家88