Пример #1
0
    /// <summary>
    /// 计算两节点间的权重信息
    /// </summary>
    /// <param name="v1"></param>
    /// <param name="v2"></param>
    /// <param name="inContext">上下文信息</param>
    /// <returns></returns>
    private float CalcWeight(DijkstraVertex v1, DijkstraVertex v2, AStarUserContext inContext)
    {
        //  REMARK:该方法计算的权重值应该和A星里的NeighborDistance的值相同。

        //  距离权重
        int   diffX = Math.Abs(v1.X - v2.X);
        int   diffY = Math.Abs(v1.Y - v2.Y);
        float dis   = 0.0f;

        switch (diffX + diffY)
        {
        case 1: dis = 1; break;

        case 2: dis = SQRT_2; break;

        case 0: dis = 0; break;

        default:
            Assert.Should(false);
            break;
        }

        //  计算目标节点v2自身的附加权重
        if (v2.AuxWeight < 0)
        {
            v2.AuxWeight = inContext.map.CalcAuxWeight(v2.X, v2.Y, inContext);
        }

        //  返回总权重值(TODO:附加权重是考虑的时间,时间和距离仅有1:1的情况下才可以相加,否则不是太准确。※ 距离1需要1s则ok,否则需要把距离转换为时间。t=s/v)
        return(dis + v2.AuxWeight);
    }
Пример #2
0
    private bool IsWalkable(int X, int Y, AStarUserContext inContext)
    {
        ///<    可飞行
        if (inContext.entity.CanFlying())
        {
            return(true);
        }

        ///<    动态评估格式是否可通行
        return(inContext.map.IsPassable(X, Y, true));
    }
Пример #3
0
 /// <summary>
 /// 计算目标点的附加权重值(给A星以及Dijkstra用)
 /// </summary>
 /// <param name="x"></param>
 /// <param name="y"></param>
 ///// <param name="inContext"></param>
 /// <returns></returns>
 public float CalcAuxWeight(int x, int y, AStarUserContext inContext)
 {
     Assert.Should(inContext != null && inContext.entity != null);
     //  墙 && 不可穿越
     if (IsWallorLinker(x, y) && !inContext.entity.CanOverTheWall())
     {
         return(10.0f);
         ////  不同兵种拆墙时间估算(REMARK:这里简单处理不考虑墙的HP等情况了)
         //if (EntityTypeUtil.IsBombMan(inContext.entity.model))
         //{
         //    return inContext.entity.model.rate + 1.0f;
         //}
         //else
         //{
         //    return 10.0f;
         //}
     }
     //  其他情况不附加权重
     return(0.0f);
 }
