游戏开发岗面试A*算法
Posted 头号理想
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏开发岗面试A*算法相关的知识,希望对你有一定的参考价值。
A*寻路来解决什么问题?
A*寻路来计算玩家行进最短路径
A*基本原理
不停的找周围的点,选出一个点作为起点,再循环的找,知道找到终点
A*详细原理
1.寻路消耗公式
f(寻路消耗)=g(离起点距离 分为两种 上下左右为1 其他四个角为1.4 根号2)+ h(离终点距离 使用曼哈顿街区的思想)
2.开启列表(所有点的存放)
3.关闭列表(最优点的存放)
每次判断最优点是否为终点 如果是 停止寻路,否则继续寻路
4.格子对象的父对象(用来确定最终的路径)
需求分析
需要一个格子类 寻路管理器(管理所有的格子)
开启列表 关闭列表
格子类
成员变量:
寻路消耗 f g h
父亲格子father
坐标 x y
格子类型 type
方法:
构造函数
寻路管理器类
成员变量:
格子数组 nodes
开启列表 openlist
关闭列表 clostlist
地图的边界 mapx mapy
方法:
初始化地图格子方法
寻找路径方法(起点,终点)
源码
网格类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum E_node_type
walk,//可以走
stop//不能走
//A*格子类
public class AStarNode
public float f;//寻路消耗
public float g;//距离起点距离
public float h;//距离终点距离
public AStarNode father;//父对象
//格子对象坐标
public int x;
public int y;
public E_node_type type;
public AStarNode(int x,int y ,E_node_type type)
//传入坐标和类型
this.x = x;
this.y = y;
this.type = type;
网格管理器类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//管理器
public class AStarManager
private static AStarManager Instance;
public static AStarManager instance
get
if(Instance == null)
Instance = new AStarManager();
return Instance;
private AStarNode[,] nodes;//地图相关对象容器
private List<AStarNode> openList;//开启列表
private List<AStarNode> closeList;//关闭列表
private int mapx;
private int mapy;
//宽高
public void initmapinfo(int x,int y)
//初始化地图信息
//根据宽高 创建格子
this.mapx = x;
this.mapy = y;
nodes = new AStarNode[x,y];//声明容器装多少个格子
for(int i = 0; i < x; i++)
for(int j = 0; i < y; j++)
AStarNode node = new AStarNode(i, j, Random.Range(0, 100) < 20 ? E_node_type.stop : E_node_type.walk);
//随机阻挡
//寻路方法
public List<AStarNode> findpath(Vector2 startpos,Vector2 endpos)
//首先判断传入点是否合法 (不是阻挡点)
//实际开发需要转换坐标
if (startpos.x < 0 || startpos.x >= mapx || startpos.y < 0 || startpos.y > mapy||
endpos.x < 0 || endpos.x >= mapx || endpos.y < 0 || endpos.y > mapy)
Debug.LogError("由于在地图边界外");
return null;//不合法
AStarNode start = nodes[(int)startpos.x, (int)startpos.y];
AStarNode end = nodes[(int)endpos.x, (int)endpos.y];
if (start.type == E_node_type.stop || end.type == E_node_type.stop)
Debug.LogError("该点是阻挡点");
return null;//不合法
openList.Clear();
closeList.Clear();//清空数据 防止影响
//把开始点初始化之后放入关闭列表中
start.father = null;
start.f = 0;
start.g = 0;
start.h = 0;
closeList.Add(start);
while (true)
//寻找周围的所有点
FindnearNodeToopenList(start.x - 1, start.y - 1, 1.4f, start, end);
FindnearNodeToopenList(start.x - 1, start.y, 1, start, end);
FindnearNodeToopenList(start.x - 1, start.y + 1, 1.4f, start, end);
FindnearNodeToopenList(start.x, start.y - 1, 1f, start, end);
FindnearNodeToopenList(start.x, start.y + 1, 1f, start, end);
FindnearNodeToopenList(start.x + 1, start.y - 1, 1.4f, start, end);
FindnearNodeToopenList(start.x + 1, start.y, 1f, start, end);
FindnearNodeToopenList(start.x + 1, start.y - 1, 1.4f, start, end);
if (openList.Count == 0)//开始列表为空 还没有找到终点
Debug.LogError("死路!");
return null;
//开启列表放入上边的八个点
openList.Sort(sortopenlist);//自定义排序
//放入关闭列表
closeList.Add(openList[0]);
start = openList[0];//找到的这个点变成新的起点 进行新的计算
openList.RemoveAt(0);//移除
if (start == end)
//寻路结束
List<AStarNode> path = new List<AStarNode>();
path.Add(end);
while (end.father != null)
path.Add(end.father);
end = end.father;
//翻转一下
path.Reverse();
return path;//找到路径
private int sortopenlist(AStarNode a,AStarNode b)//自定义排序
if (a.f > b.f)
return 1;
else
return -1;
//把邻近的点放入开启列表中去
private void FindnearNodeToopenList(int x,int y,float g,AStarNode father,AStarNode end)
//边间检测
if (x < 0 || x >= mapx || y < 0 || y >= mapy)
return;
AStarNode node = nodes[x, y];
//判断是否是边界,阻挡
if (node == null||node.type==E_node_type.stop||openList.Contains(node)||closeList.Contains(node))
return;
//计算f值 f=g+h=起点距离+终点距离
node.father = father;//记录父对象
node.g = father.g + g;//父亲离起点距离 + 我离父亲距离=我离起点的距离
node.h = Mathf.Abs(end.x - node.x) + Mathf.Abs(end.y - node.y);//曼哈顿街区算法
node.f = node.g + node.h;
openList.Add(node);//存入开启了列表中
之后的测试实例我还会更新的 希望以上所写对大家有所帮助
2021.3.11更新
在上一场面试中 我和面试官聊到了很多A*算法相关的问题
其中有一个 面试官问 如果地图中有两种地形,一种是草地,一种是沙地
然后有一个角色优先考虑走沙地 问我怎么实现
我当时很快想到的就是 在A*算法中每个格子设置一个值 就作为草地和沙地的权重
优先选择权重较大的 比如设置草地为1 沙地为2 优先选择沙地
然后面试官还问了我一个问题:如何优化A*算法中角色移动的轨迹(使得路径尽量保持类似直线)
当时我没想到好的方法 只想到了将格子扩大 这样可以稍微优化
但是很明显这不是面试官想要的结果
然后面试结束之后 我回想起来 我们可以设置上一次路径的方向 优先选择方向相同的
比如上一步是向上走的 我们就给各个方向设置一个权重 离上一次的路线角度越小 权重越大 反之依然
最后我们还是找权重大的路线
以上是关于游戏开发岗面试A*算法的主要内容,如果未能解决你的问题,请参考以下文章
游戏开发面经我在阿里HRG面这关跪掉了,游戏客户端开发岗,总结一下(阿里 | 游戏 | 凉面面经)
游戏开发面经我在阿里HRG面这关跪掉了,游戏客户端开发岗,总结一下(阿里 | 游戏 | 凉面面经)
游戏开发面经我在阿里HRG面这关跪掉了,游戏客户端开发岗,总结一下(阿里 | 游戏 | 凉面面经)