正常的地图
起始点:左上角
宽度:地图上方x轴
高度:地图左边y轴
这是一个100*50的地图

通过坐标获取地图格子
/**
* 通过坐标获取地图格子
* @param pos
* @param mapId
* @returns
*/
getGridByPos(pos: Vec3, mapId: string) {
let tiledMap = this._tileMapData.get(mapId);
if (!tiledMap) {
console.error("can not find tiledMap by mapId:", mapId);
return null;
}
let _mapWidth = tiledMap.getMapSize().width;
let _mapHeight = tiledMap.getMapSize().height;
let _tileWidth = tiledMap.getTileSize().width;
let _tileHeight = tiledMap.getTileSize().height;
let gridX = ~~((pos.x + _mapWidth * _tileWidth / 2) / _tileWidth);
let gridY = ~~((_mapHeight * _tileHeight / 2 - pos.y) / _tileHeight);
return [gridX, gridY];
}
通过地图格子获取坐标
/**
* 通过地图格子获取坐标
* @param gridX
* @param gridY
* @param mapId
* @returns
*/
getPosByGrid(gridX: number, gridY: number, mapId: string) {
let tiledMap = this._tileMapData.get(mapId);
if (!tiledMap) {
console.error("can not find tiledMap by mapId:", mapId);
return null;
}
let _mapWidth = tiledMap.getMapSize().width;
let _mapHeight = tiledMap.getMapSize().height;
let _tileWidth = tiledMap.getTileSize().width;
let _tileHeight = tiledMap.getTileSize().height;
let pos = new Vec3(gridX * _tileWidth, gridY * _tileHeight, 0);
//原点为中心时,坐标系为左上角,需要转换为中心点坐标系
let realPosx = pos.x - _mapWidth * _tileWidth / 2 + _tileWidth / 2;
let realPosy = _mapHeight * _tileHeight / 2 - pos.y - _tileHeight / 2;
return new Vec3(realPosx, realPosy, 0);
}
获取地图的宽高
/**
* 获取地图的宽高
* @param map
* @returns
*/
getTileMapSize(map: TiledMap) {
let tiledMapWidth = map.getMapSize().width * map.getTileSize().width;
let tiledMapHeight = map.getMapSize().height * map.getTileSize().height;
return [tiledMapWidth, tiledMapHeight];
}
设置多边形对象障碍物
**
* 设置多边形对象障碍物
*/
setPolyObjtacles() {
let obstacle = this.tiledMap.getObjectGroup("obstacle");
let _mapWidth = this.tiledMap.getMapSize().width;
let _mapHeight = this.tiledMap.getMapSize().height;
let _tileWidth = this.tiledMap.getTileSize().width;
let _tileHeight = this.tiledMap.getTileSize().height;
if (obstacle) {
let objs = obstacle.getObjects();
for (let i = 0; i < objs.length; i++) {
//存在多个障碍对象
let polyArr: Array<Vec2> = [];
let obj = objs[i];
let points = obj.points;
let offset = obj.offset;
for (let j = 0; j < points.length; j++) {
let point = points[j];
let pos = new Vec2(point.x, point.y);
let newPosx = pos.x - _mapWidth * _tileWidth / 2 + offset.x;
let newPosy = _mapHeight * _tileHeight / 2 + pos.y - offset.y;
polyArr.push(new Vec2(newPosx, newPosy));
}
//绘制多边形障碍区域
// this.debugPolygonDraw(polyArr);
//创建多边形障碍
this.createPolygonObstacle(polyArr);
};
}
}
/**
* 设置地图图块属性障碍
*/
setObjtacles() {
let land = this.tiledMap.getLayer("land");
let _mapWidth = this.tiledMap.getMapSize().width;
let _mapHeight = this.tiledMap.getMapSize().height;
let _tileWidth = this.tiledMap.getTileSize().width;
let _tileHeight = this.tiledMap.getTileSize().height;
for (let i = 0; i < _mapWidth; i++) {
for (let j = 0; j < _mapHeight; j++) {
let tiled = land.getTileGIDAt(i, j);
if (tiled !== 0) {
let pro = this.tiledMap.getPropertiesForGID(tiled);
if (pro && pro.hasOwnProperty('wall')) {
//生成刚体
let pos = new Vec3(i * _tileWidth, j * _tileHeight, 0);
let realPosx = pos.x - _mapWidth * _tileWidth / 2;
let realPosy = _mapHeight * _tileHeight / 2 - pos.y;
let newPosx = realPosx + _tileWidth / 2;
let newPosy = realPosy - _tileHeight / 2;
this.createRectObstacle(new Vec3(newPosx, newPosy, 0), _tileWidth, _tileHeight);
}
}
}
}
}
多边形的对象点转换
let obstacle = this.tiledMap.getObjectGroup("obstacle");
let _mapWidth = this.tiledMap.getMapSize().width;
let _mapHeight = this.tiledMap.getMapSize().height;
let _tileWidth = this.tiledMap.getTileSize().width;
let _tileHeight = this.tiledMap.getTileSize().height;
if (obstacle) {
let objs = obstacle.getObjects();
for (let i = 0; i < objs.length; i++) {
//存在多个障碍对象
let polyArr: Array<Vec2> = [];
let obj = objs[i];
let points = obj.points;
let offset = obj.offset;
for (let j = 0; j < points.length; j++) {
let point = points[j];
let pos = new Vec2(point.x, point.y);
let newPosx = pos.x - _mapWidth * _tileWidth / 2 + offset.x;
let newPosy = _mapHeight * _tileHeight / 2 + pos.y - offset.y;
polyArr.push(new Vec2(newPosx, newPosy));
}
//绘制多边形障碍区域
// this.debugPolygonDraw(polyArr);
//创建多边形障碍
this.createPolygonObstacle(polyArr);
};
}
矩形对象的点转换
let objGroup = this.tiledMap.getObjectGroup("door");
let objs = objGroup.getObjects();
let [tiledMapWidth, tiledMapHeight] = TiledMapData.instance.getTileMapSize(this.tiledMap);
let enterDoor: Array<Rect> = [];
let outDoor: Array<Rect> = [];
for (let i = 0; i < objs.length; i++) {
//有多个门
let obj = objs[i];
let offset = obj.offset;
let realPosx = offset.x - tiledMapWidth / 2;
let realPosy = tiledMapHeight / 2 - offset.y;
// this.debugRectDraw(new Vec3(realPosx, realPosy - obj.height, 0), obj.width, obj.height);
//添加门口
if (obj.name === "enter") {
enterDoor.push(new Rect(realPosx, realPosy - obj.height, obj.width, obj.height));
}
if (obj.name === "out") {
outDoor.push(new Rect(realPosx, realPosy - obj.height, obj.width, obj.height));
}
}
点对象的坐标转换
/**
* 设置怪物
*/
setMonsterBornPoint() {
let [tiledMapWidth, tiledMapHeight] = TiledMapData.instance.getTileMapSize(this.tiledMap);
let objGroup = this.tiledMap.getObjectGroup("monster");
if (objGroup) {
let objs = objGroup.getObjects();
for (let i = 0; i < objs.length; i++) {
//遍历出生点
let obj = objs[i];
let offset = obj.offset;
let itemId = obj.name;
let realPosx = offset.x - tiledMapWidth / 2;
let realPosy = tiledMapHeight / 2 - offset.y;
MonsterData.instance.addMonsterBornPoint(itemId, new Vec3(realPosx, realPosy, 0));
}
//初始化生成地图怪物
EventListener.emit(GameEvent.INIT_MAP_MONSTER, this.tiledMap.getLayer("Place"));
}
}
45度的地图
起始点:上方顶点
宽度:地图右边x轴
高度:地图左边y轴
这是一个60*30的地图

