/** **************************************************************************************************** \fn void UpdateAIDestinationTo( UINT8 &i_u8Index, const UINT8 &i_u8NodeID ) \brief Update destination for this AI \param i_u8Index index of entity in AI entity \param i_u8NodeID destination node ID \return NONE **************************************************************************************************** */ void GameEngine::AI::UpdateAIDestinationTo( const UINT8 &i_u8Index, const UINT8 &i_u8NodeID ) { FUNCTION_START; if( AIEntityDatabase->at(i_u8Index)->m_AIState != E_AI_STATE_DEACTIVATE ) AbortAI( i_u8Index ); if( i_u8Index < AIEntityDatabase->size() ) { UINT32 u32ClosestNodeID = Utilities::MAX_UINT32; D3DXVECTOR3 entityPosition( AIEntityDatabase->at(i_u8Index)->m_entity->m_v3Position.X(), AIEntityDatabase->at(i_u8Index)->m_entity->m_v3Position.Y(), AIEntityDatabase->at(i_u8Index)->m_entity->m_v3Position.Z() ); FindClosestNodeIDFromPosition( entityPosition, u32ClosestNodeID ); if( u32ClosestNodeID < wayPointList->size() ) { AIEntityDatabase->at(i_u8Index)->m_u32TargetNodeID = u32ClosestNodeID; AIEntityDatabase->at(i_u8Index)->m_AIState = E_AI_STATE_GO_TO_TARGET_NODE; FindOptimalPath( u32ClosestNodeID, i_u8NodeID, *(AIEntityDatabase->at(i_u8Index)->m_optimalPath) ); } } FUNCTION_FINISH; }
/* ============ idAI::FindPathAroundObstacles Finds a path around dynamic obstacles using a path tree with clockwise and counter clockwise edge walks. ============ */ bool idAI::FindPathAroundObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path ) { int numObstacles, areaNum, insideObstacle; obstacle_t obstacles[MAX_OBSTACLES]; idBounds clipBounds; idBounds bounds; pathNode_t *root; bool pathToGoalExists; path.seekPos = seekPos; path.firstObstacle = NULL; path.startPosOutsideObstacles = startPos; path.startPosObstacle = NULL; path.seekPosOutsideObstacles = seekPos; path.seekPosObstacle = NULL; if( !aas ) { return true; } bounds[1] = aas->GetSettings()->boundingBoxes[0][1]; bounds[0] = -bounds[1]; bounds[1].z = 32.0f; // get the AAS area number and a valid point inside that area areaNum = aas->PointReachableAreaNum( path.startPosOutsideObstacles, bounds, ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) ); aas->PushPointIntoAreaNum( areaNum, path.startPosOutsideObstacles ); // get all the nearby obstacles numObstacles = GetObstacles( physics, aas, ignore, areaNum, path.startPosOutsideObstacles, path.seekPosOutsideObstacles, obstacles, MAX_OBSTACLES, clipBounds ); // get a source position outside the obstacles GetPointOutsideObstacles( obstacles, numObstacles, path.startPosOutsideObstacles.ToVec2(), &insideObstacle, NULL ); if( insideObstacle != -1 ) { path.startPosObstacle = obstacles[insideObstacle].entity; } // get a goal position outside the obstacles GetPointOutsideObstacles( obstacles, numObstacles, path.seekPosOutsideObstacles.ToVec2(), &insideObstacle, NULL ); if( insideObstacle != -1 ) { path.seekPosObstacle = obstacles[insideObstacle].entity; } // if start and destination are pushed to the same point, we don't have a path around the obstacle if( ( path.seekPosOutsideObstacles.ToVec2() - path.startPosOutsideObstacles.ToVec2() ).LengthSqr() < Square( 1.0f ) ) { if( ( seekPos.ToVec2() - startPos.ToVec2() ).LengthSqr() > Square( 2.0f ) ) { return false; } } // build a path tree root = BuildPathTree( obstacles, numObstacles, clipBounds, path.startPosOutsideObstacles.ToVec2(), path.seekPosOutsideObstacles.ToVec2(), path ); // draw the path tree if( ai_showObstacleAvoidance.GetBool() ) { DrawPathTree( root, physics->GetOrigin().z ); } // prune the tree PrunePathTree( root, path.seekPosOutsideObstacles.ToVec2() ); // find the optimal path pathToGoalExists = FindOptimalPath( root, obstacles, numObstacles, physics->GetOrigin().z, physics->GetLinearVelocity(), path.seekPos ); // free the tree FreePathTree_r( root ); return pathToGoalExists; }
/** **************************************************************************************************** \fn float FindSquaredDistanceToNodeID( const D3DXVECTOR3 &i_vCurrPosition, const UINT32 &i_u32NodeID ) \brief Find squared distance from position to node ID \param *i_vCurrPosition current entity position \param i_u32NodeID the node ID \return float \retval Squared distance to the given node **************************************************************************************************** */ float GameEngine::AI::FindDistanceToNodeID( const D3DXVECTOR3 &i_vCurrPosition, const UINT32 &i_u32NodeID ) { UINT32 u32ClosestNodeID; float returnDistance = 0.0f; FUNCTION_START; FindClosestNodeIDFromPosition( i_vCurrPosition, u32ClosestNodeID ); if( u32ClosestNodeID < wayPointList->size() ) { D3DXVECTOR3 distance; distance = wayPointList->at(u32ClosestNodeID).centre - i_vCurrPosition; returnDistance = D3DXVec3Length( &distance ); std::deque<UINT32> path; bool bResult = FindOptimalPath( u32ClosestNodeID, i_u32NodeID, path ); if( bResult ) { std::deque<UINT32>::const_iterator pathIter = path.begin(); for( ; pathIter != path.end(); ++pathIter ) { D3DXVECTOR3 startPoint = wayPointList->find((*pathIter))->second.centre; D3DXVECTOR3 endPoint = startPoint; ++pathIter; if( pathIter != path.end() ) endPoint = wayPointList->find((*pathIter))->second.centre; --pathIter; distance = endPoint - startPoint; returnDistance += D3DXVec3Length( &distance ); } } } FUNCTION_FINISH; return returnDistance; }