略,网上可搜到
流程图通过processon制作
各个坐标节点为单独的gameObject,并自带脚本:
using UnityEngine;
using System.Collections;
public class AStarNodeSC : MonoBehaviour {
public bool obstacle=false;
public float CostG=0;
public float CostH=0;
public float CostF
{
get
{
return this.CostG + this.CostH;
}
}
public GameObject previousNode=null;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
场景控制脚本,各个成员,包括根据流程图写出的寻路方法:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class AStarNew : MonoBehaviour {
public Ray AStarRay;
public RaycastHit AStarHit;
public RaycastHit AStarHit2;
public float CostG;
public float CostH;
public GameObject AStarNode;
public GameObject start;
public static GameObject end;
public int SDflag=0;
public float timespan=0;
public static List OpenList=new List();
public static List ClostList=new List();
public static GameObject minnode;
public static List adjpoints = new List ();
public static GameObject routestart;
public static int minnodeint;
public GameObject AStarSearch(float x1,float y1,float x2,float y2,GameObject currentnode){
adjpoints.Add (new Vector3 (x1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 + 1,1f));
foreach (Vector3 temp in adjpoints) {
if (Physics.Linecast (new Vector3(temp.x,temp.y,-10), temp, out AStarHit2)) { //if the node is within the map
if (ClostList.Contains(AStarHit2.transform.gameObject)) {
continue;
}
if (AStarHit2.transform.gameObject.GetComponent ().obstacle) {
continue;
}
if (OpenList.Contains (AStarHit2.transform.gameObject)) {
this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);
if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}
if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}
if (AStarHit2.transform.gameObject.GetComponent ().CostG > this.CostG) {
AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
}
continue;
}
if (!OpenList.Contains (AStarHit2.transform.gameObject) && !ClostList.Contains (AStarHit2.transform.gameObject)) {
this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);
if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}
if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}
AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
AStarHit2.transform.gameObject.GetComponent ().CostH = Mathf.Abs (AStarHit2.transform.position.x - x2) + Mathf.Abs (AStarHit2.transform.position.y - y2);
if (AStarHit2.transform.gameObject.GetComponent ().CostH >= -0.00001&&AStarHit2.transform.gameObject.GetComponent ().CostH <= 0.00001) {
return AStarHit2.transform.gameObject;
}
OpenList.Add (AStarHit2.transform.gameObject);
AStarHit2.transform.gameObject.GetComponent().material.color=Color.yellow;
continue;
}
}
else{
continue;
}
}
adjpoints.RemoveRange (0, adjpoints.Count);
OpenList.Remove (currentnode);
ClostList.Add (currentnode);
currentnode.GetComponent ().material.color = Color.gray;
if (OpenList.Count == 0) {
return null;
}
minnode = OpenList [0];
minnodeint = 0;
for(int i=0;i
if (minnode.GetComponent ().CostF > OpenList[i].GetComponent ().CostF) {
minnode = OpenList[i];
minnodeint=i;
}
}
return OpenList [minnodeint];
}
场景控制脚本,在Start里对场景进行初始设置,以及在Update内通过鼠标设置障碍,起始点,终点并调用寻路方法:
void Start () {
int column = 50;
int line = 50;
for(int i=0;i
for(int j=0;j
GameObject aStarNodeClOne=Instantiate(AStarNode,new Vector2(i,j),AStarNode.transform.rotation)as GameObject;
}
}
Camera.main.transform.position = new Vector3 (column/2, line/2,-15);
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0) && SDflag == 0){
AStarRay= Camera.main.ScreenPointToRay (Input.mousePosition);
if(Physics.Raycast (AStarRay, out AStarHit, 1000.3f)){
AStarHit.transform.gameObject.GetComponent ().material.color = Color.red;
AStarHit.transform.gameObject.GetComponent ().obstacle = true;
}
}
if (Input.GetMouseButton (1) && SDflag == 0) {
AStarRay = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (AStarRay, out AStarHit, 1000.3f)) {
print ("hit");
SDflag = 1;
start = AStarHit.transform.gameObject;
AStarHit.transform.gameObject.GetComponent ().material.color = Color.blue;
}
}
if(SDflag==1){
timespan+=Time.deltaTime;
}
if (Input.GetMouseButton (1) && SDflag == 1 && timespan > 1) {
AStarRay = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (AStarRay, out AStarHit, 1000.3f)) {
print ("hit");
timespan = 0;
SDflag = 2;
end = AStarHit.transform.gameObject;
AStarHit.transform.gameObject.GetComponent ().material.color = Color.yellow;
}
}
if (SDflag == 2) {
start.GetComponent().CostH=Mathf.Abs (start.transform.position.x-end.transform.position.x) + Mathf.Abs (start.transform.position.y-end.transform.position.y);
OpenList.Add(start);
routestart=AStarSearch(start.transform.position.x,start.transform.position.y,end.transform.position.x,end.transform.position.y,start);
for(int i=0;routestart.GetComponent().CostH>=0.1f;i++)
{
routestart=AStarSearch(routestart.transform.position.x,routestart.transform.position.y,end.transform.position.x,end.transform.position.y,routestart);
}
SDflag=3;
for(int i=0;routestart.GetComponent().previousNode!=null;i++){
routestart.transform.gameObject.GetComponent().material.color=Color.green;
routestart=routestart.GetComponent().previousNode;
}
}
}
}
结合Unity Linecast方法与A星寻路算法做出以下效果,红色点为障碍物,灰色表示在关闭列表内,黄色在开放列表内,绿色为最捷路径:
除了利用for循环调用寻路方法,也可以将此方法改为递归,但是在节点数过多时会出现堆栈溢出异常:
public GameObject AStarSearch(float x1,float y1,float x2,float y2,GameObject currentnode){
adjpoints.Add (new Vector3 (x1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 + 1,1f));
foreach (Vector3 temp in adjpoints) {
if(!Physics.Linecast (new Vector3(temp.x,temp.y,-10), temp, out AStarHit2)){
continue;
}
if (Physics.Linecast (new Vector3(temp.x,temp.y,-10), temp, out AStarHit2)) { //if the node is within the map
if (ClostList.Contains(AStarHit2.transform.gameObject)) {
continue;
}
if (AStarHit2.transform.gameObject.GetComponent ().obstacle) {
continue;
}
if (OpenList.Contains (AStarHit2.transform.gameObject)) {
this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);
if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}
if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}
if (AStarHit2.transform.gameObject.GetComponent ().CostG > this.CostG) {
AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
}
continue;
}
if (!OpenList.Contains (AStarHit2.transform.gameObject) && !ClostList.Contains (AStarHit2.transform.gameObject)) {
this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);
if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}
if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}
AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
AStarHit2.transform.gameObject.GetComponent ().CostH = Mathf.Abs (AStarHit2.transform.position.x - x2) + Mathf.Abs (AStarHit2.transform.position.y - y2);
if (AStarHit2.transform.gameObject.GetComponent ().CostH >= -0.00001&&AStarHit2.transform.gameObject.GetComponent ().CostH <= 0.00001) {
return AStarHit2.transform.gameObject;
}
OpenList.Add (AStarHit2.transform.gameObject);
continue;
}
}
}
adjpoints.RemoveRange (0, adjpoints.Count);
OpenList.Remove (currentnode);
ClostList.Add (currentnode);
if (OpenList.Count == 0) {
return null;
}
minnode = OpenList [0]; //not sure
minnodeint = 0;
for(int i=0;i
if (minnode.GetComponent ().CostF > OpenList[i].GetComponent ().CostF) {
minnode = OpenList[i];
minnodeint=i;
}
}
return AStarSearch (OpenList[minnodeint].transform.position.x, OpenList[minnodeint].transform.position.y, end.transform.position.x, end.transform.position.y, OpenList[minnodeint]);
}
另外,以上代码虽然实现了A星寻路的思想但是不够优化,在节点数超过10000时搜寻速度不甚理想,因此只为展示思路。