BGE: Support for collision group/mask from the api + activated on EndObject.
A Python API for the collision group / mask has been added: ``` KX_GameObject.collisionGroup KX_GameObject.collisionMask ``` The maximum number of collision groups and masked has been increased from eight to sixteen. This means that the max value of collisionGroup/Mask is (2 ** 16) - 1 EndObject will now activate objects that were sleeping and colliding with the removed object. This means that, unlike now, if a rigid body starts sleeping on top of another object, when the latter is removed the rigid body will activate and fall, rather than float midair as before. Collision groups that do not intersect used to collide on the first frame. Now this has been fixed so that they collide appropriately. Thanks to agoose77 for his help. Reviewers: scorpion81, hg1, agoose77, sergof Reviewed By: agoose77, sergof Subscribers: sergof, moguri Projects: #game_physics, #game_engine Differential Revision: https://developer.blender.org/D1243
This commit is contained in:
		@@ -161,6 +161,18 @@ base class --- :class:`SCA_IObject`
 | 
			
		||||
 | 
			
		||||
      :type: :class:`KX_GameObject` or None
 | 
			
		||||
 | 
			
		||||
   .. attribute:: collisionGroup
 | 
			
		||||
 | 
			
		||||
      The object's collision group.
 | 
			
		||||
 | 
			
		||||
      :type: bitfield
 | 
			
		||||
 | 
			
		||||
   .. attribute:: collisionMask
 | 
			
		||||
 | 
			
		||||
      The object's collision mask.
 | 
			
		||||
 | 
			
		||||
      :type: bitfield
 | 
			
		||||
 | 
			
		||||
   .. attribute:: collisionCallbacks
 | 
			
		||||
 | 
			
		||||
      A list of functions to be called when a collision occurs.
 | 
			
		||||
 
 | 
			
		||||
