public int MoveToBestSpot() { //print("MoveToBestSpot()"); if (CurrentActionPoints <= 0) { return((int)BTNode.EState.Failure); } Checkpoint checkpointTarget = GetClosestCheckpoint(); MBGraphNode checkpointNode = checkpointTarget == null ? null : checkpointTarget.node; if (checkpointNode == null) { return((int)BTNode.EState.Failure); } // get the closest reachable node to the checkpoint/goal GraphNode <GameObject> optimalGraphNode = reachableNodeIds.Count > 0 ? GameplayManager.Instance.gridGraph.graph[reachableNodeIds[0]] : null; float dist = Mathf.Infinity; foreach (string nodeId in reachableNodeIds) { GraphNode <GameObject> graphNode = GameplayManager.Instance.gridGraph.graph[nodeId]; float tempDist = (graphNode.Data.transform.position - checkpointNode.transform.position).magnitude; if (tempDist < dist) { optimalGraphNode = graphNode; dist = tempDist; } } if (optimalGraphNode != null) { List <GraphNode <GameObject> > path = pathFinding.FindPath(PositionNode.nodeId, optimalGraphNode.Id, MovementHeuristic, checkpoints.Count <= 1); if (path.Count > 0) { path.RemoveAt(0); } if (path.Count == 0) { return((int)BTNode.EState.Failure); } Move(path); //print("MoveToBestSpot: " + path.Count); //foreach (GraphNode<GameObject> gnode in path) //{ // print(gnode.Data.transform.localPosition); //} return((int)BTNode.EState.Success); } else { return((int)BTNode.EState.Failure); // <- we cannot move anymore } }
/// <summary> /// Resets the behavior tree properties. This function is called each time before the behavior tree is evaluated. <br /> /// See <see cref="BehaviorTree.Evaluate"/> /// </summary> private void ResetBehaviorTreeProperties() { itemToUseIndex = -1; playerAttackTarget = null; playerAttackThreats.Clear(); reachableNodeIds.Clear(); moveTargetNode = null; nodeToSpillOn = null; }
private void Awake() { Collider[] hitColliders = Physics.OverlapSphere(transform.position, 1.5f); foreach (var hitCollider in hitColliders) { if (hitCollider.tag == "Node") { MBGraphNode positionNode = hitCollider.gameObject.GetComponent <MBGraphNode>(); powerUpScript.PositionNode = positionNode; transform.position = new Vector3(positionNode.transform.position.x, transform.position.y, positionNode.transform.position.z); transform.parent = positionNode.transform; } } }
private void ConnectGridNodes(MBGraph target, MBGraphNode nodeA, MBGraphNode nodeB) { Vector3 direction = nodeB.transform.position - nodeA.transform.position; bool shouldConnect = true; if (target.__detectCollisions) { List <RaycastHit> hits = FilterRaycastHits(target, Physics.SphereCastAll(nodeA.transform.position, 0.25f, direction, direction.magnitude)); shouldConnect = hits.Count == 0; } if (shouldConnect) { target.SetEdge(nodeA, nodeB); } }
public int IsItemInRange() { //print("IsItemInRange()"); var nodesWithItems = new List <MBGraphNode>(); // Check all reachable nodes to see if it contains a PowerUp foreach (var nodeID in reachableNodeIds) { var node = GameplayManager.Instance.gridGraph.graph[nodeID]; // Check if node has an ItemBox on it for (int i = 0; i < node.Data.transform.childCount; ++i) { Transform child = node.Data.transform.GetChild(i); if (child.gameObject.CompareTag("PowerUp")) { nodesWithItems.Add(GameplayManager.Instance.gridGraph.graph[nodeID].Data.GetComponent <MBGraphNode>()); } } } // At least one PowerUp is in Range if (nodesWithItems.Count > 0) { var shortestDistance = int.MaxValue; var closestNode = nodesWithItems[0]; // Find the closest PowerUp foreach (var node in nodesWithItems) { List <GraphNode <GameObject> > path = pathFinding.FindPath(PositionNode.nodeId, node.nodeId, MovementHeuristic, checkpoints.Count <= 1); if (path.Count < shortestDistance) { shortestDistance = path.Count; closestNode = node; } } moveTargetNode = closestNode; return((int)BTNode.EState.Success); } // No Items in Range return((int)BTNode.EState.Failure); }
public int MoveToCover() { //print("MoveToCover()"); // foreach player in the playerAttackThreats list, check if they have ranged/attack items // if they do, then foreach spot that the player can reach choose the one that is safest // and add the CRMove() coroutine to the queue (see below) and return success // else if there is no cover available then return failure List <MBGraphNode> coverNodes = reachableNodeIds.Select(nId => GameplayManager.Instance.gridGraph.graph[nId].Data.GetComponent <MBGraphNode>()).ToList(); foreach (AbstractPlayer player in playerAttackThreats) { int pMissileIndex = player.Inventory.GetItemIndex("Rocket"); if (pMissileIndex != -1) { for (int i = 0; i < coverNodes.Count; ++i) { MBGraphNode node = coverNodes[i]; bool coverAvailable = false; // check for guaranteed shield PU_Base item = node.transform.GetComponentInChildren <PU_Base>(); if (item != null && item.powerUpScript is PU_Shield) { coverAvailable = true; coverNodes.Clear(); coverNodes.Add(node); break; } if (!coverAvailable) { // if we don't hit something, then there is no cover at this node and so, we remove it from the cover list RaycastHit[] hits = Physics.RaycastAll(player.transform.position + (Vector3.up * 0.5f), node.transform.position - player.transform.position); //Debug.DrawRay(player.transform.position, node.transform.position - player.transform.position, Color.red, 10000); foreach (RaycastHit hit in hits) { // ignore ourselves if (hit.collider.transform == transform) { continue; } //print(node.transform.localPosition); coverAvailable = true; break; } } if (!coverAvailable) { coverNodes.RemoveAt(i); --i; } } } } if (coverNodes.Count > 0) { // Get cover node that is closest to the closest checkpoint/goal Checkpoint checkpointTarget = GetClosestCheckpoint(); MBGraphNode optimalCoverNode = checkpointTarget == null ? coverNodes[0] : checkpointTarget.node; if (checkpointTarget != null) { float coverToCPDist = Mathf.Infinity; foreach (MBGraphNode coverNode in coverNodes) { float tempDist = (coverNode.transform.position - checkpointTarget.transform.position).magnitude; if (tempDist < coverToCPDist) { optimalCoverNode = coverNode; coverToCPDist = tempDist; } } } List <GraphNode <GameObject> > path = pathFinding.FindPath(PositionNode.nodeId, optimalCoverNode.nodeId, MovementHeuristic, checkpoints.Count <= 1); if (path.Count > 0) { path.RemoveAt(0); } if (path.Count == 0) { return((int)BTNode.EState.Failure); } Move(path); return((int)BTNode.EState.Success); } else { return((int)BTNode.EState.Failure); } }
public int ShouldUseItem() { //print("ShouldUseItem()"); // TODO: foreach item in inventory, // if any item would give the player any value // set itemToUseIndex to be the item that offers the greatest value and return success // else if none of the items give any value at this moment (ex: no targets, etc...) // return failure int missileIndex = Inventory.GetItemIndex("Rocket"); int boostIndex = Inventory.GetItemIndex("Boost"); int shieldIndex = Inventory.GetItemIndex("Shield"); int oilSpillIndex = Inventory.GetItemIndex("Oil Spill"); if (boostIndex != -1) { itemToUseIndex = boostIndex; } else if (missileIndex != -1) { // check if other players are in sight for missile target foreach (AbstractPlayer p in GameplayManager.Instance.Players) { RaycastHit[] hits = Physics.RaycastAll(transform.position + (Vector3.up * 0.5f), p.transform.position - transform.position); foreach (RaycastHit hit in hits) { // we are colliding with ourself if (hit.transform == transform) { continue; } if (hit.collider.tag.Equals("HumanPlayer") || hit.collider.tag.Equals("AIPlayer")) { AbstractPlayer potentialTarget = hit.collider.GetComponent <AbstractPlayer>(); // check if potentialTarget is in equal or higher place standing. If not, then do not waste the missile on them. if (potentialTarget.checkpoints.Count <= checkpoints.Count) { playerAttackTarget = potentialTarget; itemToUseIndex = missileIndex; } break; } } } } else if (shieldIndex != -1) { // check if player is in sight for foreign missiles foreach (AbstractPlayer p in GameplayManager.Instance.Players) { if (p.Inventory.GetItemIndex("Rocket") != -1) { RaycastHit[] hits = Physics.RaycastAll(p.transform.position + (Vector3.up * 0.5f), transform.position - p.transform.position); Debug.DrawRay(p.transform.position, transform.position - p.transform.position, Color.red, 10000); foreach (RaycastHit hit in hits) { // the ray has hit us if (hit.transform == transform) { itemToUseIndex = shieldIndex; } } // itemToUseIndex = shieldIndex; } } } else if (oilSpillIndex != -1) { // we can only place oil spills on neighbor nodes around us IWeightedDiGraph <GameObject, float> graph = PositionNode.mbGraph.graph; List <GameObject> potentialOilTargets = new List <GameObject>(); foreach (GraphNode <GameObject> graphNode in graph.Neighbors(PositionNode.nodeId)) { // CalculatePathToGoal() and if this node is on that path then do not add it to the list (otherwise we'd be hindering ourselves) potentialOilTargets.Add(graphNode.Data); } Checkpoint checkpointTarget = GetClosestCheckpoint(); MBGraphNode checkpointNode = checkpointTarget == null ? null : checkpointTarget.node; GraphNode <GameObject> optimalGraphNode = reachableNodeIds.Count > 0 ? GameplayManager.Instance.gridGraph.graph[reachableNodeIds[0]] : null; float dist = Mathf.Infinity; foreach (string nodeId in reachableNodeIds) { GraphNode <GameObject> gNode = GameplayManager.Instance.gridGraph.graph[nodeId]; float tempDist = (gNode.Data.transform.position - checkpointNode.transform.position).magnitude; if (tempDist < dist) { optimalGraphNode = gNode; dist = tempDist; } } if (optimalGraphNode != null) { List <GraphNode <GameObject> > path = pathFinding.FindPath(PositionNode.nodeId, optimalGraphNode.Id, MovementHeuristic, checkpoints.Count <= 1); if (path.Count > 0) { path.RemoveAt(0); } if (path.Count == 0) { return((int)BTNode.EState.Failure); } // If there 1 or less nodes that don't have an oil spill on them then don't place the oil spill or else we would be trapping ourselves if (potentialOilTargets.Count > 1) { // select the first potential oil target nodeToSpillOn = potentialOilTargets[0]; foreach (GameObject ot in potentialOilTargets) { if (!path.Contains(GameplayManager.Instance.gridGraph.graph[ot.GetComponent <MBGraphNode>().nodeId])) { nodeToSpillOn = ot; itemToUseIndex = oilSpillIndex; break; } } } } } return(itemToUseIndex >= 0 ? (int)BTNode.EState.Success : (int)BTNode.EState.Failure); }
protected void DrawControls() { MBGraphNode target = (MBGraphNode)this.target; EditorGUILayout.Space(); List <MBGraphNode> selectedNodes = new List <MBGraphNode>(); foreach (GameObject obj in Selection.gameObjects) { if (obj.GetComponent <MBGraphNode>() != null) { selectedNodes.Add(obj.GetComponent <MBGraphNode>()); } } if (selectedNodes.Count == 1) { // A single node is selected EditorGUILayout.BeginVertical(EditorStyles.helpBox); { if (GUILayout.Button("Add Node")) { GameObject addedNode = null; if (addNodeEdgeDirectionality == 2) { addedNode = target.mbGraph.AddNode(); } else { addedNode = target.mbGraph.AddNode(target, addNodeEdgeWeight, (EdgeDirectionality)addNodeEdgeDirectionality); } Selection.activeGameObject = addedNode; } addNodeEdgeDirectionality = EditorGUILayout.Popup("Edge Directionality", addNodeEdgeDirectionality, strEdgeDirectionalities); addNodeEdgeWeightIsDistance = EditorGUILayout.Toggle("Weight == Distance", addNodeEdgeWeightIsDistance); addNodeEdgeWeight = EditorGUILayout.FloatField("Edge Weight", addNodeEdgeWeight); } EditorGUILayout.EndVertical(); } else if (selectedNodes.Count == 2) { // A pair of nodes (edge) has been selected GraphEdge <float>[] modifiableEdges = new GraphEdge <float> [2]; modifiableEdges[0] = target.mbGraph.graph.GetEdge(selectedNodes[0].nodeId, selectedNodes[1].nodeId); modifiableEdges[1] = target.mbGraph.graph.GetEdge(selectedNodes[1].nodeId, selectedNodes[0].nodeId); for (int i = 0; i < modifiableEdges.Length; ++i) { GraphEdge <float> edge = modifiableEdges[i]; EditorGUILayout.BeginVertical(EditorStyles.helpBox); var edgeLabelStyle = new GUIStyle(GUI.skin.label) { fontStyle = FontStyle.Bold }; EditorGUILayout.LabelField(i == 0 ? "A -> B" : "B -> A", edgeLabelStyle); DrawHorizontalLine(); int edgeDirectionalityInt = EditorGUILayout.Popup("Directionality", edge == null ? 2 : (int)edge.Directionality, strEdgeDirectionalities); float edgeWeight = EditorGUILayout.FloatField("Edge Weight", edge == null ? 0 : edge.Weight); bool edgeWeightIsDistance = GUILayout.Button("Weight == Distance"); EditorGUILayout.EndVertical(); if ( (edge != null || edgeDirectionalityInt != 2) && ((edge == null && edgeDirectionalityInt != 2) || edgeWeight != edge.Weight || edgeDirectionalityInt != (int)edge.Directionality) ) { if (edge != null && edgeDirectionalityInt == 2) { target.mbGraph.RemoveEdge(edge.FromId, edge.ToId); } else if (edgeDirectionalityInt != 2) { if (i == 0) { target.mbGraph.SetEdge(selectedNodes[0], selectedNodes[1], edgeWeight, (EdgeDirectionality)edgeDirectionalityInt); } else if (i == 1) { target.mbGraph.SetEdge(selectedNodes[1], selectedNodes[0], edgeWeight, (EdgeDirectionality)edgeDirectionalityInt); } } EditorSceneManager.MarkSceneDirty(target.gameObject.scene); EditorUtility.SetDirty(target); } if (edgeWeightIsDistance) { target.mbGraph.graph.isDirty = true; edge.Weight = (selectedNodes[0].transform.position - selectedNodes[1].transform.position).magnitude; EditorSceneManager.MarkSceneDirty(target.gameObject.scene); EditorUtility.SetDirty(target); } if (edgeDirectionalityInt == 0) { break; } } } }
/// <summary> /// Show the available neighbors to travel to. /// </summary> /// <param name="show"></param> Whether to show the tiles or not. /// <param name="startNode"></param> Which node to start from. /// <param name="times"></param> Number of levels to find the neighbors. /// <param name="direction"></param> Which direction the neighbors are in. private void ShowMovementTiles(bool show, MBGraphNode startNode, int times, Direction direction, List <MBGraphNode> directionTiles) { if (times <= 0) { return; } for (int i = 0; i < startNode.transform.childCount; ++i) { if (startNode.transform.GetChild(i).tag.Equals("GridSquare")) { startNode.transform.GetChild(i).gameObject.SetActive(show); } } var nodeNeighbors = startNode.mbGraph.graph.Neighbors(startNode.nodeId); foreach (var node in nodeNeighbors) { int extraValue = (node.Data.transform.GetComponentInChildren <OilSpillManager>()) != null ? 2 : 0; var mbNode = node.Data.GetComponent <MBGraphNode>(); bool doIt = true; if (GameplayManager.Instance.blockedOffNodes.Contains(mbNode) && player.checkpoints.Count > 1) { doIt = false; } if (node.Data.transform.position.x > startNode.transform.position.x && direction == Direction.Right) { if (doIt) { directionTiles.Add(mbNode); ShowMovementTiles(show, mbNode, times - 1 - extraValue, Direction.Right, directionTiles); } } if (node.Data.transform.position.x < startNode.transform.position.x && direction == Direction.Left) { if (doIt) { directionTiles.Add(mbNode); ShowMovementTiles(show, mbNode, times - 1 - extraValue, Direction.Left, directionTiles); } } if (node.Data.transform.position.z > startNode.transform.position.z && direction == Direction.Down) { if (doIt) { directionTiles.Add(mbNode); ShowMovementTiles(show, mbNode, times - 1 - extraValue, Direction.Down, directionTiles); } } if (node.Data.transform.position.z < startNode.transform.position.z && direction == Direction.Up) { if (doIt) { directionTiles.Add(mbNode); ShowMovementTiles(show, mbNode, times - 1 - extraValue, Direction.Up, directionTiles); } } } }
private void GenerateGrid(MBGraph target) { ClearNodes(target); float width = target.__gridColumns * target.__gridCellSize; float height = target.__gridRows * target.__gridCellSize; Vector3 position = new Vector3(target.transform.position.x - (width / 2), target.transform.position.y, target.transform.position.z - (height / 2)); // 1st pass: generate nodes MBGraphNode[,] nodeGrid = new MBGraphNode[target.__gridRows, target.__gridColumns]; for (int r = 0; r < target.__gridRows; ++r) { float startingX = position.x; for (int c = 0; c < target.__gridColumns; ++c) { bool shouldAddNode = true; if (target.__detectCollisions) { List <Collider> colliders = FilterColliders(target, Physics.OverlapSphere(position, target.__collisionRadius)); shouldAddNode = colliders.Count == 0; } if (shouldAddNode) { GameObject addedNodeObj = target.AddNode(); addedNodeObj.transform.position = position; nodeGrid[r, c] = addedNodeObj.GetComponent <MBGraphNode>(); } position = new Vector3(position.x + target.__gridCellSize, position.y, position.z); } position = new Vector3(startingX, position.y, position.z + target.__gridCellSize); } // 2nd pass: generate edges for (int r = 0; r < target.__gridRows; ++r) { for (int c = 0; c < target.__gridColumns; ++c) { if (nodeGrid[r, c] == null) { continue; } // NWES edges if (c > 0 && nodeGrid[r, c - 1] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r, c - 1]); } if (c < target.__gridColumns - 1 && nodeGrid[r, c + 1] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r, c + 1]); } if (r > 0 && nodeGrid[r - 1, c] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r - 1, c]); } if (r < target.__gridRows - 1 && nodeGrid[r + 1, c] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r + 1, c]); } // diagonal edges if (target.__gridType == MBGraph.EGridType.EightWay) { if (r > 0 && c > 0 && nodeGrid[r - 1, c - 1] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r - 1, c - 1]); } if (r < target.__gridRows - 1 && c < target.__gridColumns - 1 && nodeGrid[r + 1, c + 1] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r + 1, c + 1]); } if (r > 0 && c < target.__gridColumns - 1 && nodeGrid[r - 1, c + 1] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r - 1, c + 1]); } if (r < target.__gridRows - 1 && c > 0 && nodeGrid[r + 1, c - 1] != null) { ConnectGridNodes(target, nodeGrid[r, c], nodeGrid[r + 1, c - 1]); } } } } }