A*寻路可以说是老生常谈的内容了,我这里要讲的是项目里碰到一个关于如何给A*做地图烘焙,到如何做算法结构调整优化。算法是另一个程序写的,我只是进行了一些补充和筛选,后续优化还会继续更新。
先说一下功能的背景和需求,我们制作的是一款(……以下省略1W字介绍,我拉点关键信息出来)。
2D游戏,要做一个点击移动的功能,类似于大地图寻路,2D游戏我们没有选择网格烘焙(NavMesh),而是选择了把地图数据洪培成一张图片,标识可行走区域和不可行走区域来做A*算法进行寻路。
先来看一下地图样式,
同事推荐的国外的一个论坛:
https://www.redblobgames.com/grids/hexagons/?tdsourcetag=s_pcqq_aiomsg
我当时一看我去!惊了!我们要做六边形寻路这种高端大气上档次的东西吗? 废话不多说,折腾了几天后发现很复杂,而且算法复杂度极高,难以优化,最终改成了点对点的寻路,即所有的坐标定义成一个结构体,墙体由一个哈希结构存储(取数据时间复杂度低)。
地图采集由编辑器工具生成(实时生成开销较大),
废话不多说,上代码:
using ProtoBuf;
using System.Collections.Generic;
using UnityEngine;
namespace Client
{
public static class AStarHelper
{
/// <summary>
/// 采集换算倍率
/// </summary>
public const float samplingNum = 5f;
/// <summary>
/// 数据中心点放大倍率
/// </summary>
public const float CenterScaling = 1000f;
public const string AStarBytesPath = "/Resources/AstarData/Bytes";
public static AStarData GetAStarData()
{
return BytesConvertHelper.LoadFromFile<AStarData>("AstarData/aStar");
}
public static Location GetLocation(Vector3 worldPos, AstarData aStar, Texture2D texture)
{
return new Location
(
(int)((worldPos.x - aStar.CenterX / CenterScaling) * samplingNum + texture.width / 2)
,
(int)((worldPos.y - aStar.CenterY / CenterScaling) * samplingNum + texture.height / 2)
);
}
public static SquareGrid SetNewGrid(int style, int id, out Texture2D texture)
{
texture = Resources.Load<Texture2D>("AstarData/" + style + "/" + id);
if (texture == null)
return null;
SquareGrid grid = new SquareGrid(texture.width, texture.height);
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
if (texture.GetPixel(i, j) != Color.blue)
{
grid.walls.Add(new Location(i, j));
}
}
}
return grid;
}
public static Vector3 GetPos(Location location, Texture2D