Пример #4
0
    /// <summary>
    /// 邻近节点迭代器
    /// </summary>
    /// <param name="v1">当前节点</param>
    /// <param name="inContext"></param>
    /// <returns></returns>
    private IEnumerable NeighborNodes(DijkstraVertex v1, AStarUserContext inContext)
    {
        //  获取所有邻近节点
        int x = v1.X;
        int y = v1.Y;

        if ((x > 0) && (y > 0))
        {
            m_NeighborNodes[0] = m_SearchSpace[x - 1, y - 1];
        }
        else
        {
            m_NeighborNodes[0] = null;
        }

        if (y > 0)
        {
            m_NeighborNodes[1] = m_SearchSpace[x, y - 1];
        }
        else
        {
            m_NeighborNodes[1] = null;
        }

        if ((x < Constants.EDGE_WIDTH - 1) && (y > 0))
        {
            m_NeighborNodes[2] = m_SearchSpace[x + 1, y - 1];
        }
        else
        {
            m_NeighborNodes[2] = null;
        }

        if (x > 0)
        {
            m_NeighborNodes[3] = m_SearchSpace[x - 1, y];
        }
        else
        {
            m_NeighborNodes[3] = null;
        }

        if (x < Constants.EDGE_WIDTH - 1)
        {
            m_NeighborNodes[4] = m_SearchSpace[x + 1, y];
        }
        else
        {
            m_NeighborNodes[4] = null;
        }

        if ((x > 0) && (y < Constants.EDGE_HEIGHT - 1))
        {
            m_NeighborNodes[5] = m_SearchSpace[x - 1, y + 1];
        }
        else
        {
            m_NeighborNodes[5] = null;
        }

        if (y < Constants.EDGE_HEIGHT - 1)
        {
            m_NeighborNodes[6] = m_SearchSpace[x, y + 1];
        }
        else
        {
            m_NeighborNodes[6] = null;
        }

        if ((x < Constants.EDGE_WIDTH - 1) && (y < Constants.EDGE_HEIGHT - 1))
        {
            m_NeighborNodes[7] = m_SearchSpace[x + 1, y + 1];
        }
        else
        {
            m_NeighborNodes[7] = null;
        }

        //  返回所有节点
        for (int i = 0; i < m_NeighborNodes.Length; i++)
        {
            DijkstraVertex v2 = m_NeighborNodes[i];
            if (v2 == null || v2.Visited)
            {
                continue;
            }

            //  略过监视范围外节点
            if (inContext.entity.monitorRange > 0.0f)
            {
                float dx = m_StartVertex.X - v2.X;
                float dy = m_StartVertex.Y - v2.Y;
                if (dx * dx + dy * dy > inContext.entity.monitorRange * inContext.entity.monitorRange)
                {
                    continue;
                }
            }

            //  略过不可通行的节点
            if (!IsWalkable(v2.X, v2.Y, inContext))
            {
                continue;
            }

            yield return(v2);
        }
    }
Пример #5
0
    IEnumerable <bool>
#endif
    SearchCore(int startX, int startY, AStarUserContext inContext)
    {
        Assert.Should(startX >= 0 && startX < Constants.EDGE_WIDTH);
        Assert.Should(startY >= 0 && startY < Constants.EDGE_HEIGHT);
        Assert.Should(inContext != null && inContext.map != null && inContext.entity != null);

        //  初始化
        for (int x = 0; x < Constants.EDGE_WIDTH; x++)
        {
            for (int y = 0; y < Constants.EDGE_HEIGHT; y++)
            {
                m_SearchSpace[x, y].Reset();
            }
        }

#if !REALTIME_AI
        yield return(false);
#endif

        //  初始化未访问列表(把起始节点添加到该列表)
        m_StartVertex        = m_SearchSpace[startX, startY];
        m_StartVertex.Weight = 0.0f;
        m_StartVertex.Parent = null;

        m_NotVisitedList.Clear();
        m_NotVisitedList.Push(m_StartVertex);

        DijkstraVertex v1 = null;

        //  循环处理
        int iVisitedCount = 0;
        while (m_NotVisitedList.Count > 0)
        {
            //  从未访问列表中获取最近的节点作为当前节点(并添加访问过标记)
            v1         = m_NotVisitedList.Pop();
            v1.Visited = true;

            //  遍历当前节点v1的所有邻近节点
            foreach (DijkstraVertex v2 in NeighborNodes(v1, inContext))
            {
                //  尚未添加到 未访问 列表则添加
                if (!v2.InNotVisitedList)
                {
                    v2.InNotVisitedList = true;
                    m_NotVisitedList.Push(v2);
                }
                //  计算路径权重(startToV1 + V1ToV2)
                float startToV2 = v1.Weight + CalcWeight(v1, v2, inContext);
                //  更优的情况则更新节点信息 和 优先队列信息
                if (startToV2 < v2.Weight)
                {
                    v2.Weight = startToV2;
                    v2.Parent = v1;
                    m_NotVisitedList.Update(v2);
                }
            }

            //  迭代
            if (++iVisitedCount >= 1000)
            {
                iVisitedCount = 0;
#if !REALTIME_AI
                //yield return false;
#endif
            }
        }

        ////  检测(是否全部节点都访问过了)
        //Debug.Log("Start Check...");
        //bool pass = true;
        //for (int x = 0; x < Constants.EDGE_WIDTH; x++)
        //{
        //    for (int y = 0; y < Constants.EDGE_HEIGHT; y++)
        //    {
        //        if (!m_SearchSpace[x, y].Visited)
        //        {
        //            //int diffX = Math.Abs(m_StartVertex.X - m_SearchSpace[x, y].X);
        //            //int diffY = Math.Abs(m_StartVertex.Y - m_SearchSpace[x, y].Y);
        //            //if (diffX + diffY >= 15)
        //            //    continue;

        //            Debug.Log("not Visited");
        //            pass = false;
        //        }
        //    }
        //}
        //Assert.Should(pass, "check failed...");

#if !REALTIME_AI
        yield return(true);
#endif
    }
