通常项目开发中,会遇到自动寻路功能
在Unity中利用自带的NavMesh导航可以实现自动寻路功能,操作简单
还有一种经常收开发者喜欢的A星寻路,下面简单介绍一下A星算法在Unity的实现过程
在unity中把地面看成是N个坐标做组成,那么这个坐标集合就是,世界坐标原点,也就是(0,0)点。
利用当前坐标对目标坐标判断的最小值 ,障碍物的坐标在坐标集合中移除,那么人物的行走路线就出现了;
一下是实现的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
public class AStar : MonoBehaviour {
private const int mapWidth=30;
private const int mapHeigh=20;
private Point [,]map=new Point[mapWidth,mapHeigh];
public CanvasGroup star;
public CanvasGroup nav;
private bool ismove=false;
// Use this for initialization
void Start () {
InitMap ();
Point start = map [2, 3];
CreatPlayer (2,3);
Point end = map [10, 2];
FindPath (start,end);
Vector3 []newpath= ShowPath (start,end);
MoveEndPoint (player, newpath);
}
private GameObject hitObj;
void Update()
{
if (ismove == false) {
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast (ray, out hitInfo)) {
if (hitInfo.collider.gameObject == null) {
Debug.Log ("NULL");
return;
} else {
ismove = true;
hitObj = hitInfo.collider.gameObject;
hitObj.GetComponent<BoxCollider> ().enabled = false;
hitobj.Add (hitObj);
int a = (int)player.transform.position.x;
int b = (int)player.transform.position.z;
int c = (int)hitInfo.collider.gameObject.transform.position.x;
int d = (int)hitInfo.collider.gameObject.transform.position.z;
FindPath (map [a, b], map [c, d]);
Vector3[] newpath = ShowPath (map [a, b], map [c, d]);
MoveEndPoint (player, newpath);
star.blocksRaycasts = false;
star.interactable = false;
nav.blocksRaycasts = false;
nav.interactable = false;
}
}
}
} else
{
return;
}
}
private Hashtable args;
private void MoveEndPoint(GameObject obj, Vector3[] paths)
{
args = new Hashtable ();
args.Add ("speed",10);
args.Add ("path",paths);
args.Add ("easeType",iTween.EaseType.linear);
args.Add ("oncomplete","AnimationEnd");
args.Add ("oncompleteparams","end");
args.Add ("oncompletetarget",gameObject);
iTween.MoveTo (obj, args);
ismove = true;
}
private List<GameObject>hitobj=new List<GameObject> ();
private void AnimationEnd(){
ismove = false;
Debug.Log ("动画结束");
map [(int)player.transform.position.x, (int)player.transform.position.z].Parent = null;
Destroy (endCube);
if (hitobj.Count>=2) {
hitobj [0].GetComponent<BoxCollider> ().enabled = true;
hitobj.RemoveAt (0);
}
star.blocksRaycasts = true;
star.interactable = true;
nav.blocksRaycasts = true;
nav.interactable = true;
}
private GameObject endCube;
private Vector3[] ShowPath(Point strat, Point end)
{
Point temp = end;
List<Vector3> points = new List<Vector3> ();
while (true)
{
//Debug.Log (temp.X+" sd "+temp.Y);
points.Add (new Vector3(temp.X,0,temp.Y) );
Color c = Color.gray;
if (temp == strat) {
} else if (temp == end) {
c = Color.red;
CreatCube (temp.X, temp.Y, c);
}
if (temp.Parent==null)
break;
temp = temp.Parent;
}
Vector3[] paths = points.ToArray ();
Array.Reverse (paths);
return paths;
}
private void CreatMap(int x,int y,bool judge)
{
GameObject go = GameObject.CreatePrimitive (PrimitiveType.Cube);
go.AddComponent<AStarMap> ();
go.transform.position = new Vector3 (x,-1,y);
if (map [x, y].IsWall) {
go.GetComponent<BoxCollider> ().enabled = false;
}
if (judge==true) {
//退出 go.GetComponent<MeshRenderer> ().material.color = Color.black;
hitobj.Add (go);
go.GetComponent<BoxCollider> ().enabled = false;
}
}
private void CreatCube(int x,int y,Color color)
{
GameObject go = GameObject.CreatePrimitive (PrimitiveType.Cube);
go.transform.position = new Vector3 (x,0,y);
go.GetComponent<MeshRenderer> ().material.color = color;
go.GetComponent<BoxCollider> ().enabled = false;
endCube = go;
}
GameObject player;
private void CreatPlayer(int x,int y)
{
GameObject go = GameObject.CreatePrimitive (PrimitiveType.Sphere);
go.transform.position = new Vector3 (x,0,y);
go.GetComponent<MeshRenderer> ().material.color = Color.green;
go.GetComponent<SphereCollider> ().enabled = false;
player = go;
}
private void InitMap()
{
for (int i = 0; i < mapWidth; i++) {
for (int j = 0; j < mapHeigh; j++) {
map [i, j] = new Point (i,j);
}
}
map [2, 15].IsWall = true;
map [2, 18].IsWall = true;
map [2, 19].IsWall = true;
map [5, 13].IsWall = true;
map [5, 12].IsWall = true;
map [5, 13].IsWall = true;
map [4, 2].IsWall = true;
map [4, 3].IsWall = true;
map [4, 4].IsWall = true;
map [5, 2].IsWall = true;
map [8, 3].IsWall = true;
map [10, 4].IsWall = true;
map [6, 2].IsWall = true;
map [6, 3].IsWall = true;
map [6, 4].IsWall = true;
map [7, 8].IsWall = true;
map [12, 5].IsWall = true;
map [12, 6].IsWall = true;
map [12, 7].IsWall = true;
map [12, 8].IsWall = true;
map [18, 3].IsWall = true;
map [18, 15].IsWall = true;
map [18, 16].IsWall = true;
map [18, 17].IsWall = true;
map [20, 12].IsWall = true;
map [20, 18].IsWall = true;
map [20, 19].IsWall = true;
map [20, 10].IsWall = true;
map [22, 12].IsWall = true;
map [22, 5].IsWall = true;
map [22, 6].IsWall = true;
map [22, 10].IsWall = true;
map [25, 2].IsWall = true;
map [25, 8].IsWall = true;
map [25, 9].IsWall = true;
map [25, 10].IsWall = true;
map [14, 15].IsWall = true;
map [14, 16].IsWall = true;
map [14, 17].IsWall = true;
map [14, 18].IsWall = true;
map [28, 5].IsWall = true;
map [28, 6].IsWall = true;
map [28, 7].IsWall = true;
map [28, 8].IsWall = true;
for (int i = 0; i < mapWidth; i++) {
for (int j = 0; j < mapHeigh; j++) {
if (map[i,j].IsWall) {
CreatCube (i, j, Color.blue);
}
if (i == 10 && j == 2) {
CreatMap (i,j,true);
} else
{
CreatMap (i,j,false);
}
}
}
}
private void FindPath(Point start,Point end)
{
List<Point> openList = new List<Point> ();
List<Point> closeList = new List<Point> ();
openList.Add (start);
while(openList.Count>0)
{
Point point = FindMinFOfPoint (openList);
openList.Remove (point);
closeList.Add (point);
List<Point> surroundPoints = GetSurroundPoints (point);
PointsFilter (surroundPoints,closeList);
foreach (Point surroundPoint in surroundPoints) {
if (openList.IndexOf (surroundPoint) > -1)
{
float nowG = CarcG (surroundPoint, point);
if (nowG < surroundPoint.G) {
surroundPoint.UpdateParent (point, nowG);
}
} else
{
surroundPoint.Parent = point;
CarcF (surroundPoint,end);
openList.Add (surroundPoint);
}
}
//判断一下
if (openList.IndexOf(end)>-1) {
break;
}
}
}
private void PointsFilter(List<Point>src,List<Point>closePoint){
foreach (Point p in closePoint) {
if (src.IndexOf(p)>-1) {
src.Remove (p);
}
}
}
private List<Point>GetSurroundPoints(Point point)
{
Point up = null, down = null, left = null, right = null;
Point lu = null, ru = null, ld = null, rd = null;
if (point.Y < mapHeigh - 1) {
up = map [point.X, point.Y + 1];
}
if (point.Y>0) {
down = map [point.X, point.Y-1];
}
if (point.X>0) {
left = map [point.X - 1, point.Y];
}
if (point.X<mapWidth-1) {
right = map [point.X + 1, point.Y];
}
if (up!=null&&left!=null) {
lu = map [point.X - 1, point.Y + 1];
}
if (up!=null&&right!=null) {
ru = map [point.X + 1, point.Y + 1];
}
if (down!=null&&left!=null) {
ld = map [point.X - 1, point.Y - 1];
}
if (down!=null&&right!=null) {
rd = map [point.X + 1, point.Y - 1];
}
List<Point> list = new List<Point> ();
if (down!=null&&down.IsWall==false) {
list.Add (down);
}
if (up!=null&&up.IsWall==false) {
list.Add (up);
}
if (left!=null&&left.IsWall==false) {
list.Add (left);
}
if (right!=null&&right.IsWall==false) {
list.Add (right);
}
if (lu!=null&&lu.IsWall==false&&left.IsWall==false&&up.IsWall==false) {
list.Add(lu);
}
if (ld!=null&&ld.IsWall==false&&left.IsWall==false&&down.IsWall==false) {
list.Add(ld);
}
if (ru!=null&&ru.IsWall==false&&right.IsWall==false&&up.IsWall==false) {
list.Add(ru);
}
if (rd!=null&&rd.IsWall==false&&right.IsWall==false&&down.IsWall==false) {
list.Add(rd);
}
return list;
}
private Point FindMinFOfPoint(List<Point>openList)
{
float f = float.MaxValue;
Point temp = null;
foreach (Point p in openList)
{
if (p.F<f)
{
temp = p;
f = p.F;
}
}
return temp;
}
private float CarcG(Point now,Point parent)
{
return Vector2.Distance (new Vector2 (now.X, now.Y), new Vector2 (parent.X, parent.Y))+parent.G;
}
private void CarcF(Point now,Point end)
{
//F=G+H
float h=Mathf.Abs(now.X-end.X)+Mathf.Abs(now.Y-end.Y);
float g=0;
if (now.Parent == null) {
g = 0;
} else
{
g=Vector2.Distance (new Vector2 (now.X, now.Y), new Vector2 (now.Parent.X, now.Parent.Y))+now.Parent.G;
}
float f = g + h;
now.F = f;
now.G = g;
now.H = h;
}
}
NavMash系统自带的组件,使用很简单,就不作过多介绍。项目中也已经实现