Lordofpomelo源码分析 (一): World初始化之读取地图配置

凡事总有个起点, 我们先从 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

你可能感兴趣的:(nodejs,pomelo,游戏服务端)