void CPhysicsSpring::AttachListener()
{
	if ( !(m_pObjStart->GetCallbackFlags() & CALLBACK_NEVER_DELETED) )
	{
		m_pObjStart->GetObject()->add_listener_object( this );
	}

	if ( !(m_pObjEnd->GetCallbackFlags() & CALLBACK_NEVER_DELETED) )
	{
		m_pObjEnd->GetObject()->add_listener_object( this );
	}
}
bool CPlayerController::IsInContact() {
	CPhysicsEnvironment *pEnv = m_pObject->GetVPhysicsEnvironment();

	int numManifolds = pEnv->GetBulletEnvironment()->getDispatcher()->getNumManifolds();
	for (int i = 0; i < numManifolds; i++) {
		btPersistentManifold *contactManifold = pEnv->GetBulletEnvironment()->getDispatcher()->getManifoldByIndexInternal(i);
		const btCollisionObject *obA = contactManifold->getBody0();
		const btCollisionObject *obB = contactManifold->getBody1();
		CPhysicsObject *pPhysUs = NULL;
		CPhysicsObject *pPhysOther = NULL;

		if (contactManifold->getNumContacts() > 0 && (obA == m_pObject->GetObject() || obB == m_pObject->GetObject())) {
			if (obA == m_pObject->GetObject()) {
				pPhysUs = (CPhysicsObject *)obA->getUserPointer();
				pPhysOther = (CPhysicsObject *)obB->getUserPointer();
			} else if (obB == m_pObject->GetObject()) {
				pPhysUs = (CPhysicsObject *)obB->getUserPointer();
				pPhysOther = (CPhysicsObject *)obA->getUserPointer();
			}

			if (pPhysOther->IsStatic() || !pPhysOther->IsMotionEnabled() || (pPhysOther->GetCallbackFlags() & CALLBACK_SHADOW_COLLISION))
				continue;

			return true;
		}
	}

	return false;
}
void CPhysicsSpring::DetachListener()
{
	if ( !(m_pObjStart->GetCallbackFlags() & CALLBACK_NEVER_DELETED) )
	{
		m_pObjStart->GetObject()->remove_listener_object( this );
	}

	if ( !(m_pObjEnd->GetCallbackFlags() & CALLBACK_NEVER_DELETED) )
	{
		m_pObjEnd->GetObject()->remove_listener_object( this );
	}

	m_pObjStart = NULL;
	m_pObjEnd = NULL;
	m_pSpring = NULL;
}
bool CPlayerController::IsInContact( void )
{
	IVP_Real_Object *pivp = m_pObject->GetObject();
	if ( !pivp->flags.collision_detection_enabled )
		return false;

	IVP_Synapse_Friction *pfriction = pivp->get_first_friction_synapse();
	while ( pfriction )
	{
		extern IVP_Real_Object *GetOppositeSynapseObject( IVP_Synapse_Friction *pfriction );

		IVP_Real_Object *pobj = GetOppositeSynapseObject( pfriction );
		if ( pobj->flags.collision_detection_enabled )
		{
			// skip if this is a static object
			if ( !pobj->get_core()->physical_unmoveable && !pobj->get_core()->pinned )
			{
				CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pobj->client_data);
				
				// skip if this is a shadow object
				// UNDONE: Is this a hack? need a better way to detect shadows?
				if ( !(pPhys->GetCallbackFlags() & CALLBACK_SHADOW_COLLISION) )
					return true;
			}
		}

		pfriction = pfriction->get_next();
	}

	return false;
}
Пример #5
0
		void Tick() {
			btDiscreteDynamicsWorld *pBulletEnv = m_pEnv->GetBulletEnvironment();
			btCollisionObjectArray &colObjArray = pBulletEnv->getCollisionObjectArray();
			for (int i = 0; i < colObjArray.size(); i++) {
				CPhysicsObject *pObj = (CPhysicsObject *)colObjArray[i]->getUserPointer();
				if (!pObj) continue; // Internal object that the game doesn't need to know about

				Assert(*(char *)pObj != 0xDD); // Make sure the object isn't deleted (only works in debug builds)
 
				// Don't add objects marked for delete
				if (pObj->GetCallbackFlags() & CALLBACK_MARKED_FOR_DELETE) {
					continue;
				}

				if (colObjArray[i]->getActivationState() != pObj->GetLastActivationState()) {
					int newState = colObjArray[i]->getActivationState();

					// Not a state we want to track.
					if (newState == WANTS_DEACTIVATION)
						continue;

					if (m_pObjEvents) {
						switch (newState) {
							// FIXME: Objects may call objectwake twice if they go from disable_deactivation -> active_tag
							case DISABLE_DEACTIVATION:
							case ACTIVE_TAG:
								m_pObjEvents->ObjectWake(pObj);
								break;
							case ISLAND_SLEEPING: // Don't call ObjectSleep on DISABLE_SIMULATION on purpose.
								m_pObjEvents->ObjectSleep(pObj);
								break;
						}
					}

					switch (newState) {
						case DISABLE_DEACTIVATION:
						case ACTIVE_TAG:
							// Don't add the object twice!
							if (m_activeObjects.Find(pObj) == -1)
								m_activeObjects.AddToTail(pObj);

							break;
						case DISABLE_SIMULATION:
						case ISLAND_SLEEPING:
							m_activeObjects.FindAndRemove(pObj);
							break;
					}

					pObj->SetLastActivationState(newState);
				}
			}
		}
	virtual void core_left_volume( IVP_Controller_Phantom *controller, IVP_Core *pCore )
	{
		CPhysicsFluidController *pFluid = static_cast<CPhysicsFluidController *>( controller->client_data );
		IVP_Real_Object *pivp = pCore->objects.element_at(0);
		CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pivp->client_data);
		if ( !pObject )
			return;

		if ( pFluid )
		{
			if ( pObject && (pObject->GetCallbackFlags() & CALLBACK_FLUID_TOUCH) )
			{
				m_pCallback->FluidEndTouch( pObject, pFluid );
			}
		}
		else
		{
			// must be a trigger
			IVP_Real_Object *pTriggerIVP = controller->get_object();
			CPhysicsObject *pTrigger = static_cast<CPhysicsObject *>(pTriggerIVP->client_data);

			m_pCallback->ObjectLeaveTrigger( pTrigger, pObject );
		}
	}
	//-----------------------------------------------------------------------------
	// Purpose: This walks the objects in the environment and generates friction events
	//			for any scraping that is occurring.
	//-----------------------------------------------------------------------------
	void ProcessActiveObjects( IVP_Environment *pEnvironment, IPhysicsCollisionEvent *pEvent )
	{
		// FIXME: Is this correct? Shouldn't it do next PSI - lastScrape?
		float nextTime = pEnvironment->get_old_time_of_last_PSI().get_time();
		float delta = nextTime - m_lastScrapeTime;

		// only process if we have done a PSI
		if ( delta < pEnvironment->get_delta_PSI_time() )
			return;

		float t = 1.0f;
		t /= delta;
		if ( t > 10.0f )
			t = 10.0f;

		m_lastScrapeTime = nextTime;

		// UNDONE: This only calls friciton for one object in each pair.
		// UNDONE: Split energy in half and call for both objects?
		// UNDONE: Don't split/call if one object is static (like the world)?
		for ( int i = 0; i < m_activeObjects.Count(); i++ )
		{
			CPhysicsObject *pObject = m_activeObjects[i];
			IVP_Real_Object *ivpObject = pObject->GetObject();
			
			// no friction callbacks for this object
			if ( ! (pObject->GetCallbackFlags() & CALLBACK_GLOBAL_FRICTION) )
				continue;

			// UNDONE: IVP_Synapse_Friction is supposed to be opaque.  Is there a better way
			// to implement this?  Using the friction listener is much more work for the CPU
			// and considers sleeping objects.
			IVP_Synapse_Friction *pfriction = ivpObject->get_first_friction_synapse();
			while ( pfriction )
			{
				IVP_Contact_Point *contact = pfriction->get_contact_point();
				IVP_Synapse_Friction *pOpposite = GetOppositeSynapse( pfriction );
				IVP_Real_Object *pobj = pOpposite->get_object();
				CPhysicsObject *pScrape = (CPhysicsObject *)pobj->client_data;

				// friction callbacks for this object?
				if ( pScrape->GetCallbackFlags() & CALLBACK_GLOBAL_FRICTION )
				{
					float energy = IVP_Contact_Point_API::get_eliminated_energy( contact );
					if ( energy ) 
					{
						IVP_Contact_Point_API::reset_eliminated_energy( contact );
						// scrape with an estimate for the energy per unit mass
						// This assumes that the game is interested in some measure of vibration
						// for sound effects.  This also assumes that more massive objects require
						// more energy to vibrate.
						energy = energy * t * ivpObject->get_core()->get_inv_mass();

						if ( energy > 0.05f )
						{
							int hitSurface = physprops->RemapIVPMaterialIndex( pOpposite->get_material_index() );
							CPhysicsFrictionData data(pfriction);
							pEvent->Friction( pObject, ConvertEnergyToHL(energy), pObject->GetMaterialIndexInternal(), hitSurface, &data );
						}
					}
				}
				pfriction = pfriction->get_next();
			}
		}
	}