精华 一个基于Phaser.TilemapLayer的寻路函数
发布于 7 年前 作者 aleafworld 2114 次浏览 来自 分享

最近写的一个寻路函数,算法比较简单,但并非A*算法。 因为要用到TilemapLayer的layer.data,所以把它挂在TilemapLayer上了。 旨在分享,相互学习,写的不好,欢迎指正,希望能抛砖引玉,对大家有所启发。 OK,上菜:

// *****************************
// Phaser.TilemapLayer.findTilePath 
// 基于TilemapLayer的寻路函数,寻找两个Tile之间的路径
// *****************************
// 参数:
// x0 : 起点Tile的x
// y0 : 起点Tile的y
// x1 : 终点Tile的x
// y1 : 终点Tile的y
// collideIndexes : 检测碰撞的index数组(像tilemap中的collideIndexes)
// 返回 : Tile数组或 false
// 数组第一个元素为终点Tile,依次到起点Tile,但最后不包含起点Tile
// 走路时,可用Array.pop()读取下一步的Tile
Phaser.TilemapLayer.prototype.findTilePath = function (x0, y0, x1, y1, collideIndexes, limit) {
	if(limit === undefined){ limit = 100; }
	var _layer = this.layer;
	var path = [];
	var excepts = []; 
	var roundTilesAll = [];
	var isFound = false;
	if(_layer.data[y1] === undefined || _layer.data[y1][x1] === undefined){ // 目标不存在?
		return false;
	}
	var curTile = _layer.data[y0][x0];
	var tarTile = _layer.data[y1][x1];
	if(collideIndexes.indexOf(tarTile.index) > -1){ // 目标不可及?
		return false;
	}
	roundTilesAll.push([curTile]);
	excepts.push(curTile);
	var step = 0;
	var rounds = this._getRoundTiles(roundTilesAll[0], excepts, collideIndexes);
	while(rounds.length > 0){
		step ++;
		if(step > limit){
			break;
		}
		if(rounds.indexOf(tarTile) > -1){
			isFound = true;
			break;
		}
		excepts = roundTilesAll[roundTilesAll.length - 1].concat();
		roundTilesAll.push(rounds);
		rounds = this._getRoundTiles(rounds, excepts, collideIndexes);
	}
	if(isFound){
		path.push(tarTile);
		var tmpTile;
		while(roundTilesAll.length > 1){
			rounds = roundTilesAll.pop();
			if(tarTile.x > 0){
				tmpTile = _layer.data[tarTile.y][tarTile.x - 1];
				if(rounds.indexOf(tmpTile) != -1){
					path.push(tmpTile);
					tarTile = tmpTile;
					continue;
				}
			}
			if(tarTile.x < _layer.width-1){
				tmpTile = _layer.data[tarTile.y][tarTile.x + 1];
				if(rounds.indexOf(tmpTile) != -1){
					path.push(tmpTile);
					tarTile = tmpTile;
					continue;
				}
			}
			if(tarTile.y > 0){
				tmpTile = _layer.data[tarTile.y - 1][tarTile.x];
				if(rounds.indexOf(tmpTile) != -1){
					path.push(tmpTile);
					tarTile = tmpTile;
					continue;
				}
			}
			if(tarTile.y < _layer.height - 1){
				tmpTile = _layer.data[tarTile.y + 1][tarTile.x];
				if(rounds.indexOf(tmpTile) != -1){
					path.push(tmpTile);
					tarTile = tmpTile;
					continue;
				}
			}
		}
		return path;
	}else{  
		return false;
	}
};
// *****************************
// _getRoundTiles (获取外围的Tiles)
// *****************************
// 返回 Array<Tile>
Phaser.TilemapLayer.prototype._getRoundTiles = function(roundTiles, exceptTiles, collideIndexes){
	var _layer = this.layer;
	var newRoundArray = [];
	var x;
	var y;
	var tmpTile;
	for (var i = 0; i < roundTiles.length; i++){
		x = roundTiles[i].x;
		y = roundTiles[i].y;
		if(x > 0){
			tmpTile = _layer.data[y][x - 1];
			if(collideIndexes.indexOf(tmpTile.index) == -1 && exceptTiles.indexOf(tmpTile) == -1){
				newRoundArray.push(tmpTile);
				exceptTiles.push(tmpTile);
			}
		}
		if(x<_layer.width - 1){
			tmpTile = _layer.data[y][x + 1];
			if(collideIndexes.indexOf(tmpTile.index) == -1 && exceptTiles.indexOf(tmpTile) == -1){
				newRoundArray.push(tmpTile);
				exceptTiles.push(tmpTile);
			}
		}
		if(y>0){
			tmpTile = _layer.data[y - 1][x];
			if(collideIndexes.indexOf(tmpTile.index) == -1 && exceptTiles.indexOf(tmpTile) == -1){
				newRoundArray.push(tmpTile);
				exceptTiles.push(tmpTile);
			}
		}
		if(y<_layer.height - 1){
			tmpTile = _layer.data[y + 1][x];
			if(collideIndexes.indexOf(tmpTile.index) == -1 && exceptTiles.indexOf(tmpTile) == -1){
				newRoundArray.push(tmpTile);
				exceptTiles.push(tmpTile);
			}
		}
	}
	return newRoundArray;
};


