Information regarding the Physics System in the BGE

Hi everyone.
I’ve been taking a look into the BGE source code as I hoped to add some Python exposure to various collision settings. I’d even hoped to determine if it were easy to add velocity information to the collision sensors.

Anyway, during this process I’ve come to understand (I hope!) the physics settings a little further, and thought that I’d share them here. (Please correct me if I’ve misunderstood what I’ve read in the source!)

Physics type:

class KX_ClientObjectInfo:    SENSOR: SCA SENSOR (Creates new object for the sensor)
    OBSENSOR: OBJECT IN SENSOR MODE (USES OBJECT MESH FOR COLLISIONS) 
    OBSENSOR: OBJECT IN SENSOR MODE WITH ACTOR ENABLED(USES OBJECT MESH FOR COLLISIONS) 

The sensor mode for a KX_GameObject will use the object’s mesh for any sensors that involve collisions. This means that there are no more meshes for any number of sensors which is good if you want to have multiple sensors looking for different things. Therefore if you want to have multiple collision that look for a special property, simply create a collision object, set it to SENSOR physics mode, add all the logic and parent it to the parent object.

I’m also writing a semi-psuedo Python description of what the GameLoop does regarding physics, which might be of interest.


class KX_ClientObjectInfo:	SENSOR: SCA SENSOR (Creates new object for the sensor)
	OBSENSOR: OBJECT IN SENSOR MODE (USES OBJECT MESH FOR COLLISIONS) 
	OBACTORSENSOR: OBJECT IN SENSOR MODE WITH ACTOR ENABLED(USES OBJECT MESH FOR COLLISIONS) 


class TouchEventManager:
	def __init__(self):
		# Assume no other managers are instantiated (I believe)
		CcdPhysicsEnvironment.addTouchCallback(PHY_OBJECT_RESPONSE, self.newCollisionResponse, self)
		CcdPhysicsEnvironment.addTouchCallback(PHY_SENSOR_RESPONSE, self.newCollisionResponse, self)
		CcdPhysicsEnvironment.addTouchCallback(PHY_BROADPH_RESPONSE, self.newBroadphaseResponse, self)
	
	def NewHandleCollision(self, obj_a, obj_b, coll_data):
		self.m_newCollisions.append((obj_a.controller, obj_b.controller))
	
	@staticmethod
	def newCollisionResponse(client_data, obj_a, obj_b, coll_data):
		# Doesn't get coll_data atm
		with client_data as self:
			self.NewHandleCollision(obj_a, obj_b, coll_data)
	
	def newBroadPhaseResponse(self, client_data, obj_a, obj_b, coll_data):
		# Only for physics controllers of near and radar
		info_a = obj_a.controller.game_object_info
		info_b = obj_b.controller.game_object_info 
		
		obj_type = info_a.obj_type
		
		if obj_type == None:
			return True
			
		# If a sensor obj created from GameLogic sensor
		if obj_type == KX_ClientObjectInfo.SENSOR:
			# Sensors (e.g collisions sensor) only have one sensor (on parent obj)!
			if len(obj_info.m_sensors) == 1:
				sensor = obj_info.m_sensors[0]
				return sensor.BroadPhaseFilterCollision(obj_a, obj_b)
		
		# If a gameobject set as sensor mode
		elif obj_type in (KX_ClientObjectInfo.OBSENSOR, KX_ClientObjectInfo.OBACTORSENSOR):
			for sensor in obj_info.m_sensors:
				if isinstance(sensor, SCA_ISensor.ST_TOUCH):
					if sensor.BroadPhaseSensorFilterCollision(obj_a, obj_b):
						return True
		
			# Sensor KX_GameObject's can't collide so False if executed
			return False
			
		# Otherwise yes, physical objects must be included in broadphase
		return True
	
	def RegisterSensor(self, sensor):
		self.sensors.append(sensor)
		sensor.RegisterSumo(self)
		
	def UnegisterSensor(self, sensor):
		self.sensors.remove(sensor)
		sensor.UnregisterSumo(self)
	
	def NextFrame(self):
		if m_sensors:
			
			# Update all the sensors
			for collision in m_newCollisions:
				obj_a, obj_b = collision
				obj_a.update_sensors(obj_b)
				obj_b.update_sensors(obj_a)
			
			# Activate all the sensors (ensure all collisions handled)
			for sensor in self.m_sensors:
				sensor.activate(self.m_logicmgr)


class TouchSensor:
	def RegisterSumo(self):
		# If first controller
		if CcdPhysicsEnvironment.registerCollisionCallback(self):
			# If a sensor object
			if self.is_sensor():
				CcdPhysicsEnvironment.addSensor()
		
	def UnregisterSumo(self):
		# Does the same as register sumo in reverse
		pass
		
	def BroadPhaseSensorFilterCollision(self, obj_a, obj_b):
		assert obj_a = self.m_physCtrl
		
		# Same as obj_a when cast
		my_obj = self.parent
		my_parent = my_obj.parent
		
		# Get infos
		my_info = my_obj.controller.game_object_info
		other_info = other_obj.controller.game_object_info
		
		# Also get other object
		other_obj = other_info.m_gameobject
		
		# If we don't have the other as a GameObject
		if not other_obj or \
			# If is our parent
			other_obj is my_parent or \
			# If only actor - actor interaction
			(isinstance(my_obj, KX_ClientObjectInfo.OBACTORSENSOR) and not isinstance(other_obj, KX_ClientObjectInfo.ACTOR):
			return False
		
		# Set the found value as true if no property name
		found = not bool(m_touchedpropname)
		
		if not found:
			if m_bFindMaterial:
				# DO material stuff and apply to found bool
				pass
				
		return found
	
class CCDPhysicsController.h
	def Register(self):
		self.m_registerCount += 1
		# If first controller
		return self.m_registerCount == 1
	
	def Unregister(self):
		# Does the same as register in reverse
		pass
	
class CcdPhysicsEnvironment.cpp
	def addTouchCallback(self, cls, callback, user):
		'''	Adds callback for key CLS,
		Associates user with key'''
		self.m_triggerCallbacks[cls] = callback
		# Only one touch manager! 
		self.m_triggerCallbacksUserPtrs[cls] = user


	def addCcdPhysicsController(self, ctrl):
		Add the physics object to our environment. self will allow the environmnent to affect 
	
	def addSensor(self, ctrl):
		#Called on sensor object activation
		self.enableCCDPhysicsController(ctrl)
		
	def enableCcdPhysicsController(self, ctrl):
		Enables object for collisions
		
	def requestCollisionCallback(self, ctrl):
		# ctrl.users = the register count of ctrl
		if not ctrl.Register:
			return False
		
		#Register controller for triggering 
		self.m_triggerControllers.append(ctrl)
		return True
	
	def CallbackTriggers(self):
		if not self.m_triggerCallbacks[PHY_OBJECT_RESPONSE]:
			return		
		
		obj_a, obj_b = manifold
		
		if set((obj_a.controller, obj_b.controller)).intersection(self.m_triggerControllers):
			self.m_triggerCallbacks[PHY_OBJECT_RESPONSE].__call__(self.m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE], obj_a.controller, obj_b.controller, 0)
			
		
		
    

Work in progress…