예제 #1
0
//-----------------------------------------------------------------------------
// Step iteratively toward a destination position
//-----------------------------------------------------------------------------
AIMotorMoveResult_t CAI_Motor::MoveGroundStep( const Vector &newPos, CBaseEntity *pMoveTarget, float yaw, bool bAsFarAsCan, AIMoveTrace_t *pTraceResult )
{
	// By definition, this will produce different results than GroundMoveLimit() 
	// because there's no guarantee that it will step exactly one step 

	// See how far toward the new position we can step...
	// But don't actually test for ground geometric validity;
	// if it isn't valid, there's not much we can do about it
	AIMoveTrace_t moveTrace;
	GetMoveProbe()->TestGroundMove( GetLocalOrigin(), newPos, MASK_NPCSOLID, AITGM_IGNORE_FLOOR, &moveTrace );
	if ( pTraceResult )
	{
		*pTraceResult = moveTrace;
	}

	bool bHitTarget = (moveTrace.pObstruction && (pMoveTarget == moveTrace.pObstruction ));

	// Move forward either if there was no obstruction or if we're told to
	// move as far as we can, regardless
	bool bIsBlocked = IsMoveBlocked(moveTrace.fStatus);
	if ( !bIsBlocked || bAsFarAsCan || bHitTarget )
	{
		// The true argument here causes it to touch all triggers
		// in the volume swept from the previous position to the current position
		UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true);
		
		// skip tiny steps, but notify the shadow object of any large steps
		if ( moveTrace.flStepUpDistance > 0.1f )
		{
			float height = clamp( moveTrace.flStepUpDistance, 0, StepHeight() );
			IPhysicsObject *pPhysicsObject = GetOuter()->VPhysicsGetObject();
			if ( pPhysicsObject )
			{
				IPhysicsShadowController *pShadow = pPhysicsObject->GetShadowController();
				if ( pShadow )
				{
					pShadow->StepUp( height );
				}
			}
		}
		if ( yaw != -1 )
		{
			QAngle angles = GetLocalAngles();
			angles.y = yaw;
			SetLocalAngles( angles );
		}
		if ( bHitTarget )
			return AIM_PARTIAL_HIT_TARGET;
			
		if ( !bIsBlocked )
			return AIM_SUCCESS;
			
		if ( moveTrace.fStatus == AIMR_BLOCKED_NPC )
			return AIM_PARTIAL_HIT_NPC;

		return AIM_PARTIAL_HIT_WORLD;
	}
	return AIM_FAILED;
}
예제 #2
0
//-----------------------------------------------------------------------------
// Step iteratively toward a destination position
//-----------------------------------------------------------------------------
AIMotorMoveResult_t CAI_Motor::MoveGroundStep( const Vector &newPos, CBaseEntity *pMoveTarget, float yaw, bool bAsFarAsCan, bool bTestZ, AIMoveTrace_t *pTraceResult )
{
	// By definition, this will produce different results than GroundMoveLimit() 
	// because there's no guarantee that it will step exactly one step 

	// See how far toward the new position we can step...
	// But don't actually test for ground geometric validity;
	// if it isn't valid, there's not much we can do about it
	AIMoveTrace_t moveTrace;
	unsigned testFlags = AITGM_IGNORE_FLOOR;

	char *pchHackBoolToInt = (char*)(&bTestZ);
	if ( *pchHackBoolToInt == 2 )
	{
		testFlags |= AITGM_CRAWL_LARGE_STEPS;
	}
	else
	{
		if ( !bTestZ )
			testFlags |= AITGM_2D;
	}

#ifdef DEBUG
	if ( ai_draw_motor_movement.GetBool() )
		testFlags |= AITGM_DRAW_RESULTS;
#endif

	GetMoveProbe()->TestGroundMove( GetLocalOrigin(), newPos, GetOuter()->GetAITraceMask(), testFlags, &moveTrace );
	if ( pTraceResult )
	{
		*pTraceResult = moveTrace;
	}

	bool bHitTarget = (moveTrace.pObstruction && (pMoveTarget == moveTrace.pObstruction ));

	// Move forward either if there was no obstruction or if we're told to
	// move as far as we can, regardless
	bool bIsBlocked = IsMoveBlocked(moveTrace.fStatus);
	if ( !bIsBlocked || bAsFarAsCan || bHitTarget )
	{
#ifdef DEBUG
		if ( GetMoveProbe()->CheckStandPosition( GetLocalOrigin(), GetOuter()->GetAITraceMask() ) && !GetMoveProbe()->CheckStandPosition( moveTrace.vEndPosition, GetOuter()->GetAITraceMask() ) )
		{
			DevMsg( 2, "Warning: AI motor probably given invalid instructions\n" );
		}
#endif

		// The true argument here causes it to touch all triggers
		// in the volume swept from the previous position to the current position
		UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true);

		// check to see if our ground entity has changed
		// NOTE: This is to detect changes in ground entity as the movement code has optimized out
		// ground checks.  So now we have to do a simple recheck to make sure we detect when we've 
		// stepped onto a new entity.
		if ( GetOuter()->GetFlags() & FL_ONGROUND )
		{
			GetOuter()->PhysicsStepRecheckGround();
		}

		// skip tiny steps, but notify the shadow object of any large steps
		if ( moveTrace.flStepUpDistance > 0.1f )
		{
			float height = clamp( moveTrace.flStepUpDistance, 0, StepHeight() );
			IPhysicsObject *pPhysicsObject = GetOuter()->VPhysicsGetObject();
			if ( pPhysicsObject )
			{
				IPhysicsShadowController *pShadow = pPhysicsObject->GetShadowController();
				if ( pShadow )
				{
					pShadow->StepUp( height );
				}
			}
		}
		if ( yaw != -1 )
		{
			QAngle angles = GetLocalAngles();
			angles.y = yaw;
			SetLocalAngles( angles );
		}
		if ( bHitTarget )
			return AIM_PARTIAL_HIT_TARGET;
			
		if ( !bIsBlocked )
			return AIM_SUCCESS;
			
		if ( moveTrace.fStatus == AIMR_BLOCKED_NPC )
			return AIM_PARTIAL_HIT_NPC;

		return AIM_PARTIAL_HIT_WORLD;
	}
	return AIM_FAILED;
}
예제 #3
0
void CPhysicsSystem::PhysicsSimulate()
{
	CMiniProfilerGuard mpg(&g_mp_PhysicsSimulate);
	VPROF_BUDGET( "CPhysicsSystem::PhysicsSimulate", VPROF_BUDGETGROUP_PHYSICS );
	float frametime = gpGlobals->frametime;

	if ( physenv )
	{
		g_Collisions.BufferTouchEvents( true );
#ifdef _DEBUG
		physenv->DebugCheckContacts();
#endif
		frametime *= cl_phys_timescale.GetFloat();

		int maxTicks = cl_phys_maxticks.GetInt();
		if ( maxTicks )
		{
			float maxFrameTime = physenv->GetDeltaFrameTime( maxTicks ) - 1e-4f;
			frametime = clamp( frametime, 0, maxFrameTime );
		}

		physenv->Simulate( frametime );

		int activeCount = physenv->GetActiveObjectCount();
		g_mp_active_object_count.Add(activeCount);
		IPhysicsObject **pActiveList = NULL;
		if ( activeCount )
		{
			PHYS_PROFILE(aUpdateActiveObjects)
			pActiveList = (IPhysicsObject **)stackalloc( sizeof(IPhysicsObject *)*activeCount );
			physenv->GetActiveObjects( pActiveList );

			for ( int i = 0; i < activeCount; i++ )
			{
				C_BaseEntity *pEntity = reinterpret_cast<C_BaseEntity *>(pActiveList[i]->GetGameData());
				if ( pEntity )
				{
					//const CCollisionProperty *collProp = pEntity->CollisionProp();
					//debugoverlay->AddBoxOverlay( collProp->GetCollisionOrigin(), collProp->OBBMins(), collProp->OBBMaxs(), collProp->GetCollisionAngles(), 190, 190, 0, 0, 0.01 );

					if ( pEntity->CollisionProp()->DoesVPhysicsInvalidateSurroundingBox() )
					{
						pEntity->CollisionProp()->MarkSurroundingBoundsDirty();
					}
					pEntity->VPhysicsUpdate( pActiveList[i] );
					IPhysicsShadowController *pShadow = pActiveList[i]->GetShadowController();
					if ( pShadow )
					{
						// active shadow object, check for error
						Vector pos, targetPos;
						QAngle rot, targetAngles;
						pShadow->GetTargetPosition( &targetPos, &targetAngles );
						pActiveList[i]->GetPosition( &pos, &rot );
						Vector delta = targetPos - pos;
						float dist = VectorNormalize(delta);
						bool bBlocked = false;
						if ( dist > cl_phys_block_dist.GetFloat() )
						{
							Vector vel;
							pActiveList[i]->GetImplicitVelocity( &vel, NULL );
							float proj = DotProduct(vel, delta);
							if ( proj < dist * cl_phys_block_fraction.GetFloat() )
							{
								bBlocked = true;
								//Msg("%s was blocked %.3f (%.3f proj)!\n", pEntity->GetClassname(), dist, proj );
							}
						}
						Vector targetAxis;
						float deltaTargetAngle;
						RotationDeltaAxisAngle( rot, targetAngles, targetAxis, deltaTargetAngle );
						if ( fabsf(deltaTargetAngle) > 0.5f )
						{
							AngularImpulse angVel;
							pActiveList[i]->GetImplicitVelocity( NULL, &angVel );
							float proj = DotProduct( angVel, targetAxis ) * Sign(deltaTargetAngle);
							if ( proj < (fabsf(deltaTargetAngle) * cl_phys_block_fraction.GetFloat()) )
							{
								bBlocked = true;
								//Msg("%s was rot blocked %.3f proj %.3f!\n", pEntity->GetClassname(), deltaTargetAngle, proj );
							}
						}
					
						if ( bBlocked )
						{
							C_BaseEntity *pBlocker = FindPhysicsBlocker( pActiveList[i] );
							if ( pBlocker )
							{
								if ( IsBlockedShouldDisableCollisions( pEntity ) )
								{
									PhysDisableEntityCollisions( pEntity, pBlocker );
									pActiveList[i]->RecheckContactPoints();
									// GetClassname returns a pointer to the same buffer always!
									//Msg("%s blocked !", pEntity->GetClassname() ); Msg("by %s\n", pBlocker->GetClassname() );
								}
							}
						}
					}
				}
			}
		}

#if 0
		if ( cl_visualize_physics_shadows.GetBool() )
		{
			int entityCount = NUM_ENT_ENTRIES;
			for ( int i = 0; i < entityCount; i++ )
			{
				IClientEntity *pClientEnt = cl_entitylist->GetClientEntity(i);
				if ( !pClientEnt )
					continue;
				C_BaseEntity *pEntity = pClientEnt->GetBaseEntity();
				if ( !pEntity )
					continue;

				Vector pos;
				QAngle angle;
				IPhysicsObject *pObj = pEntity->VPhysicsGetObject();
				if ( !pObj || !pObj->GetShadowController() )
					continue;

				pObj->GetShadowPosition( &pos, &angle );
				debugoverlay->AddBoxOverlay( pos, pEntity->CollisionProp()->OBBMins(), pEntity->CollisionProp()->OBBMaxs(), angle, 255, 255, 0, 32, 0 );
				char tmp[256];
				V_snprintf( tmp, sizeof(tmp),"%s, (%s)\n", pEntity->GetClassname(), VecToString(angle) );
				debugoverlay->AddTextOverlay( pos, 0, tmp );
			}
		}
#endif
		g_Collisions.BufferTouchEvents( false );
		g_Collisions.FrameUpdate();
	}
	physicssound::PlayImpactSounds( m_impactSounds );
}