2 回复

给力啊,老哥,可以自动寻路了

寻路函数都有了,怎么可以没有Demo? 以下是实现走路的代码:

function Main(game) {
	var map;
	var mapLayer;
	var hero;

	this.preload=function () {
		var loading = game.add.sprite(game.width/2, game.height/2, "loading");
		loading.anchor.setTo(0.5);
		loading.animations.add("loading", [0, 1, 2], 5, true);
		loading.animations.play("loading");

		game.load.spritesheet("hero", "img/hero.png", 32, 32);
		game.load.image("maptiles", "img/maptiles.png");  
		game.load.tilemap("worldmap", "img/worldmap.json", null, Phaser.Tilemap.TILED_JSON);

	};

	this.create = function(){
		map = game.add.tilemap("worldmap");
		map.addTilesetImage("maptiles");
		mapLayer = map.createLayer("layer-1");
		mapLayer.resizeWorld();
		map.setCollision([2,3,4], true, mapLayer);

		hero = game.add.sprite(5*32, 3*32, "hero");
		hero.animations.add("down", [1, 0, 1, 2] , 8, true);
		hero.animations.add("left", [4, 3, 4, 5] , 8, true);
		hero.animations.add("right", [7, 6, 7, 8] , 8, true);
		hero.animations.add("up", [10, 9, 10, 11] , 8, true);
		hero.goingX = hero.x;
		hero.goingY = hero.y;
		hero.isMoving = false;
		hero.movePath = [];
		hero.moveTween = game.add.tween(hero);
		hero.moveTween.onComplete.add(function(){hero.isMoving = false;}, this);

		game.camera.follow(hero);

		mapLayer.inputEnabled = true;;
		mapLayer.events.onInputDown.add(function(){
			var x0 = mapLayer.getTileX(hero.goingX);
			var y0 = mapLayer.getTileY(hero.goingY);
			var x1 = mapLayer.getTileX(game.input.activePointer.worldX);
			var y1 = mapLayer.getTileY(game.input.activePointer.worldY);
			hero.movePath = mapLayer.findTilePath(x0, y0, x1, y1, map.collideIndexes) || hero.movePath;
		}, this);

	};
	this.update = function(){
		if(!hero.isMoving){
			if(hero.movePath.length>0){ // 有路要走?
				hero.isMoving = true;
				var nextTile = hero.movePath.pop(); // 从路径数组中取出下一步的tile
				hero.goingX = nextTile.worldX;
				hero.goingY = nextTile.worldY;
				hero.moveTween.timeline = []; // 重复使用tween,清空timeline即可
				hero.moveTween.to({x : hero.goingX, y : hero.goingY}, 200, "Linear", true);

				if(hero.goingX < hero.x){
					hero.animations.play("left");
				}else if(hero.goingX > hero.x){
					hero.animations.play("right");
				}else if(hero.goingY < hero.y){
					hero.animations.play("up");
				}else if(hero.goingY > hero.y){
					hero.animations.play("down");
				}
			}else{
				hero.animations.stop();
			}
		}
	};
}

具体效果请看Demo网址: http://www.aleaf.com/h5/games/findpathdemo/

回到顶部