A*算法核心类:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YSFrame
{
public class YsPath
{
private static Transform cubesGroups;
private static YsPath _instance;
//存储路径方格子
public List<Object> mPathPosList = new List<Object>();
public static void InitYsPath()
{
cubesGroups = GameObject.FindGameObjectWithTag("Groups").transform;
}
public static YsPath GetInsatnce
{
get
{
if (_instance == null)
{
_instance = new YsPath();
}
return _instance;
}
}
public void ClearGrid()
{
List<Object> _cubeList = new List<Object>();
for (int i = 0; i < cubesGroups.childCount; i++)
{
if (cubesGroups.GetChild(i).gameObject.activeInHierarchy)
{
_cubeList.Add(cubesGroups.GetChild(i).GetComponent<Object>());
}
}
for (int i = 0; i < _cubeList.Count; i++)
{
if (_cubeList[i].layer!=EA.LayerType.Obstancle)
{
//重新设置父节点
_cubeList[i].mParentPoint = null;
}
}
}
//寻路
public List<Object> FindPath(Object mStartPoint, Object mEndPoint)
{
if (mEndPoint.layer == EA.LayerType.Obstancle || mStartPoint.baseTransfrom.vector3 == mEndPoint.baseTransfrom.vector3||mEndPoint.type!=EA.ObjectType.Cube)
{
return null;
}
//开启列表
List<Object> openPointList = new List<Object>();
//关闭列表
List<Object> closePointList = new List<Object>();
openPointList.Add(mStartPoint);
while (openPointList.Count > 0)
{
//寻找开启列表中最小预算值的表格
Object minFPoint = FindPointWithMinF(openPointList);
//将当前表格从开启列表移除 在关闭列表添加
openPointList.Remove(minFPoint);
closePointList.Add(minFPoint);
//找到当前点周围的全部点
List<Object> surroundPoints = FindSurroundPoint(minFPoint);
//排除障碍物的点
for (int i = 0; i < surroundPoints.Count; i++)
{
if (surroundPoints[i].layer == EA.LayerType.Obstancle)
{
surroundPoints.Remove(surroundPoints[i]);
}
}
//在周围的点中,将关闭列表里的点移除掉
SurroundPointsFilter(surroundPoints, closePointList);
//寻路逻辑
foreach (var surroundPoint in surroundPoints)
{
if (openPointList.Contains(surroundPoint))
{
//计算下新路径下的G值(H值不变的,比较G相当于比较F值)
float newPathG = CalcG(surroundPoint, minFPoint);
if (newPathG < surroundPoint.mG)
{
surroundPoint.mG = newPathG;
surroundPoint.mF = surroundPoint.mG + surroundPoint.mH;
surroundPoint.mParentPoint = minFPoint;
}
}
else
{
//将点之间的
surroundPoint.mParentPoint = minFPoint;
CalcF(surroundPoint, mEndPoint);
openPointList.Add(surroundPoint);
}
}
//如果开始列表中包含了终点,说明找到路径
if (openPointList.IndexOf(mEndPoint) > -1)
{
break;
}
}
return ShowPath(mStartPoint, mEndPoint);
}
private List<Object> ShowPath(Object start, Object end)
{
mPathPosList.Clear();
Object temp = end;
while (true)
{
mPathPosList.Add(temp);
Color c = Color.white;
if (temp == start)
{
c = Color.green;
}
else if (temp == end)
{
c = Color.red;
}
if (temp.mParentPoint == null)
break;
temp = temp.mParentPoint;
}
return mPathPosList;
}
//寻找预计值最小的格子
private Object FindPointWithMinF(List<Object> openPointList)
{
float f = float.MaxValue;
Object temp = null;
foreach (Object p in openPointList)
{
if (p.mF < f)
{
temp = p;
f = p.mF;
}
}
return temp;
}
//寻找周围的全部点
private List<Object> FindSurroundPoint(Object point)
{
List<Object> list = new List<Object>();
判断周围的4个点是否在网格内/
Object up = null, down = null, left = null, right = null;
up = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(0, 0, 1));
down = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(0, 0, -1));
left = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(-1, 0, 0));
right = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(1, 0, 0));
/将可以经过的表格添加到开启列表中/
if (down != null && down.layer != EA.LayerType.Obstancle)
{
list.Add(down);
}
if (up != null && up.layer != EA.LayerType.Obstancle)
{
list.Add(up);
}
if (left != null && left.layer != EA.LayerType.Obstancle)
{
list.Add(left);
}
if (right != null && right.layer != EA.LayerType.Obstancle)
{
list.Add(right);
}
return list;
}
//根据点找对应的Object
public static Object GetObjectByPoints(Vector3 v3)
{
List<Object> cubeList=new List<Object>();
for (int i = 0; i < cubesGroups.childCount; i++)
{
if (cubesGroups.GetChild(i).gameObject.activeInHierarchy)
{
cubeList.Add(cubesGroups.GetChild(i).GetComponent<Object>());
}
}
for (int i = 0; i < cubeList.Count; i++)
{
if (cubeList[i].baseTransfrom.vector3.x==v3.x&& cubeList[i].baseTransfrom.vector3.z==v3.z)
{
return cubeList[i];
}
}
return null;
}
//将关闭带你从周围点列表中关闭
private void SurroundPointsFilter(List<Object> surroundPoints, List<Object> closePoints)
{
foreach (var closePoint in closePoints)
{
if (surroundPoints.Contains(closePoint))
{
Debug.Log("将关闭列表的点移除");
surroundPoints.Remove(closePoint);
}
}
}
//计算最小预算值点G值
private float CalcG(Object surround, Object minFPoint)
{
return Vector3.Distance(surround.baseTransfrom.vector3, minFPoint.baseTransfrom.vector3) + minFPoint.mG;
}
//计算该点到终点的F值
private void CalcF(Object now, Object end)
{
//F = G + H
float h = Mathf.Abs(end.baseTransfrom.vector3.x - now.baseTransfrom.vector3.x) + Mathf.Abs(end.baseTransfrom.vector3.z - now.baseTransfrom.vector3.z);
float g = 0;
if (now.mParentPoint == null)
{
g = 0;
}
else
{
g = Vector2.Distance(new Vector2(now.baseTransfrom.vector3.x, now.baseTransfrom.vector3.z), new Vector2(now.mParentPoint.baseTransfrom.vector3.x, now.mParentPoint.baseTransfrom.vector3.z)) + now.mParentPoint.mG;
}
float f = g + h;
now.mF = f;
now.mG = g;
now.mH = h;
}
}
}
Object(自定义基类)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YSFrame
{
[Serializable]
public class Object : MonoBehaviour
{
public static Dictionary<int, GameObject> ODict = new Dictionary<int, GameObject>();
[Header("ID")]
public int ID;
[Header("物品类型")]
public EA.ObjectType type;
[Header("寻路层级性质")]
public EA.LayerType layer;
[Header("依附父级方块ID")]
public int parentCubeID;//0代表没有
[Header("信息")]
public string message;
[Header("Transfrom")]
public BaseTransfrom baseTransfrom;
//父“格子”
public Object mParentPoint { get; set; }
//格子显示对象
public GameObject mGameObject { get; set; }
public float mF { get; set; }
public float mG { get; set; }
public float mH { get; set; }
private void ShowMessage()
{
}
private void OnMouseEnter()
{
}
private void OnMouseExit()
{
}
//测试,这里你可以根据自己需求测试
private void OnMouseDown()
{
if (this.type==EA.ObjectType.Cube)
{
Person person = PersonManager.Instance.GetPersonByNumber(0);
person.FindPath(this.baseTransfrom.vector3, Done, Erro);
}
}
private void Done()
{
Debug.Log("完成!");
}
private void Erro()
{
Debug.Log("此路不通!");
}
}
[System.Serializable]
public class JsonObject
{
public static Dictionary<int, GameObject> ODict = new Dictionary<int, GameObject>();
public int ID;
public EA.ObjectType type;
public EA.LayerType layer;
public int parentCubeID;//0代表没有
public string message;
public BaseTransfrom baseTransfrom;
public JsonObject(Object _object)
{
this.ID = _object.ID;
this.type = _object.type;
this.layer = _object.layer;
this.parentCubeID = _object.parentCubeID;
this.message = _object.message;
this.baseTransfrom = _object.baseTransfrom;
}
public static GameObject GetGameObjectByID(int ID)
{
GameObject go = null;
ODict.TryGetValue(ID, out go);
return go;
}
}
}
测试类Person,请忽略其他无关代码
using DG.Tweening;
using System;
using System.Collections.Generic;
using UnityEngine;
using YsFrame;
using YSFrame;
using Object = YSFrame.Object;
[System.Serializable]
[RequireComponent(typeof(Animation))]
public class Person: MonoBehaviour,IPerson
{
private GameManager gameManger;
Action YsPathOnCompelete;//寻路完成回掉
Action YsPathErro;//此路不通!
[Header("[PersonBaseInfo]")]
[SerializeField]
private EA.PersonState personState;
[SerializeField]
private int _number;
[SerializeField]
private string _name;
[SerializeField]
private int _age;
[SerializeField]
private long _money;
[SerializeField]
private long _asset;
[SerializeField]
private EA.Sex _sex;
[SerializeField]
private EA.Status _status;
[SerializeField]
private EA.Bourgeoisie _bourgeoisie;
[SerializeField]
private Animator _animator;
[SerializeField]
private EA.AnimationState _animationState;
[SerializeField]
private Customizer _customizer;
//存储路径点
public List<Object> mPathPosList;
public YSFrame.Object mStartPos;
public YSFrame.Object mEndPos;
public int Number
{
get
{
return _number;
}
set
{
_number = value;
}
}
public string Name {
get {
return _name;
}
set {
_name = value;
}
}
public int Age
{
get {
return _age;
}
set {
_age = value;
}
}
public EA.Sex Sex
{
get
{
return _sex;
}
set
{
_sex = value;
}
}
public EA.Bourgeoisie Bourgeoisie
{
get
{
return _bourgeoisie;
}
set
{
_bourgeoisie = value;
}
}
public EA.Status Status
{
get
{
return _status;
}
set
{
_status = value;
}
}
public Animator Animator
{
get
{
return _animator;
}
set
{
_animator = value;
}
}
public long Money
{
get
{
return _money;
}
set
{
_money = value;
}
}
public long Asset {
get
{
return _asset;
}
set
{
_asset = value;
}
}
public EA.AnimationState AnimationState
{
get
{
return _animationState;
}
set
{
_animationState = value;
}
}
public Customizer Customizer
{
get { return _customizer; }
set { _customizer = value; }
}
public EA.PersonState PersonState
{
get
{
return this.personState;
}
set { personState = value; }
}
private int index;//路径下标
/// <summary>
/// 转换职业身份
/// </summary>
/// <param name="status"></param>
public void ChangeStatus(EA.Status status)
{
if (status == this.Status) return;
Type sT = Status.GetAttribute();
Destroy(this.GetComponent(sT));
this.Status = status;
Type eT = Status.GetAttribute();
this.gameObject.AddComponent(eT);
}
public void Die()
{
}
/// <summary>
/// A*寻路
/// </summary>
/// <param name="target"></param>
public void FindPath(Vector3 target,Action OnCompelete, Action ysPathErro)
{
if (PersonState == EA.PersonState.Walk)
{
transform.DOPause();
}
this.YsPathOnCompelete += OnCompelete;
this.YsPathErro += ysPathErro;
if (mPathPosList != null)
{
mPathPosList.Clear();
}
YsPath.GetInsatnce.ClearGrid();
//网格点对象重新刷新了 需要使用网格来索引到点 mPathPosList存储的点是之前的AStarPoint
this.mEndPos = YsPath.GetObjectByPoints(target);
if (this.mStartPos==null)
{
this.mStartPos = YsPath.GetObjectByPoints(transform.localPosition);
}
mPathPosList = YsPath.GetInsatnce.FindPath(mStartPos, mEndPos);
if (mPathPosList == null) return;
if (mPathPosList.Count == 1 && mPathPosList[0] == mEndPos)
{
YsPathErro();
return;
}
index = mPathPosList.Count - 1;
Walk();
}
/// <summary>
/// 播动画
/// </summary>
/// <param name="animationState"></param>
public void PlayAnimation(EA.AnimationState animationState)
{
if (animationState == _animationState) return;
string animationController = animationState.GetAttributeAnimatiomName(0);
int animationInterger = Int32.Parse( (animationState.GetAttributeAnimatiomName(1)));
Animator.SetInteger(animationController,animationInterger);
this.AnimationState = animationState;
if (animationState == EA.AnimationState.Run) {
// Run();
} else if (animationState == EA.AnimationState.Walk) {
//Walk();
}else if (animationState == EA.AnimationState.Idle)
{
// Idle();
}
}
public void Run()
{
}
public void Talk(string message)
{
}
public void Walk()
{
if (index < 0)
{
PersonState = EA.PersonState.Idle;
YsPathOnCompelete();
}
if (mPathPosList != null && mPathPosList.Count >= 1)
{
PersonState = EA.PersonState.Walk;
this.transform.DOLookAt(mPathPosList[index].baseTransfrom.vector3, 0.5f,AxisConstraint.Y);
this.transform.DOLocalMove(mPathPosList[index].baseTransfrom.vector3+new Vector3(0,2.6f,0), 1f).SetEase(Ease.Flash).OnComplete(() =>
{
mPathPosList.Remove(mPathPosList[index]);
if (mPathPosList.Count!=0)
{
mStartPos = mPathPosList[mPathPosList.Count - 1];
}
index--;
Walk();
});
}
}
public void Idle()
{
this.transform.DOPause();
}
void FixedUpdate()
{
if (gameManger.gameState==EA.GameState.InGame)
{
switch (PersonState)
{
case EA.PersonState.Walk:
// if(AnimationState==EA.AnimationState.Walk)return;
//PlayAnimation(EA.AnimationState.Walk);
break;
case EA.PersonState.Run:
break;
case EA.PersonState.Idle:
//if (AnimationState == EA.AnimationState.Idle) return;
//PlayAnimation(EA.AnimationState.Idle);
break;
}
}
}
void Awake()
{
this.Animator = this.GetComponent<Animator>();
this._customizer = GetComponent<Customizer>();
this.gameManger = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameManager>();
}
}
我并没有采用二维数组构建地图,我使用的是我现有的地图寻路。