凡事总有个起点, 我们先从 world.init开始吧!
// 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));
});
这段代码位于lordofpomelo的game-server下的app.js文件,我们先看这句world.init(dataApi.area.all()),它对应调用的是./app/domain/world.js文件的init方法,代码如下:
exp.init = function(areasConfig){
//Init areas
for(var key in areasConfig){
//init map
var areaConfig = areasConfig[key];
areaConfig.weightMap = false;
maps[areaConfig.id] = new Map(areaConfig);
}
};
内容很简单,传入的参数是所有的area服务器,lordofpomelo中默认配了3个area服务器,分别对应游戏中的3个地图,初始化world时逐个循环进行area的map初始化,这里调用到的是maps[areaConfig.id] = new Map(areaConfig);接下来进入map的构造方法,对应的文件是./app/domain/map/map.js
/**
* The data structure for map in the area
*/
var Map = function(opts) {
this.mapPath = process.cwd() + opts.path;
this.map = null;
this.weightMap = null;
this.name = opts.name;
this.init(opts);
};
首先this.mapPath 是取得第一张地图的配置文件,位于 ./config/map/desert.json。看名字就能猜出来,是张沙漠的地图。this.name 就是desert,紧接着执行this.init(opts)方法
/**
* Init game map
* @param {Object} opts
* @api private
*/
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));
}
}
}
};
这段代码比较长,不用心急,我们慢慢看。首先var map = require(this.mapPath);其实就是读取前面的地图配置文件。然后是这句this.configMap(map);
Map.prototype.configMap = function(map){
this.map = {};
var layers = map.layers;
for(var i = 0; i < layers.length; i++){
var layer = layers[i];
if(layer.type === 'objectgroup'){
this.map[layer.name] = configObjectGroup(layer.objects);
}
}
};
这个不复杂,就是读取配置中的layers,这里面第一张地图一共有5个layer,分别为desert、birth、mob、npc、collision,看名字也能猜出来,就是背景地板、出生地、怪物、npc和障碍物5层了,其中后四个都是属于objectgroup类型,因此都会调用到 this.map[layer.name] = configObjectGroup(layer.objects) 这句,继续看代码;
function configObjectGroup(objs){
for(var i = 0; i < objs.length; i++){
objs[i] = configProps(objs[i]);
}
return objs;
}
逐个循环layer里面的object,然后调用configProps(objs[i])
function configProps(obj){
if(!!obj && !!obj.properties){
for(var key in obj.properties){
obj[key] = obj.properties[key];
}
delete obj.properties;
}
return obj;
}
这里面就是把每个obj的属性读取出来,返回上层,形成一个数组继续向上返回到this.map[layer.name]这个变量中存储。
好了,源码好多,慢慢来,这一章就到这。。
各位保重,88