F=G(已花费)+H(将花费);
G:直线花费10点。斜着走花费14点。
A* 算法的核心是,确定F花费最少的节点,并将节点记录下来。
1建立节点信息类,用以处理节点。
2确定初始节点
Node
root =
new
Node
(start);
3利用BFS思想,确定可以拓展的节点
4.在确定可拓展节点前,拓展队列中最小花费的节点,作为将要拓展节点的父节点。(父节点唯一)
5.在可扩展节点处,实例新的节点信息,确定父节点,并计算当前节点的F、G、H值。(计算与终点的预估值H)(G为已花费)
核心在于F值的大小会影响优先级。
6,当节点坐标与终点坐标重合时,即找到目标,通过循环,将此线路的父节点压入栈中。
7.通过读取栈中的值,可以确定路线。
public
class
Node
{
//坐标
public
int
X, Y;
//消耗
public
int
F, G, H;
//父节点
public
Node
Parent;
//计算H值
public
void
CalculateH(
Vector2
end) {
this
.H = (
int
)(10 * (
Mathf
.Abs(end.x - X) +
Mathf
.Abs(end.y - Y)));
}
public
void
CalculateF() {
this
.F =
this
.G +
this
.H;
}
public
Node(
int
x,
int
y,
Node
parent=
null
) {
this
.X = x;
this
.Y = y;
this
.Parent = parent;
}
public
Node(
Vector2
point,
Node
parent =
null
)
{
this
.X =(
int
)point.x;
this
.Y = (
int
)point.y;
this
.Parent = parent;
}
}
#region
Segment
public
static
Stack
<
Vector2
> path =
new
Stack
<
Vector2
>();
Vector2
start;
Vector2
end;
public
const
int
RowCount = 7;
public
const
int
ColCount = 9;
byte
[,] mapData =
new
byte
[RowCount, ColCount];
Transform
player;
Vector3
moveDir;
Vector3
targer;
#endregion
#region
Mothed
private
void
Start()
{
//LoadMapData();
//CreateMap();
//GetStartEnd();
//BFS();
//player = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
//player.transform.position = GetPosition(start);
//targer = GetPosition(path.Peek());
}
public
void
Update()
{
moveDir = (targer - player.position).normalized;
player.Translate(moveDir*
Time
.deltaTime);
if
(
Vector3
.Distance(player.transform.position,targer)<0.1f)
{
path.Pop();
if
(path.Count==0)
{
this
.enabled =
false
;
}
else
{
targer = GetPosition(path.Peek());
}
}
}
//获取游戏数据
private
void
LoadMapData()
{
string
path =
Application
.dataPath +
"/Map/map.txt"
;
StreamReader
sr =
new
StreamReader
(path);
string
result = sr.ReadToEnd();
string
[] data = result.Split(
new
string
[] {
"\r\n"
}, System.
StringSplitOptions
.None);
for
(
int
i = 0; i < RowCount; i++)
{
for
(
int
j = 0; j < ColCount; j++)
{
mapData[i, j] =
byte
.Parse(data[i][j].ToString());
}
}
}
//生成地图数据
public
void
CreateMap()
{
GameObject
Roads =
new
GameObject
(
"Roads"
);
GameObject
red =
Resources
.Load(
"red"
,
typeof
(
GameObject
))
as
GameObject
;
GameObject
blue =
Resources
.Load(
"blue"
,
typeof
(
GameObject
))
as
GameObject
;
GameObject
yellow =
Resources
.Load(
"yellow"
,
typeof
(
GameObject
))
as
GameObject
;
for
(
int
i = 0; i < RowCount; i++)
{
for
(
int
j = 0; j < ColCount; j++)
{
GameObject
road =
null
;
switch
(mapData[i, j])
{
case
0:
road = Instantiate(red)
as
GameObject
;
break
;
case
1:
road =
GameObject
.CreatePrimitive(
PrimitiveType
.Cube);
break
;
case
2:
road = Instantiate(blue)
as
GameObject
;
break
;
case
9:
road = Instantiate(yellow)
as
GameObject
;
break
;
default
:
road =
GameObject
.CreatePrimitive(
PrimitiveType
.Cube);
break
;
}
road.transform.SetParent(Roads.transform);
road.transform.position = GetPosition(i, j);
road.transform.localScale =
Vector3
.one * 0.8f;
road.name = i.ToString() +
"_"
+ j.ToString();
}
}
}
Vector3
GetPosition(
int
x,
int
y)
{
int
pos_x = -RowCount / 3 + y;
int
pos_y = ColCount / 3 + x;
return
new
Vector3
(pos_x, 0, pos_y);
}
Vector3
GetPosition(
Vector2
pos)
{
int
pos_x = -RowCount / 3 + (
int
)pos.y;
int
pos_y = ColCount / 3 + (
int
)pos.x;
return
new
Vector3
(pos_x, 1, pos_y);
}
void
GetStartEnd()
{
for
(
int
i = 0; i < mapData.GetLength(0); i++)
{
for
(
int
j = 0; j < mapData.GetLength(1); j++)
{
if
(mapData[i, j] == 0)
{
start.x = i;
start.y = j;
}
else
if
(mapData[i, j] == 9)
{
end.x = i;
end.y = j;
Debug
.Log(
new
Vector2
(i, j));
}
}
}
}
List
<
Node
> list =
new
List
<
Node
>();
List
<
Node
> visited =
new
List
<
Node
>();
private
Vector2
[] dirs =
new
Vector2
[] {
Vector2
.up,
Vector2
.down,
Vector2
.left,
Vector2
.right,
new
Vector2
(1, 1),
new
Vector2
(-1, 1),
new
Vector2
(1, -1),
new
Vector2
(-1, -1) };
void
BFS()
{
Node
root =
new
Node
(start);
list.Add(root);
while
(list.Count > 0)
{
//f值排序
list.Sort(Comparer);
Node
node = list[0];
list.Remove(node);
//移除
visited.Add(node);
//添加访问节点
for
(
int
i = 0; i < dirs.Length; i++)
{
Vector2
point;
point.x = node.X + dirs[i].x;
point.y = node.Y + dirs[i].y;
if
(IsOk(point))
{
Node
n =
new
Node
(point, node);
n.G = i > 3 ? node.G + 14 : node.G + 10;
n.CalculateH(end);
n.CalculateF();
list.Add(n);
if
(point == end)
{
Debug
.Log(
"find"
);
Node
p = n;
while
(p !=
null
)
{
Debug
.Log(p.X +
"\t"
+ p.Y);
path.Push(
new
Vector2
(p.X,p.Y));
p = p.Parent;
}
return
;
}
}
}
}
}
private
int
Comparer(
Node
x,
Node
y)
{
if
(x.F == y.F)
{
return
0;
//表示不交互位置
}
else
if
(x.F > y.F)
{
return
1;
//表示交互位置
}
else
{
return
-1;
//表示不交换位置
}
}
public
bool
IsOk(
Vector2
point)
{
if
(point.x <= 0 || point.x >= mapData.GetLength(0) || point.y <= 0 || point.y >= mapData.GetLength(1))
{
return
false
;
}
if
(mapData[(
int
)point.x, (
int
)point.y] == 2)
{
return
false
;
}
for
(
int
i = 0; i < visited.Count; i++)
{
if
(visited[i].X == point.x && visited[i].Y == point.y)
{
return
false
;
}
}
for
(
int
i = 0; i < list.Count; i++)
{
if
(list[i].X == point.x && list[i].Y == point.y)
{
return
false
;
}
}
return
true
;
}
#endregion