Source

pygamekit / collision.pxi



from gameobject cimport *
from collision cimport *
from gkmath cimport *

cdef list collision_callbacks = []



cdef class Collision(Sensor):
    
    cdef gkPhysicsController *pc
    cdef gkString *prop
    cdef gkGameObjectArray *objlist
    
    def __init__(self, prop):
        del self.prop
        self.prop = new gkString(prop)
        self.init_sensor([])
        
    def __dealloc__(self):
        del self.prop
        del self.objlist
        
    cdef void _set_owner(self, GameObject owner):
        self.owner = owner
        self.pc = (<gkGameObject*>self.owner._p).getPhysicsController()
        self.objlist = new gkGameObjectArray()
        self.callback_list = collision_callbacks
        
    def __nonzero__(self):
        return self._test()
        
    cdef bool _test(self):
        if self.pc!=NULL:
            return self.pc.sensorCollides(self.prop[0], gkString(""), False, False, self.objlist)
            
    property hit_objects:
        
        def __get__(self):
            return wrap(GameObjectArray, self.objlist)
            
    def __str__(self):
        if self._test(): return "<Collision Active>"
        else: return "<Collision>"
        
    def __repr__(self):
        if self._test(): return "<Collision Active>"
        else: return "<Collision>"
        
cdef void evaluate_collision_callbacks() except *:
    cdef bool s
    cdef Collision e
    
    for e in collision_callbacks:
        if e.pc:
            s = e._test()
            if e.prevstate!=s:
                e.execute()
            e.prevstate = s
            
cdef class Ray(Collision):
    
    cdef gkRayTest *test
    cdef gkVector3 *ray_to
    cdef gkGameObject *obj_to
    cdef public bool only_actors
    cdef public bool xray
    
    property hit_point:
        def __get__(self):
            return Vector().assign(self.test.getHitPoint())
    
    property hit_normal:
        def __get__(self):
            return Vector().assign(self.test.getHitNormal())
            
    property hit_object:
        def __get__(self):
            return to_GameObject(self.test.getObject())
    
    property hit_fraction:
        def __get__(self):
            return self.test.getHitFraction()

    def __cinit__(self):
        self.test = new gkRayTest()
        
    def __dealloc__(self):
        del self.test
        del self.ray_to
        
    def __init__(self, prop, ray_to = None):
        del self.prop
        self.prop = new gkString(prop)
        self.init_sensor([])
        if isinstance(ray_to, GameObject):
            self.obj_to = <gkGameObject*>(<GameObject>ray_to)._p
        elif ray_to is not None:
            self.ray_to = new gkVector3(ray_to[0], ray_to[1], ray_to[2])
        
    cdef bool _test(self):
        cdef gkVector3 ray_from, ray_to
        cdef gkGameObject *obj, *hit
        cdef bool result
        
        if self.owner is not None:
            obj = <gkGameObject*>self.owner._p
            ray_from = obj.getWorldPosition()
            
            if self.obj_to:
                ray_to = self.obj_to.getWorldPosition()
            else:
                if self.ray_to==NULL:
                    self.ray_to = new gkVector3(0,0,obj.getWorldScale().z)
                ray_to = obj.getWorldOrientation().mul(self.ray_to[0])
                ray_to.iadd(ray_from)
            
            if self.xray:
                result = self.test.collides(ray_from, ray_to,
                                            xrayFilter(obj, self.prop[0], gkString("")))
            else:
                result = self.test.collides(ray_from, ray_to, notMeFilter(obj))
                if result:
                    hit = gkPhysicsController_castObject(self.test.getCollisionObject())
                    if hit:
                        result = result and gkPhysicsController_sensorTest(
                            hit, self.prop[0], gkString(""), self.only_actors, False)
                            
            return result                            
        return False
        
        
cdef bool prop_filter(btCollisionObject *ob, void *data):
    return gkPhysicsController_castObject(ob).hasVariable((<gkString *>data)[0])
        
        
cdef class NegativeRay(Ray):
    
    cdef bool _test(self):
        return not Ray._test(self)