A星算法

发布时间 2023-09-12 15:31:15作者: 色色先生
        /// <summary>
        /// 返回移动到目标点的移动路径 A*算法 ,vFindPathCallBack 找到路径给个回调,直到找到路径才调用
        /// </summary>
        /// <returns></returns>
        public List<Vector3> GetMoveTargetPosPath(Vector3 vCurPos, Vector3 vTargetPos,Action<List<Vector3>> vFindPathCallBack = null)
        {
            InitScenePoint(mSceneChangeDataManager.SceneID);
            mCurParentG = 0;
            mCheckCount = 0;
            mOpenList.Clear();
            var vList = new List<Vector3>();

            // 先重置状态
            foreach (var vItem in mScenePointDataArr)
            {
                vItem?.ResetData();
            }

            // 转换当前的坐标
            var vCurX = GameTools.GetValueByConfigValue(vCurPos.x);
            var vCurZ = GameTools.GetValueByConfigValue(vCurPos.z);

            // 拿到位置
            var vStartIndexX = (vCurX - mMinX) / mDiameter;
            var vStartIndexZ = (vCurZ - mMinZ) / mDiameter;

            if (vStartIndexX < 0 || vStartIndexX >= mMapInfoLenX || vStartIndexZ < 0 || vStartIndexZ >= mMapInfoLenZ)
            {
                Log.Error($"寻路测试:起始点{vCurPos.ToString()}超出边界");
                return null;
            }

            var vStartScenePointData = mScenePointDataArr[vStartIndexX, vStartIndexZ];
            var vCurMapInfo = vStartScenePointData;
            if (vCurMapInfo == null)
            {
                Log.Error($"寻路测试:起始点{vCurPos.ToString()}不可行走");
                return null;
            }

            // 标记当前的格子关闭
            vCurMapInfo.SetPointType(PointType.Close);

            // 先把起点周边的坐标都放入OpenList
            AddScenePointDataToOpenList(vCurMapInfo.Index, mCurParentG);

            var vTargetX = GameTools.GetValueByConfigValue(vTargetPos.x);
            var vTargetZ = GameTools.GetValueByConfigValue(vTargetPos.z);

            mTargetIndexX = (vTargetX - mMinX) / mDiameter;
            mTargetIndexZ = (vTargetZ - mMinZ) / mDiameter;

            if (mTargetIndexX < 0 || mTargetIndexX >= mMapInfoLenX || mTargetIndexZ < 0 ||
                mTargetIndexZ >= mMapInfoLenZ)
            {
                Log.Info($"寻路测试:终点{vTargetPos.ToString()}超出边界");
                return null;
            }

            var vEndScenePointData = mScenePointDataArr[mTargetIndexX, mTargetIndexZ];
            if (vEndScenePointData == null)
            {
                Log.Info($"寻路测试:终点{vTargetPos.ToString()}不可行走");
                return null;
            }

            mGoToNext = true;
            mTargetCanGo = false;
            while (mGoToNext)
            {
                var vIsTarget = GetMinIndexByOpenList(out var vCurScenePointData);
                if (vIsTarget)
                {
                    // 如果是找到终点了,则直接跳出去
                    mGoToNext = false;
                    mTargetCanGo = true;
                    vList.Add(GameTools.GetConfigPosition(vCurScenePointData.Pos.x, 0, vCurScenePointData.Pos.y));
                    Log.Info("寻路测试:终于找到目的地了");
                    break;
                }

                // 下一个点,都不可走。直接跳出
                if (vCurScenePointData == null)
                {
                    mGoToNext = false;
                    mTargetCanGo = false;
                    Log.Info("寻路测试:找到死胡同了");
                    return null;
                }

                mCurParentG = vCurScenePointData.G;
                mOpenList.Remove(vCurScenePointData);

                vList.Add(GameTools.GetConfigPosition(vCurScenePointData.Pos.x, 0, vCurScenePointData.Pos.y));

                AddScenePointDataToOpenList(vCurScenePointData.Index, mCurParentG);

                // TODO:保底,防止出不去
                mCheckCount++;
                if (mCheckCount <= mCheckCountMax) continue;
                mGoToNext = false;
                mTargetCanGo = false;
                break;
            }

            return GetMovePath(vStartScenePointData, vEndScenePointData,vFindPathCallBack);
        }