/// <summary> /// Called once per frame by the game object. /// </summary> /// <param name="gameTime">The amount of time that has passed this frame.</param> public override void Update(GameTime gameTime) { // Does this instance of the behaviour just want to automatically update the source // based on our parents position? if (mUpdateSourceAutomatically) { SetSource(mParentGOH.pPosition); } if (mGetNavMeshMsg.mNavMesh_Out != null) { //mGetNavMeshMsg.mNavMesh_Out.DebugCheckNodes(); } // Plan the path at a high level. MBHEngine.PathFind.GenericAStar.Planner.Result res = mPlannerNavMesh.PlanPath(); // If the search is anything but InProgress it is safe to research the pass counter. if (res == Planner.Result.InProgress) { mSearchPassCount++; } else { mSearchPassCount = 0; } // If the planner failed to find the destination tell the other behaviours. if (res == MBHEngine.PathFind.GenericAStar.Planner.Result.Failed || res == Planner.Result.InvalidLocation || mSearchPassCount > mSearchPassLimit) { if (res == Planner.Result.Failed) { mOnPathFindFailedMsg.mReason = OnPathFindFailedMessage.Reason.Failed; } else if (res == Planner.Result.InvalidLocation) { mOnPathFindFailedMsg.mReason = OnPathFindFailedMessage.Reason.InvalidLocation; } else if (mSearchPassCount > mSearchPassLimit) { mOnPathFindFailedMsg.mReason = OnPathFindFailedMessage.Reason.Timeout; } mParentGOH.OnMessage(mOnPathFindFailedMsg); mSearchPassCount = 0; } else if (res == Planner.Result.Solved)// && InputManager.pInstance.CheckAction(InputManager.InputActions.B)) { // When the high level path finding is solved, start path finding at a lower // level betwen PathNodes within the higher level. // PathNode node = mPlannerNavMesh.pCurrentBest; // We need to do more than just walk the list until we hit the mLastHighLevelSearched. There // are cases (such as 2 nodes at the same position) where we don't want to use a Node. // This tracks which was the last VALID node. PathNode lastValid = node; // Loop all the way back to one after the starting point avoiding the starting node, as // well as previously searched nodes. // We don't want the starting node because that is where we are likely already standing. while ( node != mLastHighLevelSearched && // Was the first node actually the one we looked at last Update? node.pPrevious != mLastHighLevelSearched && // Is the next one the Node looked at last Update? node.pPrevious.pGraphNode.pPosition != mPlannerTileMap.pStart.pPosition && // Is this Node at the same position as the starting position? We are already there so trying to get there again would cause issues. node.pPrevious.pPrevious != null) { node = node.pPrevious; // Only choose nodes that are not at the same position as the last valid node. Trying to path find between // 2 nodes at the TileMap level causes problems. It will solve the path fine, but the issue is when it goes // back to the HPA level, since it hasn't moved the starting position, HPA will find the exact same path. // This cycle repeats forever. if (lastValid.pGraphNode.pPosition != node.pGraphNode.pPosition) { lastValid = node; } } node = lastValid; // The lower level search uses the Level.Tile Graph, not the NavMesh, so we need to // use the node in NavMesh to find a node in the main tile map. mGetTileAtPositionMsg.Reset(); mGetTileAtPositionMsg.mPosition_In = node.pGraphNode.pPosition; WorldManager.pInstance.pCurrentLevel.OnMessage(mGetTileAtPositionMsg); // If this is the first time we are searching at the low level (for this particular // search) we want to SET the destination. If that isn't the case, we want to extend // the search to continue to a new destination. if (null == mLowLevelBest) { mPlannerTileMap.SetDestination(mGetTileAtPositionMsg.mTile_Out.mGraphNode); } else { mPlannerTileMap.ExtendDestination(mGetTileAtPositionMsg.mTile_Out.mGraphNode); } // Start/Continue planning the path. Planner.Result tileRes = mPlannerTileMap.PlanPath(); // Once the path has been solved, store out that this node in the high level search has // been completed, so the next time through this function, the next node in the path w // will be the target. if (tileRes == Planner.Result.Solved) { mLowLevelBest = mPlannerTileMap.pCurrentBest; mLastHighLevelSearched = node; } } }