/// <summary> /// 从目标列表里根据距离时间等权重筛选最有目标 /// </summary> /// <param name="targeters"></param> /// <param name="_targetPos"></param> /// <param name="_targetRoute"></param> /// <returns></returns> private List <TileEntity> SelectTargeters(List <TileEntity> targeters, out TilePoint?_targetPos, out LinkedList <IMoveGrid> _targetRoute) { _targetPos = null; _targetRoute = null; // 先在监视范围内寻找时间消耗最低的目标 IsoGridTarget targetInfos = FindTargetsNearestTimeCost(Attacker, targeters); if (targetInfos != null) { Assert.Should(targetInfos.MoveRoute != null); if (targetInfos.MoveRoute.Count > 1) { _targetRoute = targetInfos.MoveRoute; } return(AuxConvertToList(targetInfos.Targeter)); } // 未找到则直接寻找直线最近的目标 var nearest_targets = FindTargetsNearestLinear(Attacker.GetCurrentPositionCenter(), targeters, 1); var targeter = nearest_targets[0]; Vector2 p = targeter.GetCurrentPositionCenter(); //int randomOffset = Mathf.Min((int)(targeter.blockingRange / 2.0f + Attacker.model.range), targeter.width / 2); // TODO:如果该值过大导致移动结束后目标不在攻击范围内(则会导致重新锁定目标) 则需要酌情调整该值算法 int randomOffset = Mathf.Min((int)Attacker.model.range, targeter.width / 2); int x = (int)p.x; int y = (int)p.y; if (randomOffset > 0) { x = BattleRandom.Range(x - randomOffset, x + randomOffset); y = BattleRandom.Range(y - randomOffset, y + randomOffset); } _targetPos = new TilePoint(x, y); return(nearest_targets); }
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 }
/// <summary> /// 延迟计算回调函数 /// </summary> /// <param name="delayAI"></param> private void OnDelayLockTargetersCompleted(DelayAiObject <IsoGridTarget> delayAI) { m_tempTargetPos = null; m_tempMoveRoute = null; //Entity.State = EntityStateType.Thinking; IsoGridTarget targetInfos = delayAI.result; Assert.Should(targetInfos != null && targetInfos.MoveRoute != null); if (targetInfos.MoveRoute.Count > 1) { m_tempMoveRoute = targetInfos.MoveRoute; } m_tempTargeters = AuxConvertToList(targetInfos.Targeter); // 执行行动 DoAction(); }
/// <summary> /// 从备选目标对象列表筛选最近的目标(时间消耗最低) /// </summary> /// <param name="attacker"></param> /// <param name="targets"></param> /// <returns></returns> protected RetvGridTargetInfo FindTargetsNearestTimeCost(TileEntity attacker, List <TileEntity> targets) { // 备选列表 低于 需求量则不用排序直接全部返回 if (targets.Count == 0) { return(null); } ///< 计算最近目标 Dictionary <TilePoint, IsoGridTarget> gridTargets = new Dictionary <TilePoint, IsoGridTarget>(); if (attacker.model.range < 3.0f) // REMARK:3.0f是建筑和士兵之间跨越墙的最短距离(低于3则直接根据目标点中心求最近即可、否则需要根据建筑周边被攻击范围覆盖的所有区域求最近。) { foreach (var tar in targets) { Vector2 p = tar.GetCurrentPositionCenter(); TilePoint grid = new TilePoint((int)p.x, (int)p.y); IsoGridTarget tarInfos = new IsoGridTarget() { Targeter = tar, Distance = 0, X = grid.x, Y = grid.y }; gridTargets.Add(grid, tarInfos); } } else { foreach (var tar in targets) { Vector2 p = tar.GetCurrentPositionCenter(); int cx = (int)p.x; int cy = (int)p.y; int range = (int)(attacker.model.range + Mathf.Max(0.5f, tar.blockingRange / 2.0f)); int bgnX = Math.Max(cx - range, 0); int endX = Math.Min(cx + range, Constants.EDGE_WIDTH - 1); int bgnY = Math.Max(cy - range, 0); int endY = Math.Min(cy + range, Constants.EDGE_HEIGHT - 1); int range2 = range * range; for (int x = bgnX; x <= endX; x++) { for (int y = bgnY; y <= endY; y++) { int dx = cx - x; int dy = cy - y; int diff = dx * dx + dy * dy; if (diff <= range2 && IsoMap.Instance.IsPassable(x, y)) { TilePoint grid = new TilePoint(x, y); if (gridTargets.ContainsKey(grid)) { IsoGridTarget tarInfos = gridTargets[grid]; if (diff < tarInfos.Distance) { tarInfos.Distance = diff; tarInfos.Targeter = tar; } } else { IsoGridTarget tarInfos = new IsoGridTarget() { Targeter = tar, Distance = diff, X = grid.x, Y = grid.y }; gridTargets.Add(grid, tarInfos); } } } } } } if (gridTargets.Count == 0) { return(null); } #if REALTIME_AI return(IsoMap.Instance.SearchDijkstra(attacker, gridTargets)); #else return(IsoMap.Instance.SearchDijkstra(attacker, gridTargets)); #endif }
protected override List <TileEntity> TryLockTargeters(out TilePoint?_targetPos, out LinkedList <IMoveGrid> _targetRoute) { _targetPos = null; _targetRoute = null; ///< 有目标了直接返回 if (m_tempTargeters != null) { return(m_tempTargeters); } ///< 方案1:计算全地图目标时间最近(并且有墙的路线)REMARK:有墙基本就可以理解为封闭区域 Dictionary <TilePoint, IsoGridTarget> gridTargets = new Dictionary <TilePoint, IsoGridTarget>(); var targets = IsoMap.Instance.GetEntitiesByTT(Attacker.GetTargetOwner(), EntityAiType.Other, Attacker); foreach (var tar in targets) { Vector2 p = tar.GetCurrentPositionCenter(); TilePoint grid = new TilePoint((int)p.x, (int)p.y); IsoGridTarget tarInfos = new IsoGridTarget() { Targeter = tar, Distance = 0, X = grid.x, Y = grid.y }; gridTargets.Add(grid, tarInfos); } LinkedList <IMoveGrid> route = IsoMap.Instance.SearchDijkstraNearestWall(Attacker, gridTargets); if (route != null) { Assert.Should(route.Count >= 2); // 墙的位置 IMoveGrid wallGrid = route.Last.Value; route.RemoveLast(); // 墙的前一格 IMoveGrid lastGrid = route.Last.Value; // 获取墙 TileEntity wallTargeter = IsoMap.Instance.GetWallTargeter(lastGrid.X, lastGrid.Y, wallGrid.X, wallGrid.Y); Assert.Should(wallTargeter != null); // 返回 _targetRoute = route; return(AuxConvertToList(wallTargeter)); } ///< 方案2:求最近的墙o.o TileEntity targeter = GetWallEntityNearest(Attacker); if (targeter == null) { return(null); } // 查找移动目标点(墙四周离自身最近的点) int self_x = Entity.GetTilePos().x; int self_y = Entity.GetTilePos().y; Vector2 c = targeter.GetCurrentPositionCenter(); int wall_x = (int)c.x; int wall_y = (int)c.y; int wall_w = 1; // REMARK:连接器到墙中心的距离 int mindiff = 999999; int goal_x = -1; int goal_y = -1; // 依次为 左上、右上、左下、右下 DetectNearestGrid(ref mindiff, ref goal_x, ref goal_y, self_x, self_y, wall_x, wall_y + wall_w); DetectNearestGrid(ref mindiff, ref goal_x, ref goal_y, self_x, self_y, wall_x + wall_w, wall_y); DetectNearestGrid(ref mindiff, ref goal_x, ref goal_y, self_x, self_y, wall_x - wall_w, wall_y); DetectNearestGrid(ref mindiff, ref goal_x, ref goal_y, self_x, self_y, wall_x, wall_y - wall_w); // 找到目标点 并且 目标点位置不是自身位置 if (goal_x >= 0 && goal_y >= 0 && ((goal_x != self_x || goal_y != self_y))) { _targetPos = new TilePoint(goal_x, goal_y); } return(AuxConvertToList(targeter)); }