Пример #6
0
    public LinkedList <IMoveGrid> SearchNearestWall(int startX, int startY, Dictionary <TilePoint, IsoGridTarget> gridTargets, AStarUserContext inContext)
    {
        //  执行搜索
#if REALTIME_AI
        SearchCore(startX, startY, inContext);
#else
        foreach (var _break in SearchCore(startX, startY, inContext))
        {
            if (_break)
            {
                break;
            }
            yield return(null);
        }
#endif

        //  筛选所有权重最低并且有墙的路径的目标
        float          miniWeight = float.MaxValue;
        DijkstraVertex vertex     = null;
        foreach (var item in gridTargets)
        {
            var v = m_SearchSpace[item.Key.x, item.Key.y];
            if (v.Visited && v.Weight < miniWeight && HasWall(v))
            {
                miniWeight = v.Weight;
                vertex     = v;
            }
        }
        if (vertex == null)
        {
            return(null);
        }

        //  生成临时路线(从起点到目标点) REMARK:这条路线上肯定有墙
        LinkedList <DijkstraVertex> route = new LinkedList <DijkstraVertex>();
        for (var v = vertex; v != null; v = v.Parent)
        {
            route.AddFirst(v);
        }

        //  生成最终路线(从起点到第一处墙的格子)
        LinkedList <IMoveGrid> finalRoute = new LinkedList <IMoveGrid>();
        foreach (var v in route)
        {
            finalRoute.AddLast(v);
            if (v.AuxWeight > 0)
            {
                break;
            }
        }
        return(finalRoute);
    }
Пример #7
0
    public RetvGridTargetInfo Search(int startX, int startY, Dictionary <TilePoint, IsoGridTarget> gridTargets, AStarUserContext inContext)
    {
        //  执行搜索
#if REALTIME_AI
        SearchCore(startX, startY, inContext);
#else
        foreach (var _break in SearchCore(startX, startY, inContext))
        {
            if (_break)
            {
                break;
            }
            yield return(null);
        }
#endif

        //  筛选所有权重最低的格子
        float          miniWeight    = float.MaxValue;
        IsoGridTarget  targeterInfos = null;
        DijkstraVertex vertex        = null;
        foreach (var item in gridTargets)
        {
            DijkstraVertex v = m_SearchSpace[item.Key.x, item.Key.y];
            if (v.Visited && v.Weight < miniWeight)
            {
                miniWeight    = v.Weight;
                targeterInfos = item.Value;
                vertex        = v;
            }
        }

        //  未找到直接范围
        if (targeterInfos == null)
        {
            return(null);
        }

        //  生成移动路线(从起点到目标点)
        LinkedList <IMoveGrid> route = new LinkedList <IMoveGrid>();
        for (var v = vertex; v != null; v = v.Parent)
        {
            route.AddFirst(v);
        }
        targeterInfos.MoveRoute = route;

#if REALTIME_AI
        return(targeterInfos);
#else
        yield return(targeterInfos);
#endif
    }