public bool HasOverlappedTargetWithWeapon(Vector2 targetPos, WeaponPart part) { LookaheadNode curSearchNode = this; bool crossedTarget = false; while (curSearchNode != null && curSearchNode.ParentNode != null) { Vector2 originFireVec = part.OwningTank.Hull.Schematic.OrigWeaponDirs[part.EquipIdx]; float range = part.Schematic.Range; Vector2 curFireVec = originFireVec.Rotate(curSearchNode.TankInfo.Rot); Vector2 parentFireVec = originFireVec.Rotate(curSearchNode.ParentNode.TankInfo.Rot); Vector2 curToTargetVec = targetPos - curSearchNode.TankInfo.Pos; Vector2 parentToTargetVec = targetPos - curSearchNode.ParentNode.TankInfo.Pos; float curAngleDiff = Vector2.SignedAngle(curFireVec, curToTargetVec); float parentAngleDiff = Vector2.SignedAngle(parentFireVec, parentToTargetVec); bool curFacing = Mathf.Abs(curAngleDiff) < 90f; if (curFacing && Mathf.Sign(curAngleDiff) != Mathf.Sign(parentAngleDiff) && curToTargetVec.magnitude < range && parentToTargetVec.magnitude < range) { crossedTarget = true; break; } curSearchNode = curSearchNode.ParentNode; } return(crossedTarget); }
public void PopulateTree(Tank tank, Map map, float searchTime, float timeStep, List <TreeSearchMoveInfo> possibleMoves) { root = new LookaheadNode(null, new Vector2(), false, tank.StateInfo, 0, new List <Node>()); float elapsedTime = 0; List <LookaheadNode> nodesToPopulate = new List <LookaheadNode>(); nodesToPopulate.Add(root); while (elapsedTime <= searchTime) { elapsedTime += timeStep; List <LookaheadNode> populatedChildren = new List <LookaheadNode>(); foreach (LookaheadNode node in nodesToPopulate) { node.PopulateChildren(map, timeStep, possibleMoves); foreach (LookaheadNode childNode in node.ChildNodes) { populatedChildren.Add(childNode); } } nodesToPopulate = populatedChildren; } }
public LookaheadNode(LookaheadNode parentNode, Vector2 incomingDir, bool incomingWasJet, TankStateInfo stateInfo, float elapsedTimeFromParent, List <Node> passedNodes) { ParentNode = parentNode; IncomingDir = incomingDir; IncomingWasJet = incomingWasJet; TankInfo = stateInfo; ElapsedTimeFromParent = elapsedTimeFromParent; PassedNodes = passedNodes; ChildNodes = new List <LookaheadNode>(); }
public LookaheadNode GetNodeOneStepAfterRoot() { LookaheadNode curNode = this; while (curNode.ParentNode.ParentNode != null) { curNode = curNode.ParentNode; } return(curNode); }
public override AIAction[] CalcActionsToPerform() { Tank selfTank = controller.SelfTank; Tank targetTank = controller.TargetTank; Map map = controller.Map; List <TreeSearchMoveInfo> possibleMoves = new List <TreeSearchMoveInfo>(); possibleMoves.Add(new TreeSearchMoveInfo(new Vector2(0, 1), true)); possibleMoves.Add(new TreeSearchMoveInfo(new Vector2(0, -1), true)); possibleMoves.Add(new TreeSearchMoveInfo(new Vector2(0, 1).Rotate(90f), true)); possibleMoves.Add(new TreeSearchMoveInfo(new Vector2(0, 1).Rotate(-90f), true)); LookaheadTree tree = new LookaheadTree(); tree.PopulateTree(selfTank, map, LookaheadTime, LookaheadTimeStep, possibleMoves); List <LookaheadNode> possibleNodes = tree.FindAllNodesAtSearchTime(LookaheadTime); possibleNodes = AIUtility.FilterByPathNotObstructed(possibleNodes); possibleNodes = AIUtility.FilterByDestNotObstructed(possibleNodes, map); possibleNodes = AIUtility.FilterByPassingBullet(possibleNodes, map); possibleNodes = AIUtility.FilterByAwayFromWall(possibleNodes, selfTank.StateInfo); LookaheadNode bestNode = null; float bestCost = 0; foreach (LookaheadNode node in possibleNodes) { WeaponPart notUsed; int targetTime = AIUtility.CalcMinTimeForAimerToHitAimee(targetTank.StateInfo, node.TankInfo, targetTank.Hull.GetAllWeapons(), out notUsed); int selfTime = AIUtility.CalcMinTimeForAimerToHitAimee(node.TankInfo, targetTank.StateInfo, selfTank.Hull.GetAllWeapons(), out notUsed); float cost = targetTime - selfTime; if (bestNode == null || bestCost < cost) { bestNode = node; bestCost = cost; } } timeSinceLastJet = Time.time; List <AIAction> actions = new List <AIAction>(); actions.Add(new JetInDirAction(bestNode.IncomingDir, controller)); return(actions.ToArray()); }
public override AIAction[] CalcActionsToPerform() { List <AIAction> actions = new List <AIAction>(); Map map = controller.Map; elapsedTimeSinceLastUpdate += Time.deltaTime; if (elapsedTimeSinceLastUpdate >= UpdatePeriod) { LookaheadNode requestNode = pickDirToPursue(); forwardVecWhenUpdate = controller.SelfTank.GetForwardVec(); prevMoveDir = requestNode.IncomingDir; prevMoveIsJet = requestNode.IncomingWasJet; elapsedTimeSinceLastUpdate = 0; } if (prevMoveIsJet) { if (elapsedTimeSinceLastUpdate == 0) { actions.Add(new JetInDirAction(prevMoveDir, controller)); CombatDebugHandler.Instance.RegisterObject("maneuver_move_dir", prevMoveDir); } } else { float angleDiffSinceUpdate = Vector2.SignedAngle(forwardVecWhenUpdate, controller.SelfTank.GetForwardVec()); actions.Add(new GoInDirAction(prevMoveDir.Rotate(angleDiffSinceUpdate), controller)); CombatDebugHandler.Instance.RegisterObject("maneuver_move_dir", prevMoveDir.Rotate(angleDiffSinceUpdate)); } return(actions.ToArray()); }
void OnDrawGizmos() { if (Application.isPlaying && Application.isEditor) { Color origColor = Gizmos.color; if (basicTankInfoDebugOn) { Tank aiTank = CombatHandler.Instance.AITankController.SelfTank; WeaponPart part = aiTank.Hull.GetAllWeapons()[0]; Gizmos.color = Color.red; Gizmos.DrawLine( part.CalculateFirePos(), part.CalculateFirePos() + part.CalculateFireVec() * 50f); Gizmos.color = Color.green; Gizmos.DrawLine( aiTank.transform.position, (Vector2)aiTank.transform.position + aiTank.GetForwardVec() * 50f); Gizmos.color = Color.blue; Gizmos.DrawLine( aiTank.transform.position, (Vector2)aiTank.transform.position + aiTank.GetBackwardVec() * 50f); } if (moveTestDebugOn) { Gizmos.color = Color.green; Gizmos.DrawWireSphere(targetPosForMoveTest, 20); } if (actuationDebugOn) { Tank aiTank = CombatHandler.Instance.AITankController.SelfTank; object obj = getRegisterdObj("actuation_arc_vectors"); if (obj != null) { List <Vector2> arcVectors = (List <Vector2>)obj; Gizmos.color = Color.green; Gizmos.DrawLine(aiTank.transform.position, aiTank.transform.position + (Vector3)arcVectors[0] * 50f); Gizmos.DrawLine(aiTank.transform.position, aiTank.transform.position + (Vector3)arcVectors[1] * 50f); Gizmos.color = Color.blue; Gizmos.DrawLine(aiTank.transform.position, aiTank.transform.position + (Vector3)arcVectors[2] * 50f); Gizmos.DrawLine(aiTank.transform.position, aiTank.transform.position + (Vector3)arcVectors[3] * 50f); } Vector2 size = aiTank.Hull.Schematic.Size; Vector2 forwardVec = aiTank.GetForwardVec(); Vector2 leftVec = forwardVec.Rotate(90); Vector2 rightVec = forwardVec.Rotate(-90); Vector3 leftWheelPos = (Vector2)aiTank.transform.position + leftVec * size.x / 2f; Vector3 rightWheelPos = (Vector2)aiTank.transform.position + rightVec * size.x / 2f; Gizmos.color = Color.magenta; Gizmos.DrawLine(leftWheelPos, leftWheelPos + ((Vector3)forwardVec * 100 * aiTank.Hull.LeftCurPower)); Gizmos.DrawLine(rightWheelPos, rightWheelPos + ((Vector3)forwardVec * 100 * aiTank.Hull.RightCurPower)); } Goal curGoal = (Goal)getRegisterdObj("goal"); if (mapDisplayDebugOn) { // Draw Map Map map = CombatHandler.Instance.AITankController.Map; for (int x = 0; x < map.Cols; ++x) { for (int y = 0; y < map.Rows; ++y) { bool blocked = !map.GetNodeAtIdx(x, y).NodeTraversable(); Vector2 pos = map.IdxToPosition(x, y); Gizmos.color = !blocked ? Color.green : Color.red; Gizmos.DrawWireCube(pos, new Vector3(map.TileDim, map.TileDim, map.TileDim)); } } } if (maneuverGoalDebugOn && curGoal != null && curGoal.GetType() == typeof(ManeuverGoal)) { if (maneuverCurMoveDir) { object obj = getRegisterdObj("maneuver_move_dir"); if (obj != null) { Vector2 vec = (Vector2)obj; Tank aiTank = CombatHandler.Instance.AITankController.SelfTank; Gizmos.color = Color.green; Gizmos.DrawLine(aiTank.transform.position, (Vector2)aiTank.transform.position + vec.normalized * 50f); } } if (maneuverNodesAtSearchTime) { object obj = getRegisterdObj("maneuver_nodes_at_searchtime"); if (obj != null) { List <LookaheadNode> nodeList = (List <LookaheadNode>)obj; Gizmos.color = Color.green; foreach (LookaheadNode node in nodeList) { Gizmos.DrawWireSphere(node.TankInfo.Pos, 20); } } } if (maneuverPathNotObstructedFilter) { object obj = getRegisterdObj("maneuver_path_unobstructed_filter"); if (obj != null) { List <LookaheadNode> nodeList = (List <LookaheadNode>)obj; Gizmos.color = Color.green; foreach (LookaheadNode node in nodeList) { Gizmos.DrawWireSphere(node.TankInfo.Pos, 20); } } } if (maneuverDestNotObstructedFilter) { object obj = getRegisterdObj("maneuver_dest_not_obstructed_filter"); if (obj != null) { List <LookaheadNode> nodeList = (List <LookaheadNode>)obj; Gizmos.color = Color.green; foreach (LookaheadNode node in nodeList) { Gizmos.DrawWireSphere(node.TankInfo.Pos, 20); } } } if (maneuverBulletFilter) { object obj = getRegisterdObj("maneuver_bullet_filter"); if (obj != null) { List <LookaheadNode> nodeList = (List <LookaheadNode>)obj; Gizmos.color = Color.green; foreach (LookaheadNode node in nodeList) { Gizmos.DrawWireSphere(node.TankInfo.Pos, 20); } } } if (maneuverAwayFromWallFilter) { object obj = getRegisterdObj("maneuver_away_from_wall_filter"); if (obj != null) { List <LookaheadNode> nodeList = (List <LookaheadNode>)obj; Gizmos.color = Color.green; foreach (LookaheadNode node in nodeList) { Gizmos.DrawWireSphere(node.TankInfo.Pos, 20); } } } if (maneuverRunawayNodes) { object obj = getRegisterdObj("maneuver_runaway_cost_infos"); if (obj != null) { List <ManeuverGoal.CostInfo> infos = (List <ManeuverGoal.CostInfo>)obj; float maxCost = infos.Max(c => c.Cost); foreach (ManeuverGoal.CostInfo info in infos) { Gizmos.color = new Color(info.Cost / maxCost, 0, 1f - info.Cost / maxCost); Gizmos.DrawWireSphere(info.Node.TankInfo.Pos, 20); } } } if (maneuverGoingforItNode) { object obj = getRegisterdObj("maneuver_going_cost_infos"); if (obj != null) { List <ManeuverGoal.CostInfo> infos = (List <ManeuverGoal.CostInfo>)obj; float maxCost = infos.Max(c => c.Cost); foreach (ManeuverGoal.CostInfo info in infos) { Gizmos.color = new Color(info.Cost / maxCost, 0, 1f - info.Cost / maxCost); Gizmos.DrawWireSphere(info.Node.TankInfo.Pos, 20); } } } if (maneuverBestNode) { object obj = getRegisterdObj("maneuver_best_node"); if (obj != null) { LookaheadNode node = (LookaheadNode)obj; Gizmos.color = Color.green; Gizmos.DrawWireSphere(node.TankInfo.Pos, 20); } } } if (predictFutureDebugOn) { object obj = getRegisterdObj("test_future_pos_lis"); if (obj != null) { List <Vector2> posList = (List <Vector2>)obj; Gizmos.color = Color.green; foreach (Vector2 pos in posList) { Gizmos.DrawWireSphere(pos, 20); } } } if (displayAITankRange) { Tank tank = CombatHandler.Instance.AITankController.SelfTank; WeaponPart maxRangeWeapon = null; foreach (WeaponPart part in tank.Hull.GetAllWeapons()) { if (maxRangeWeapon == null || maxRangeWeapon.Schematic.Range < part.Schematic.Range) { maxRangeWeapon = part; } } Gizmos.color = Color.green; Gizmos.DrawWireSphere(tank.transform.position, maxRangeWeapon.Schematic.Range); } Gizmos.color = origColor; } }
public CostInfo(LookaheadNode node, int cost) { Node = node; Cost = cost; }
private LookaheadNode goingForItBehaviour(List <LookaheadNode> possibleNodes) { Tank selfTank = controller.SelfTank; Tank targetTank = controller.TargetTank; List <CostInfo> nodeCosts = new List <CostInfo>(); bool overlapNodeExists = false; Vector2 diffVec = targetTank.transform.position - selfTank.transform.position; List <bool> overlaps = new List <bool>(); foreach (LookaheadNode node in possibleNodes) { bool nodeOverlaps = false; foreach (WeaponPart part in selfTank.Hull.GetAllWeapons()) { if (node.HasOverlappedTargetWithWeapon(targetTank.transform.position, part)) { overlapNodeExists = true; nodeOverlaps = true; break; } } overlaps.Add(nodeOverlaps); } Debug.Assert(possibleNodes.Count == overlaps.Count, "Possible nodes and overlap count don't match. Should never happen"); for (int i = 0; i < possibleNodes.Count; ++i) { LookaheadNode node = possibleNodes[i]; WeaponPart notUsed; int targetTime = AIUtility.CalcMinTimeForAimerToHitAimee(targetTank.StateInfo, node.TankInfo, targetTank.Hull.GetAllWeapons(), out notUsed); int selfTime = AIUtility.CalcMinTimeForAimerToHitAimee(node.TankInfo, targetTank.StateInfo, selfTank.Hull.GetAllWeapons(), out notUsed); int cost = targetTime - selfTime; bool overlapCondition = true; if (overlapNodeExists) { overlapCondition = overlaps[i]; } if (overlapCondition) { nodeCosts.Add(new CostInfo(node, cost)); } } CombatDebugHandler.Instance.RegisterObject("maneuver_going_cost_infos", nodeCosts); CostInfo bestInfo = null; foreach (CostInfo info in nodeCosts) { if (bestInfo == null || info.Cost > bestInfo.Cost) { bestInfo = info; } } bestInfo = handleSameCostCostInfos(bestInfo, nodeCosts); CombatDebugHandler.Instance.RegisterObject("maneuver_best_node", bestInfo.Node); return(bestInfo.Node.GetNodeOneStepAfterRoot()); }