精华
一个基于Phaser.TilemapLayer的寻路函数
最近写的一个寻路函数,算法比较简单,但并非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/