unity 地图画格_Unity2D 四边形与六边形网格地图寻路 [新手]

毕业几年了, 每天用世界上最好的语言写crud, 有时也挺无聊。最近心血来潮稍微研究了一下Unity, 发现十分有趣, 很适合当作码农的日常休闲娱乐活动。

想象一下,要先做一个游戏,当然得先画个地图,有了地图,最先碰到的难题就是:如何寻路。百度一下寻路算法,其中著名的A星算法原理就是:把地图划分为网格,其中有些格子能通行(开放),有些格子不行(关闭)。

从起点开始,把附近的开放格子加入一个列表

从列表里选择一个最接近终点的格子,当作新起点

重复2、3步(每个格子只能被选中一次),直到起点等于终点。

简单概括一下,就是从起点开始扩散(像水流一样),然后问最先到达终点的水滴,你经过了哪些格子。

有了原理,就差代码了。(我先写了四边形A星寻路,又写了六边形A星寻路,发现代码是一样的,所以这里直接说共通的方法)

先定义一个astar方法, 需要传入6个参数:起点、终点、地图、可通行区域、距离估算方法、获取附近格子方法;需要返回一个结果:从起点到终点经过的格子列表

static List astar(Vector2Int from, Vector2Int to, Dictionary map, List passableValues,

Func getDistance, Func> getNeighbors)

{

var result = new List();

if (from == to)

{

result.Add(from);

return result;

}

Node finalNode; //一个链表节点,用来记录最先到达终点的水滴 List open = new List(); //建一个列表,逐渐储存所有连通的区域 if (findDest(new Node(null, from, getDistance(from, to), 0), open, map, to, out finalNode, passableValues, getDistance, getNeighbors))

{

//找到了,逆序链表,把每个格子加入结果中 while (finalNode != null)

{

result.Add(finalNode.pos);

finalNode = finalNode.preNode;

}

}

result.Reverse();

return result;

}

在上面的方法里,调用了findDest方法,这是一个递归方法,所做的工作就是寻路算法中的2、3步。

static bool findDest(Node currentNode, List openList,

Dictionary map, Vector2Int to, out Node finalNode, List passableValues,

Func getDistance, Func> getNeighbors)

{

if (currentNode == null) {

//所有和起点连通的格子都试过了,水流还是无法到达终点 finalNode = null;

return false;

}

else if (currentNode.pos == to)

{

//水流抵达了终点 finalNode = currentNode;

return true;

}

currentNode.open = false;

openList.Add(currentNode);

//foreach把附近的开放格子加入列表中(水流扩散) foreach (var item in getNeighbors(currentNode.pos))

{

if (map.ContainsKey(item) && passableValues.Contains(map[item]))

{

findTemp(openList, currentNode, item, to, getDistance);

}

}

//递归迭代新起点 var next = openList.FindAll(obj => obj.open).Min();

return findDest(next, openList, map, to, out finalNode, passableValues, getDistance, getNeighbors);

}

上面两个方法已经实现了原理的核心部分,接下来要考虑的,是在四边形或六边形寻路中,如何调用方法astar.

先来看四边形寻路的实现方法:

public static List find4(Vector2Int from, Vector2Int to, Dictionary map, List passableValues)

{

//距离估算方法 Func getDistance = delegate (Vector2Int a, Vector2Int b)

{

float xDistance = Mathf.Abs(a.x - b.x);

float yDistance = Mathf.Abs(a.y - b.y);

return xDistance * xDistance + yDistance * yDistance; //标准情况下,这里应该返回平方根 };

//获取附近的格子,上下左右 Func> getNeighbors = delegate (Vector2Int pos)

{

var neighbors = new List();

neighbors.Add(new Vector2Int(pos.x, pos.y + 1));

neighbors.Add(new Vector2Int(pos.x, pos.y - 1));

neighbors.Add(new Vector2Int(pos.x + 1, pos.y));

neighbors.Add(new Vector2Int(pos.x - 1, pos.y));

return neighbors;

};

//调用寻路算法 return astar(from, to, map, passableValues, getDistance, getNeighbors);

}

六边形寻路和上面的方法类似:

//第一个六边形寻路算法 public static List find6X(Vector2Int from, Vector2Int to, Dictionary map, List passableValues)

{

//估算距离 Func getDistance = delegate (Vector2Int a, Vector2Int b)

{

float xDistance = Mathf.Abs(a.x - b.x);

float yDistance = Mathf.Abs(a.y - b.y) * Mathf.Sqrt(3);

return xDistance * xDistance + yDistance * yDistance;

};

//获取附近的6个格子 Func> getNeighbors = delegate (Vector2Int pos)

{

var neighbors = new List();

neighbors.Add(new Vector2Int(pos.x + 1, pos.y + 1));

neighbors.Add(new Vector2Int(pos.x - 1, pos.y + 1));

neighbors.Add(new Vector2Int(pos.x + 1, pos.y - 1));

neighbors.Add(new Vector2Int(pos.x - 1, pos.y - 1));

neighbors.Add(new Vector2Int(pos.x - 2, pos.y));

neighbors.Add(new Vector2Int(pos.x + 2, pos.y));

return neighbors;

};

//调用寻路算法 return astar(from, to, map, passableValues, getDistance, getNeighbors);

}

//第二个六边形寻路算法 public static List find6Y(Vector2Int from, Vector2Int to, Dictionary map, List passableValues)

{

//估算距离 Func getDistance = delegate (Vector2Int a, Vector2Int b)

{

float xDistance = Mathf.Abs(a.x - b.x) * Mathf.Sqrt(3);

float yDistance = Mathf.Abs(a.y - b.y);

return xDistance * xDistance + yDistance * yDistance;

};

//获取附近的6个格子 Func> getNeighbors = delegate (Vector2Int pos)

{

var neighbors = new List();

neighbors.Add(new Vector2Int(pos.x + 1, pos.y + 1));

neighbors.Add(new Vector2Int(pos.x - 1, pos.y + 1));

neighbors.Add(new Vector2Int(pos.x + 1, pos.y - 1));

neighbors.Add(new Vector2Int(pos.x - 1, pos.y - 1));

neighbors.Add(new Vector2Int(pos.x, pos.y - 2));

neighbors.Add(new Vector2Int(pos.x, pos.y + 2));

return neighbors;

};

//调用寻路算法 return astar(from, to, map, passableValues, getDistance, getNeighbors);

}

上面的六边形寻路有两个方法, 是因为我把六边形的地图组合分成了两种情况:

一种是这样的,网格 按行错开形成的六边形网格,调用方法 find6X

另一种是,网格 按列错开形成的六边形网格,调用方法 find6Y

本文的页顶图(来自百度)就是按列错开的六边形网格,需要调用find6Y来寻路。(也考虑通过旋转矩阵,来实现六边形寻路统一调用,但难度好像超出了我的智商)

具体的实现效果,差不多是这样子:

初学Unity,写的不好的地方,还希望各位高手多多赐教。

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页