初始化45度的地图
/**
* 初始化地图数据
* 45度地图,右边为宽 左边为高 遍历格子是从右上角开始 到左下角结束,从右向左,从上到下
* @param tiledMap
*/
initFloorMapData(tiledMap: TiledMap) {
this._tiledMap = tiledMap;
let roadLayer = tiledMap.getLayer("road");
// console.log(roadLayer.tiles);
if (roadLayer) {
this._mapWidth = tiledMap.getMapSize().width;
this._mapHeight = tiledMap.getMapSize().height;
this._tileWidth = tiledMap.getTileSize().width;
this._tileHeight = tiledMap.getTileSize().height;
//右上脚第一个点的坐标中心坐标 距离 地图中心左边的偏移
//offsetX :顶点的x坐标 - 地图的宽度/2
//offsetY :地图高度/2 - tileHeight/2
let offsetX = this._mapHeight / 2 * this._tileWidth - (this._mapWidth * this._tileWidth + (this._mapHeight - this._mapWidth) * (this._tileWidth / 2)) / 2;
let offsetY = (this._mapWidth * this._tileHeight + (this._mapHeight - this._mapWidth) * (this._tileHeight / 2)) / 2 - this._tileHeight / 2;
//初始地图数据
this._tileMapData = Array(this._mapHeight).fill(1).map(() => Array(this._mapWidth).fill(1));
//通过解锁区域 设置数据
let obj = tiledMap.getObjectGroup("obj");
let ojbs = obj.getObjects();
for (let i = 0; i < ojbs.length; i++) {
//检测是否解锁
let obj = ojbs[i];
let name = obj.name;
//设置区域数据
let type = obj.properties.fType;
this._areaOjbData.set(name, obj);
//检测是否解锁
if (this.checkUnlockArea((obj.properties.area as string))) {
console.log("解锁区域:" + name);
this.setUnlockAreaData(name);
}
}
}
}
通过格子获取在大地图里的位置
/**
* 通过格子获取在大地图里的位置
* @param x
* @param y
*/
getMaxPosByGrid(x: number, y: number) {
const mapWidth = this._mapWidth; //地图行数
const mapHeight = this._mapHeight; // 地图列数
const tileWidth = this._tileWidth; // 图块宽度
const tileHeight = this._tileHeight; // 图块高度
let orgirinX = mapHeight / 2 * this._tileWidth - (mapWidth * this._tileWidth + (mapHeight - mapWidth) * (this._tileWidth / 2)) / 2;;
let orgirinY = (mapWidth * this._tileHeight + (mapHeight - mapWidth) * (this._tileHeight / 2)) / 2 - this._tileHeight / 2;
const cx = orgirinX + (x - y) * (this._tileWidth / 2);
const cy = orgirinY - (x + y) * (this._tileHeight / 2); // Y轴取反,向下延伸
return { x: cx, y: cy };
}
通过坐标获取大地图的行列
/**
* 通过坐标获取大地图的行列
* @param posX
* @param posY
* @returns
*/
getMaxMapGridByPos(posX: number, posY: number) {
const mapWidth = this._mapWidth; //地图行数
const mapHeight = this._mapHeight; // 地图列数
const tileWidth = this._tileWidth; // 图块宽度
const tileHeight = this._tileHeight; // 图块高度
let orgirinX = mapHeight / 2 * this._tileWidth - (mapWidth * this._tileWidth + (mapHeight - mapWidth) * (this._tileWidth / 2)) / 2;;
let orgirinY = (mapWidth * this._tileHeight + (mapHeight - mapWidth) * (this._tileHeight / 2)) / 2 - this._tileHeight / 2;
const x = ((posX - orgirinX) / (tileWidth / 2) + (orgirinY - posY) / (tileHeight / 2)) / 2;
const y = x - (posX - orgirinX) / (tileWidth / 2);
let x1 = Math.abs(Math.round(x)) == 0 ? 0 : Math.round(x);
let y1 = Math.abs(Math.round(y)) == 0 ? 0 : Math.round(y);
return { x: Math.round(x1), y: Math.round(y1) };
}
绘制地图网格
/**
* 绘制地图网格
*/
drawMapGrid(drawNode: Node, width: number, height: number) {
let graphics = drawNode.getComponent(Graphics);
if (!graphics) {
graphics = drawNode.addComponent(Graphics);
}
const mapWidth = width; // 地图行数
const mapHeight = height; // 地图列数
const tileWidth = this._tileWidth; // 图块宽度
const tileHeight = this._tileHeight; // 图块高度
graphics.lineWidth = 5;
graphics.strokeColor = Color.BLACK;
// graphics.fillColor.fromHEX('#ff0000');
// 遍历所有格子
let orgirinX = mapHeight / 2 * tileWidth - (mapWidth * tileWidth + (mapHeight - mapWidth) * (tileWidth / 2)) / 2;
let orgirinY = (mapWidth * tileHeight + (mapHeight - mapWidth) * (tileHeight / 2)) / 2 - tileHeight / 2;
for (let i = 0; i < mapWidth; i++) {
for (let j = 0; j < mapHeight; j++) {
// 计算当前格子的中心坐标(调整Y轴方向)
const cx = orgirinX + (i - j) * (tileWidth / 2);
const cy = orgirinY - (i + j) * (tileHeight / 2); // Y轴取反,向下延伸
// 计算菱形的四个顶点
const rightX = cx + tileWidth / 2;
const rightY = cy;
const bottomX = cx;
const bottomY = cy - tileHeight / 2;
const leftX = cx - tileWidth / 2;
const leftY = cy;
const topX = cx;
const topY = cy + tileHeight / 2;
// 绘制菱形路径
graphics.moveTo(rightX, rightY);
graphics.lineTo(bottomX, bottomY);
graphics.lineTo(leftX, leftY);
graphics.lineTo(topX, topY);
graphics.close(); // 闭合路径
}
}
graphics.stroke(); // 绘制路径
}
通过位置绘制网格
/**
* 通过位置绘制网格
* @param drawNode
* @param x
* @param y
*/
drawGridByGrid(drawNode: Node, x: number, y: number) {
let graphics = drawNode.getComponent(Graphics);
if (!graphics) {
graphics = drawNode.addComponent(Graphics);
}
const mapWidth = this._mapWidth; // 地图行数
const mapHeight = this._mapHeight; // 地图列数
const tileWidth = this._tileWidth; // 图块宽度
const tileHeight = this._tileHeight; // 图块高度
graphics.lineWidth = 2;
graphics.strokeColor = Color.BLACK;
let orgirinX = mapHeight / 2 * tileWidth - (mapWidth * tileWidth + (mapHeight - mapWidth) * (tileWidth / 2)) / 2;
let orgirinY = (mapWidth * tileHeight + (mapHeight - mapWidth) * (tileHeight / 2)) / 2 - tileHeight / 2;
const cx = orgirinX + (x - y) * (tileWidth / 2);
const cy = orgirinY - (x + y) * (tileHeight / 2); // Y轴取反,向下延伸
// 计算菱形的四个顶点
const rightX = cx + tileWidth / 2;
const rightY = cy;
const bottomX = cx;
const bottomY = cy - tileHeight / 2;
const leftX = cx - tileWidth / 2;
const leftY = cy;
const topX = cx;
const topY = cy + tileHeight / 2;
// 绘制菱形路径
graphics.moveTo(rightX, rightY);
graphics.lineTo(bottomX, bottomY);
graphics.lineTo(leftX, leftY);
graphics.lineTo(topX, topY);
graphics.close(); // 闭合路径
graphics.stroke(); // 绘制路径
}
绘制地图网格区域
/**
* 绘制地图网格区域
*/
drawMapGridArea(drawNode: Node, width: number, height: number) {
let graphics = drawNode.getComponent(Graphics);
if (!graphics) {
graphics = drawNode.addComponent(Graphics);
}
const mapWidth = width; // 地图行数
const mapHeight = height; // 地图列数
const tileWidth = this._tileWidth; // 图块宽度
const tileHeight = this._tileHeight; // 图块高度
graphics.fillColor.fromHEX('#ff00007F');
// 遍历所有格子
let orgirinX = mapHeight / 2 * tileWidth - (mapWidth * tileWidth + (mapHeight - mapWidth) * (tileWidth / 2)) / 2;
let orgirinY = (mapWidth * tileHeight + (mapHeight - mapWidth) * (tileHeight / 2)) / 2 - tileHeight / 2;
for (let i = 0; i < mapWidth; i++) {
for (let j = 0; j < mapHeight; j++) {
// 计算当前格子的中心坐标(调整Y轴方向)
const cx = orgirinX + (i - j) * (tileWidth / 2);
const cy = orgirinY - (i + j) * (tileHeight / 2); // Y轴取反,向下延伸
// 计算菱形的四个顶点
const rightX = cx + tileWidth / 2;
const rightY = cy;
const bottomX = cx;
const bottomY = cy - tileHeight / 2;
const leftX = cx - tileWidth / 2;
const leftY = cy;
const topX = cx;
const topY = cy + tileHeight / 2;
// 绘制菱形路径
graphics.moveTo(rightX, rightY);
graphics.lineTo(bottomX, bottomY);
graphics.lineTo(leftX, leftY);
graphics.lineTo(topX, topY);
graphics.close(); // 闭合路径
}
}
graphics.fill(); // 绘制区域
}
寻路的引入
import PF from 'pathfinding';
注意格子的对应
假如有一个地图为10*2的格子,width =10,height = 2
则grid = Array(height ).fill(1).map(() => Array(width ).fill(1))
1.地图xy轴空位对应grid数组索引空位
如果地图上的(0,1)为空位格子,则grid[1][0] = 0;
2.grid上的数组索引空位对应地图上xy轴的空位
如果grid[1,0]为空位0,则对应地图上(0,1) 为空位
当找grid的路径的时候 则以grid为二维地图,找到的路径是以grid地图x轴和y轴得到的最表索引,二不是数组的索引
比如
var matrix = [
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 1],
[0, 0, 1, 0, 0],
];
var grid = new PF.Grid(matrix);
找到从 (1, 2) 到 (4, 2) 的路径,(注意:起点和终点都应该可以行走):
var path = finder.findPath(1, 2, 4, 2, grid);
path将是:
[ [ 1, 2 ], [ 1, 1 ], [ 2, 1 ], [ 3, 1 ], [ 3, 2 ], [ 4, 2 ] ]