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…