//----------------------------------------------------------------------------- // Visualizes the regulations for debugging purposes //----------------------------------------------------------------------------- void CAI_PlaneSolver::VisualizeRegulations() { // Visualization of regulations if ((GetNpc()->m_debugOverlays & OVERLAY_NPC_STEERING_REGULATIONS) != 0) { m_Solver.VisualizeRegulations( GetNpc()->WorldSpaceCenter() ); } }
void CAI_PlaneSolver::VisualizeSolution( const Vector &vecGoal, const Vector& vecActual ) { if ((GetNpc()->m_debugOverlays & OVERLAY_NPC_STEERING_REGULATIONS) != 0) { // Compute centroid... Vector centroid = GetNpc()->WorldSpaceCenter(); Vector goalPt, actualPt; VectorMA( centroid, 20, vecGoal, goalPt ); VectorMA( centroid, 20, vecActual, actualPt ); NDebugOverlay::Line(centroid, goalPt, 255, 255, 255, true, 0.1f ); NDebugOverlay::Line(centroid, actualPt, 255, 255, 0, true, 0.1f ); } }
float CAI_PlaneSolver::AdjustRegulationWeight( CBaseEntity *pEntity, float weight ) { if ( pEntity->MyNPCPointer() != NULL ) { // @TODO (toml 10-03-02): How to do this with non-NPC entities. Should be using intended solve velocity... Vector2D velOwner = GetNpc()->GetMotor()->GetCurVel().AsVector2D(); Vector2D velBlocker = ((CAI_BaseNPC *)pEntity)->GetMotor()->GetCurVel().AsVector2D(); Vector2D velOwnerNorm = velOwner; Vector2D velBlockerNorm = velBlocker; float speedOwner = Vector2DNormalize( velOwnerNorm ); float speedBlocker = Vector2DNormalize( velBlockerNorm ); float dot = velOwnerNorm.Dot( velBlockerNorm ); if ( speedBlocker > 0 ) { if ( dot > 0 && speedBlocker >= speedOwner * 0.9 ) { if ( dot > 0.86 ) { // @Note (toml 10-10-02): Even in the case of no obstacle, we generate // a suggestion in because we still want to continue sweeping the // search weight = 0; } else if ( dot > 0.7 ) { weight *= sq( weight ); } else weight *= weight; } } } return weight; }
KSceneObject* GetSceneObject(DWORD dwObjectType, DWORD dwObject) { KSceneObject* pObject = NULL; switch (dwObjectType) { case RL_OBJECT_PLAYER: case RL_OBJECT_RIDES: pObject = GetPlayer(dwObject); break; case RL_OBJECT_NPC: pObject = GetNpc(dwObject); break; case RL_OBJECT_DOODAD: pObject = GetDoodad(dwObject); break; case RL_OBJECT_UNKNOWN: /* fall through */ default: break; } return pObject; }
//----------------------------------------------------------------------------- bool CAI_PlaneSolver::GenerateCircleObstacleSuggestions( const AILocalMoveGoal_t &moveGoal, float probeDist ) { bool result = false; Vector npcLoc = m_pNpc->WorldSpaceCenter(); Vector mins, maxs; m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); float radiusNpc = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5; for ( int i = 0; i < m_Obstacles.Count(); i++ ) { CBaseEntity *pObstacleEntity = NULL; float zDistTooFar; if ( m_Obstacles[i].hEntity && m_Obstacles[i].hEntity->CollisionProp() ) { pObstacleEntity = m_Obstacles[i].hEntity.Get(); if( pObstacleEntity == moveGoal.pMoveTarget && (pObstacleEntity->IsNPC() || pObstacleEntity->IsPlayer()) ) { // HEY! I'm trying to avoid the very thing I'm trying to get to. This will make we wobble like a drunk as I approach. Don't do it. continue; } pObstacleEntity->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); zDistTooFar = ( maxs.z - mins.z ) * 0.5 + GetNpc()->GetHullHeight() * 0.5; } else zDistTooFar = GetNpc()->GetHullHeight(); if ( fabs( m_Obstacles[i].center.z - npcLoc.z ) > zDistTooFar ) continue; Vector vecToNpc = npcLoc - m_Obstacles[i].center; vecToNpc.z = 0; float distToObstacleSq = sq(vecToNpc.x) + sq(vecToNpc.y); float radius = m_Obstacles[i].radius + radiusNpc; if ( distToObstacleSq > 0.001 && distToObstacleSq < sq( radius + probeDist ) ) { Vector vecToObstacle = vecToNpc * -1; float distToObstacle = VectorNormalize( vecToObstacle ); float weight; float arc; float radiusSq = sq(radius); float flDot = DotProduct( vecToObstacle, moveGoal.dir ); // Don't steer around to avoid obstacles we've already passed, unless we're right up against them. // That is, do this computation without the probeDist added in. if( flDot < 0.0f && distToObstacleSq > radiusSq ) { continue; } if ( radiusSq < distToObstacleSq ) { Vector vecTangent; float distToTangent = FastSqrt( distToObstacleSq - radiusSq ); float oneOverDistToObstacleSq = 1 / distToObstacleSq; vecTangent.x = ( -distToTangent * vecToNpc.x + radius * vecToNpc.y ) * oneOverDistToObstacleSq; vecTangent.y = ( -distToTangent * vecToNpc.y - radius * vecToNpc.x ) * oneOverDistToObstacleSq; vecTangent.z = 0; float cosHalfArc = vecToObstacle.Dot( vecTangent ); arc = RAD2DEG(acosf( cosHalfArc )) * 2.0; weight = 1.0 - (distToObstacle - radius) / probeDist; if ( weight > 0.75 ) arc += (arc * 0.5) * (weight - 0.75) / 0.25; Assert( weight >= 0.0 && weight <= 1.0 ); #if DEBUG_OBSTACLES // ------------------------- Msg( "Adding arc %f, w %f\n", arc, weight ); Vector pointTangent = npcLoc + ( vecTangent * distToTangent ); NDebugOverlay::Line( npcLoc - Vector( 0, 0, 64 ), npcLoc + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( center - Vector( 0, 0, 64 ), center + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( pointTangent - Vector( 0, 0, 64 ), pointTangent + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( npcLoc + Vector(0,0,64), center + Vector(0,0,64), 0,0,255, false, 0.1 ); NDebugOverlay::Line( center + Vector(0,0,64), pointTangent + Vector(0,0,64), 0,0,255, false, 0.1 ); NDebugOverlay::Line( pointTangent + Vector(0,0,64), npcLoc + Vector(0,0,64), 0,0,255, false, 0.1 ); #endif } else { arc = 210; weight = 1.0; } if ( m_Obstacles[i].hEntity != NULL ) { weight = AdjustRegulationWeight( m_Obstacles[i].hEntity, weight ); } AI_MoveSuggestion_t suggestion( m_Obstacles[i].type, weight, UTIL_VecToYaw(vecToObstacle), arc ); m_Solver.AddRegulation( suggestion ); result = true; } } m_Obstacles.RemoveAll(); return result; }
bool CAI_PlaneSolver::GenerateCircleObstacleSuggestions( float probeDist ) { bool result = false; Vector npcLoc = m_pNpc->WorldSpaceCenter(); Vector mins, maxs; m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); float radiusNpc = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5; for ( int i = 0; i < m_Obstacles.Count(); i++ ) { float zDistTooFar; if ( m_Obstacles[i].hEntity && m_Obstacles[i].hEntity->CollisionProp() ) { m_Obstacles[i].hEntity->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); zDistTooFar = ( maxs.z - mins.z ) * 0.5 + GetNpc()->GetHullHeight() * 0.5; } else zDistTooFar = GetNpc()->GetHullHeight(); if ( fabs( m_Obstacles[i].center.z - npcLoc.z ) > zDistTooFar ) continue; Vector vecToNpc = npcLoc - m_Obstacles[i].center; vecToNpc.z = 0; float distToObstacleSq = sq(vecToNpc.x) + sq(vecToNpc.y); float radius = m_Obstacles[i].radius + radiusNpc; if ( distToObstacleSq > 0.001 && distToObstacleSq < sq(radius + probeDist)) { Vector vecToObstacle = vecToNpc * -1; float distToObstacle = VectorNormalize( vecToObstacle ); float weight; float arc; float radiusSq = sq(radius); if ( radiusSq < distToObstacleSq ) { Vector vecTangent; float distToTangent = FastSqrt( distToObstacleSq - radiusSq ); float oneOverDistToObstacleSq = 1 / distToObstacleSq; vecTangent.x = ( -distToTangent * vecToNpc.x + radius * vecToNpc.y ) * oneOverDistToObstacleSq; vecTangent.y = ( -distToTangent * vecToNpc.y - radius * vecToNpc.x ) * oneOverDistToObstacleSq; vecTangent.z = 0; float cosHalfArc = vecToObstacle.Dot( vecTangent ); arc = RAD2DEG(acosf( cosHalfArc )) * 2.0; weight = 1.0 - (distToObstacle - radius) / probeDist; if ( weight > 0.75 ) arc += (arc * 0.5) * (weight - 0.75) / 0.25; Assert( weight >= 0.0 && weight <= 1.0 ); #if DEBUG_OBSTACLES // ------------------------- Msg( "Adding arc %f, w %f\n", arc, weight ); Vector pointTangent = npcLoc + ( vecTangent * distToTangent ); NDebugOverlay::Line( npcLoc - Vector( 0, 0, 64 ), npcLoc + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( center - Vector( 0, 0, 64 ), center + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( pointTangent - Vector( 0, 0, 64 ), pointTangent + Vector(0,0,64), 0,255,0, false, 0.1 ); NDebugOverlay::Line( npcLoc + Vector(0,0,64), center + Vector(0,0,64), 0,0,255, false, 0.1 ); NDebugOverlay::Line( center + Vector(0,0,64), pointTangent + Vector(0,0,64), 0,0,255, false, 0.1 ); NDebugOverlay::Line( pointTangent + Vector(0,0,64), npcLoc + Vector(0,0,64), 0,0,255, false, 0.1 ); #endif } else { arc = 210; weight = 1.0; } if ( m_Obstacles[i].hEntity != NULL ) { weight = AdjustRegulationWeight( m_Obstacles[i].hEntity, weight ); } AI_MoveSuggestion_t suggestion( m_Obstacles[i].type, weight, UTIL_VecToYaw(vecToObstacle), arc ); m_Solver.AddRegulation( suggestion ); result = true; } } m_Obstacles.RemoveAll(); return result; }
bool CAI_PlaneSolver::MoveLimit( Navigation_t navType, const Vector &target, bool ignoreTransients, bool fCheckStep, AIMoveTrace_t *pMoveTrace ) { return MoveLimit( navType, target, ignoreTransients, fCheckStep, GetNpc()->GetAITraceMask(), pMoveTrace ); }