@@ -1048,7 +1048,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
 | 
			
		||||
	ob->jump_speed = 10.0f;
 | 
			
		||||
	ob->fall_speed = 55.0f;
 | 
			
		||||
	ob->col_group = 0x01;
 | 
			
		||||
	ob->col_mask = 0xff;
 | 
			
		||||
	ob->col_mask = 0xffff;
 | 
			
		||||
 | 
			
		||||
	/* NT fluid sim defaults */
 | 
			
		||||
	ob->fluidsimSettings = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -530,7 +530,7 @@ enum {
 | 
			
		||||
#define OB_MAX_STATES       30
 | 
			
		||||
 | 
			
		||||
/* collision masks */
 | 
			
		||||
#define OB_MAX_COL_MASKS    8
 | 
			
		||||
#define OB_MAX_COL_MASKS    16
 | 
			
		||||
 | 
			
		||||
/* ob->gameflag */
 | 
			
		||||
enum {
 | 
			
		||||
 
 | 
			
		||||
@@ -1347,8 +1347,8 @@ static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
 | 
			
		||||
	if (!(blenderobject->gameflag & OB_COLLISION)) {
 | 
			
		||||
		// Respond to all collisions so that Near sensors work on No Collision
 | 
			
		||||
		// objects.
 | 
			
		||||
		gameobj->SetUserCollisionGroup(0xff);
 | 
			
		||||
		gameobj->SetUserCollisionMask(0xff);
 | 
			
		||||
		gameobj->SetUserCollisionGroup(0xffff);
 | 
			
		||||
		gameobj->SetUserCollisionMask(0xffff);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@
 | 
			
		||||
#include "KX_MeshProxy.h"
 | 
			
		||||
#include "KX_PolyProxy.h"
 | 
			
		||||
#include <stdio.h> // printf
 | 
			
		||||
#include <climits> // USHRT_MAX
 | 
			
		||||
#include "SG_Controller.h"
 | 
			
		||||
#include "PHY_IGraphicController.h"
 | 
			
		||||
#include "SG_Node.h"
 | 
			
		||||
@@ -561,13 +562,26 @@ void KX_GameObject::ActivateGraphicController(bool recurse)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KX_GameObject::SetUserCollisionGroup(short group)
 | 
			
		||||
void KX_GameObject::SetUserCollisionGroup(unsigned short group)
 | 
			
		||||
{
 | 
			
		||||
	m_userCollisionGroup = group;
 | 
			
		||||
	if (m_pPhysicsController)
 | 
			
		||||
		m_pPhysicsController->RefreshCollisions();
 | 
			
		||||
}
 | 
			
		||||
void KX_GameObject::SetUserCollisionMask(short mask)
 | 
			
		||||
void KX_GameObject::SetUserCollisionMask(unsigned short mask)
 | 
			
		||||
{
 | 
			
		||||
	m_userCollisionMask = mask;
 | 
			
		||||
	if (m_pPhysicsController)
 | 
			
		||||
		m_pPhysicsController->RefreshCollisions();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned short KX_GameObject::GetUserCollisionGroup()
 | 
			
		||||
{
 | 
			
		||||
	return m_userCollisionGroup;
 | 
			
		||||
}
 | 
			
		||||
unsigned short KX_GameObject::GetUserCollisionMask()
 | 
			
		||||
{
 | 
			
		||||
	return m_userCollisionMask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool KX_GameObject::CheckCollision(KX_GameObject* other)
 | 
			
		||||
@@ -2003,6 +2017,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("scaling",	KX_GameObject, pyattr_get_worldScaling,	pyattr_set_localScaling),
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset),
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("collisionCallbacks",		KX_GameObject, pyattr_get_collisionCallbacks,	pyattr_set_collisionCallbacks),
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("collisionGroup",			KX_GameObject, pyattr_get_collisionGroup, pyattr_set_collisionGroup),
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("collisionMask",				KX_GameObject, pyattr_get_collisionMask, pyattr_set_collisionMask),
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("state",		KX_GameObject, pyattr_get_state,	pyattr_set_state),
 | 
			
		||||
	KX_PYATTRIBUTE_RO_FUNCTION("meshes",	KX_GameObject, pyattr_get_meshes),
 | 
			
		||||
	KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation),
 | 
			
		||||
@@ -2349,6 +2365,56 @@ int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIB
 | 
			
		||||
	return PY_SET_ATTR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PyObject *KX_GameObject::pyattr_get_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 | 
			
		||||
{
 | 
			
		||||
	KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
 | 
			
		||||
	return PyLong_FromLong(self->GetUserCollisionGroup());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
 | 
			
		||||
{
 | 
			
		||||
	KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
 | 
			
		||||
	int val = PyLong_AsLong(value);
 | 
			
		||||
 | 
			
		||||
	if (val == -1 && PyErr_Occurred()) {
 | 
			
		||||
		PyErr_SetString(PyExc_TypeError, "gameOb.collisionGroup = int: KX_GameObject, expected an int bit field");
 | 
			
		||||
		return PY_SET_ATTR_FAIL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (val < 0 || val > USHRT_MAX) {
 | 
			
		||||
		PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
 | 
			
		||||
		return PY_SET_ATTR_FAIL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self->SetUserCollisionGroup(val);
 | 
			
		||||
	return PY_SET_ATTR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PyObject *KX_GameObject::pyattr_get_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 | 
			
		||||
{
 | 
			
		||||
	KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
 | 
			
		||||
	return PyLong_FromLong(self->GetUserCollisionMask());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
 | 
			
		||||
{
 | 
			
		||||
	KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
 | 
			
		||||
	int val = PyLong_AsLong(value);
 | 
			
		||||
 | 
			
		||||
	if (val == -1 && PyErr_Occurred()) {
 | 
			
		||||
		PyErr_SetString(PyExc_TypeError, "gameOb.collisionMask = int: KX_GameObject, expected an int bit field");
 | 
			
		||||
		return PY_SET_ATTR_FAIL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (val < 0 || val > USHRT_MAX) {
 | 
			
		||||
		PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
 | 
			
		||||
		return PY_SET_ATTR_FAIL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self->SetUserCollisionMask(val);
 | 
			
		||||
	return PY_SET_ATTR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PyObject* KX_GameObject::pyattr_get_scene(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 | 
			
		||||
{
 | 
			
		||||
	KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
 | 
			
		||||
 
 | 
			
		||||
@@ -100,8 +100,8 @@ protected:
 | 
			
		||||
	MT_Vector4							m_objectColor;
 | 
			
		||||
 | 
			
		||||
	// Bit fields for user control over physics collisions
 | 
			
		||||
	short								m_userCollisionGroup;
 | 
			
		||||
	short								m_userCollisionMask;
 | 
			
		||||
	unsigned short						m_userCollisionGroup;
 | 
			
		||||
	unsigned short						m_userCollisionMask;
 | 
			
		||||
 | 
			
		||||
	// visible = user setting
 | 
			
		||||
	// culled = while rendering, depending on camera
 | 
			
		||||
@@ -517,8 +517,10 @@ public:
 | 
			
		||||
	 */
 | 
			
		||||
	void ActivateGraphicController(bool recurse);
 | 
			
		||||
 | 
			
		||||
	void SetUserCollisionGroup(short filter);
 | 
			
		||||
	void SetUserCollisionMask(short mask);
 | 
			
		||||
	void SetUserCollisionGroup(unsigned short filter);
 | 
			
		||||
	void SetUserCollisionMask(unsigned short mask);
 | 
			
		||||
	unsigned short GetUserCollisionGroup();
 | 
			
		||||
	unsigned short GetUserCollisionMask();
 | 
			
		||||
	/**
 | 
			
		||||
	 * Extra broadphase check for user controllable collisions
 | 
			
		||||
	 */
 | 
			
		||||
@@ -1087,6 +1089,10 @@ public:
 | 
			
		||||
	static int			pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 | 
			
		||||
	static PyObject*	pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
 | 
			
		||||
	static int			pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 | 
			
		||||
	static PyObject*	pyattr_get_collisionGroup(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
 | 
			
		||||
	static int			pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 | 
			
		||||
	static PyObject*	pyattr_get_collisionMask(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
 | 
			
		||||
	static int			pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 | 
			
		||||
	static PyObject*	pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
 | 
			
		||||
	static int			pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 | 
			
		||||
	static PyObject*	pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,6 @@ extern bool gDisableDeactivation;
 | 
			
		||||
float gLinearSleepingTreshold;
 | 
			
		||||
float gAngularSleepingTreshold;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BlenderBulletCharacterController::BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight)
 | 
			
		||||
	: btKinematicCharacterController(ghost,shape,stepHeight,2),
 | 
			
		||||
		m_motionState(motionState),
 | 
			
		||||
@@ -118,6 +117,20 @@ const btVector3& BlenderBulletCharacterController::getWalkDirection()
 | 
			
		||||
	return m_walkDirection;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CleanPairCallback::processOverlap(btBroadphasePair &pair)
 | 
			
		||||
{
 | 
			
		||||
	if ((pair.m_pProxy0 == m_cleanProxy) || (pair.m_pProxy1 == m_cleanProxy)) {
 | 
			
		||||
		m_pairCache->cleanOverlappingPair(pair, m_dispatcher);
 | 
			
		||||
		CcdPhysicsController *ctrl0 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy0->m_clientObject)->getUserPointer());
 | 
			
		||||
		CcdPhysicsController *ctrl1 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy1->m_clientObject)->getUserPointer());
 | 
			
		||||
		if (ctrl0 && ctrl1) {
 | 
			
		||||
			ctrl0->GetRigidBody()->activate(true);
 | 
			
		||||
			ctrl1->GetRigidBody()->activate(true);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
 | 
			
		||||
:m_cci(ci)
 | 
			
		||||
{
 | 
			
		||||
@@ -1082,6 +1095,19 @@ void		CcdPhysicsController::ResolveCombinedVelocities(float linvelX,float linvel
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CcdPhysicsController::RefreshCollisions()
 | 
			
		||||
{
 | 
			
		||||
	btSoftRigidDynamicsWorld *dw = GetPhysicsEnvironment()->GetDynamicsWorld();
 | 
			
		||||
	btBroadphaseProxy *proxy = m_object->getBroadphaseHandle();
 | 
			
		||||
	btDispatcher *dispatcher = dw->getDispatcher();
 | 
			
		||||
	btOverlappingPairCache *pairCache = dw->getPairCache();
 | 
			
		||||
 | 
			
		||||
	CleanPairCallback cleanPairs(proxy, pairCache, dispatcher);
 | 
			
		||||
	pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher);
 | 
			
		||||
	// Forcibly recreate the physics object
 | 
			
		||||
	GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, m_cci.m_mass, m_cci.m_collisionFlags, m_cci.m_collisionFilterGroup, m_cci.m_collisionFilterMask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void	CcdPhysicsController::SuspendDynamics(bool ghost)
 | 
			
		||||
{
 | 
			
		||||
	btRigidBody *body = GetRigidBody();
 | 
			
		||||
 
 | 
			
		||||
@@ -447,6 +447,23 @@ public:
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CleanPairCallback : public btOverlapCallback
 | 
			
		||||
{
 | 
			
		||||
	btBroadphaseProxy *m_cleanProxy;
 | 
			
		||||
	btOverlappingPairCache *m_pairCache;
 | 
			
		||||
	btDispatcher *m_dispatcher;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	CleanPairCallback(btBroadphaseProxy *cleanProxy, btOverlappingPairCache *pairCache, btDispatcher *dispatcher)
 | 
			
		||||
		:m_cleanProxy(cleanProxy),
 | 
			
		||||
		m_pairCache(pairCache),
 | 
			
		||||
		m_dispatcher(dispatcher)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual bool processOverlap(btBroadphasePair &pair);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution.
 | 
			
		||||
class CcdPhysicsController : public PHY_IPhysicsController
 | 
			
		||||
{
 | 
			
		||||
@@ -598,7 +615,7 @@ protected:
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		virtual void		ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
 | 
			
		||||
 | 
			
		||||
		virtual void		RefreshCollisions();
 | 
			
		||||
		virtual void		SuspendDynamics(bool ghost);
 | 
			
		||||
		virtual void		RestoreDynamics();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -509,6 +509,13 @@ bool	CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr
 | 
			
		||||
	btRigidBody* body = ctrl->GetRigidBody();
 | 
			
		||||
	if (body)
 | 
			
		||||
	{
 | 
			
		||||
		btBroadphaseProxy *proxy = ctrl->GetCollisionObject()->getBroadphaseHandle();
 | 
			
		||||
		btDispatcher *dispatcher = m_dynamicsWorld->getDispatcher();
 | 
			
		||||
		btOverlappingPairCache *pairCache = m_dynamicsWorld->getPairCache();
 | 
			
		||||
 | 
			
		||||
		CleanPairCallback cleanPairs(proxy, pairCache, dispatcher);
 | 
			
		||||
		pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher);
 | 
			
		||||
 | 
			
		||||
		for (int i = ctrl->getNumCcdConstraintRefs() - 1; i >= 0; i--)
 | 
			
		||||
		{
 | 
			
		||||
			btTypedConstraint* con = ctrl->getCcdConstraintRef(i);
 | 
			
		||||
@@ -3525,12 +3532,14 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
 | 
			
		||||
	if (isbulletdyna)
 | 
			
		||||
		gameobj->SetRecordAnimation(true);
 | 
			
		||||
 | 
			
		||||
	physicscontroller->SetNewClientInfo(gameobj->getClientInfo());
 | 
			
		||||
 | 
			
		||||
	// don't add automatically sensor object, they are added when a collision sensor is registered
 | 
			
		||||
	if (!isbulletsensor && (blenderobject->lay & activeLayerBitInfo) != 0)
 | 
			
		||||
	{
 | 
			
		||||
		this->AddCcdPhysicsController( physicscontroller);
 | 
			
		||||
	}
 | 
			
		||||
	physicscontroller->SetNewClientInfo(gameobj->getClientInfo());
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		btRigidBody* rbody = physicscontroller->GetRigidBody();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -96,6 +96,7 @@ class PHY_IPhysicsController : public PHY_IController
 | 
			
		||||
		virtual void		SetAngularDamping(float damping)=0;
 | 
			
		||||
		virtual void		SetDamping(float linear, float angular)=0;
 | 
			
		||||
 | 
			
		||||
		virtual void		RefreshCollisions() = 0;
 | 
			
		||||
		virtual void		SuspendDynamics(bool ghost=false)=0;
 | 
			
		||||
		virtual void		RestoreDynamics()=0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user