Commits

Alberto Torres committed 9117424

Added Sensor (forgot file last time), Controller, Actuator, changed all function names to follow PEP-8, lots of fixes and removed obsolete tests.

  • Participants
  • Parent commits 1dee1c5

Comments (0)

Files changed (21)

File CMakeLists.txt

 ######################################################################################
 
 set(PYGAMEKIT_SRC
+    actuator.pxi
     blendfile.pxi
+    controller.pxi
     engine.pxi
     sensor.pxi
     gamekit.pyx
     mathutils.pxd
     mathutils.pyx
     prerequisites.pxd
-    prerequisites.pxi
+    pywrap.pxd
+    pywrap.pxi
     scene.pxi
     transformstate.pxd
     variable.pxd
+    standalone.py
 )
 
 include(FindPythonInterp)
 #include(FindPythonLibs)
 
 if (OGREKIT_BUILD_ANDROID)
-set(PYTHON_INCLUDE_PATH /home/dithi/proyectos/python-for-android/python-modules/python-lib/include/python2.6)
-set(PYTHON_LIBRARIES -L/home/dithi/proyectos/python-for-android/python-modules/python-lib/lib -lpython2.6)
+    set(PYTHON_INCLUDE_PATH ${PYTHON_ANDROID_LIB}/include/python2.6)
+    set(PYTHON_LIBRARIES -L${PYTHON_ANDROID_LIB}/lib -lpython2.6)
 else()
     include(FindPythonLibs)
     if(PYTHON_LIBRARIES)
+        if(CMAKE_BUILD_TYPE MATCHES "Deb")
+            #if(PYTHON_DEBUG_LIBRARIES)
+                #todo: add #define Py_DEBUG
+#                 set(PYTHON_LIBRARIES -lpython2.7_d)
+#                 if(PYOGREKIT_AS_MODULES)
+#                     set(PY_SUFFIX _d)
+#                 endif()
+            #endif()
+        endif()
     else()
-        set(PYTHON_INCLUDE_PATH /home/julio/.wine/drive_c/Python27/include)
-        set(PYTHON_LIBRARIES -L/home/julio/.wine/drive_c/Python27/libs -lpython27)
+        set(PYTHON_INCLUDE_PATH $ENV{HOME}/.wine/drive_c/Python27/include)
+        set(PYTHON_LIBRARIES -L$ENV{HOME}/.wine/drive_c/Python27/libs -lpython27)
     endif()
 endif()
 
 find_program(CYTHON_EXECUTABLE cython)
 
-# # Figure out installation path
-# execute_process(COMMAND
-#   ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
-#   OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
-
 # Cython integratin into gdb
 if (CMAKE_BUILD_TYPE MATCHES "Deb")
     set(CYTHON_DEBUG --gdb)
 
 add_custom_command(
   DEPENDS ${PYGAMEKIT_SRC}
-  OUTPUT gamekit.cpp mathutils.cpp
+  OUTPUT gamekit.cpp mathutils.cpp standalone.py.h
   COMMAND ${CYTHON_EXECUTABLE} ${CYTHON_DEBUG} --cplus --fast-fail -o gamekit.cpp
          "${CMAKE_CURRENT_SOURCE_DIR}/gamekit.pyx"
   COMMAND ${CYTHON_EXECUTABLE} ${CYTHON_DEBUG} --cplus --fast-fail -o mathutils.cpp
          "${CMAKE_CURRENT_SOURCE_DIR}/mathutils.pyx"
-
+  COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/standalone.py" .
+  COMMAND xxd -i standalone.py standalone.py.h
 )
-list(APPEND ADDITIONAL_MAKE_CLEAN_FILES gamekit.cpp)
+list(APPEND ADDITIONAL_MAKE_CLEAN_FILES gamekit.cpp mathutils.cpp standalone.py.h)
 
 set(PYGAMEKIT_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})
 
 #add_dependencies(gamekit.cpp gamekit.pyx)
 
 # Compile the extension
-if (PYOGREKIT_AS_MODULE)
-add_library(cython_gamekit MODULE gamekit.cpp mathutils.cpp ${PYGAMEKIT_SRC})
+if (PYGAMEKIT_AS_MODULES)
+    add_library(cython_gamekit MODULE gamekit.cpp ${PYGAMEKIT_SRC})
+    # Build mathutils as a separate module instead
+    add_library(cython_mathutils MODULE mathutils.cpp ${PYGAMEKIT_SRC})
+    set_target_properties(cython_mathutils PROPERTIES
+    PREFIX ""
+    OUTPUT_NAME "mathutils${PY_SUFFIX}"
+    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    COMPILE_FLAGS "-fno-permissive" )
+    target_link_libraries(cython_mathutils ${OGREKIT_LIB} ${PYTHON_LIBRARIES})
 else()
-add_executable(cython_gamekit gamekit.cpp mathutils.cpp ${PYGAMEKIT_SRC} standalone.cpp)
+    add_executable(cython_gamekit gamekit.cpp mathutils.cpp ${PYGAMEKIT_SRC} standalone.cpp)
 endif()
 
 set_target_properties(cython_gamekit PROPERTIES
   PREFIX ""
-  OUTPUT_NAME "gamekit"
+  OUTPUT_NAME "gamekit${PY_SUFFIX}"
   LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
   COMPILE_FLAGS "-fno-permissive" )
 target_link_libraries(cython_gamekit ${OGREKIT_LIB} ${PYTHON_LIBRARIES})
 if (OGREKIT_BUILD_ANDROID)
   target_link_libraries(cython_gamekit log)
 endif()
-include_directories(${PYTHON_INCLUDE_PATH} ${OGREKIT_INCLUDE} .)
+include_directories(${PYTHON_INCLUDE_PATH} ${OGREKIT_INCLUDE} ${CMAKE_CURRENT_BINARY_DIR} .)
 
-

File actuator.pxi

+
+from gameobject cimport *
+
+cdef class Actuator:
+    cdef gkGameObject *gkob
+    cdef readonly GameObject owner
+    cdef int activations
+    cdef public Sensor sensor
+    
+    # to be overriden
+    def __call__(self, status, fade):
+        pass 
+        #status will be either True or False
+        #may use TickSensor() and TemporalTickSensor() internally to do things
+    
+    def __init__(self, fadein=0, fadeout=0):
+        pass
+    
+    def signal(self, sensor):
+        self.sensor = sensor if isinstance(Sensor, sensor) else None
+        if sensor:
+            if not self.activations:
+                self.activate()
+            self.activations+=1
+        else:
+            self.activations-=1
+            if not self.activations:
+                self.deactivate()
+            
+    def activate(self):
+        pass
+    
+    def deactivate(self):
+        pass
+    
+    cdef void _init(self):
+        pass
+    
+    
+cdef class Movement:
+    pass
+    

File controller.pxi

+
+class Controller:
+    
+    def __init__(self, function):
+        self.f = function
+        self.calling_sensor = None
+        self.sensors = []
+        self.actuators = []
+        
+    def __call__(self, *args):
+        ret = self.f(*self.sensors)
+        for a in self.actuators:
+            a(ret)
+        
+    def link(self, *nodes):
+        for n in nodes:
+            if isinstance(n, Sensor):
+                n.link(self)
+            else:
+                self.actuators.append(n)
+    
+        
+            
 
-import sys, imp
+import sys, imp, traceback
 
 cdef extern from "gkLogger.h":
     #cdef cppclass gkLogger:
         
 cdef extern from "gkEngine.h":
     
-    cdef cppclass Listener:
+    cdef cppclass pyEngineListener "gkEngine::Listener":
         pass
+        
     cdef cppclass gkEngine:
                     
         gkEngine(gkUserDefs *defs)
         void registerActiveScene(gkScene* scene)
         void unregisterActiveScene(gkScene* scene)
 
-        void addListener(Listener* listener)
-        void removeListener(Listener* listener)
+        void addListener(pyEngineListener* listener)
+        void removeListener(pyEngineListener* listener)
 
     gkEngine* gkEngine_getSingleton "&(gkEngine::getSingleton)"()
 
         std_string& getText()
 
 cdef extern from "gkTextManager.h":
-    void* gkTextManager_getByName "gkTextManager::getSingleton().getByName"(const_std_string& name)
-    bool gkTextManager_exists "gkTextManager::getSingleton().exists"(const_std_string& name)
+    void* gkTextManager_getByName "gkTextManager::getSingleton().getByName"(const_std_string&)
+    bool gkTextManager_exists "gkTextManager::getSingleton().exists"(const_std_string&)
+
+#----------------------------------------------------------------------------
+# Globals
+cdef list tick_callback = []
+cdef bool initialized = False
+cdef Engine currentEngine
     
-cdef Sensor tick_callback = Sensor()
-cdef bool initialized = False
-
 cdef class Engine:
     cdef gkEngine *eng
+    cdef gkClock *timer
     #cdef gkHUDManager* mgr
-    
-    tickSensor = TickSensor()
 
     def __init__(self, bfile=None, cfgfile=None, initialize=True, seek=0):
         
-        global initialized
+        global initialized, currentEngine
         
         if initialize:
             if cfgfile:
             #self.mgr = new gkHUDManager()
 
             if bfile:
-                self.loadBlend(bfile, seek)
+                self.load_blend(bfile, seek)
                 
             self.eng.initializeStepLoop()
+            
+            self.timer = new gkClock()
+            self.timer.reset()
+            
             initialized = True
+            currentEngine = self
             
     def __del__(self):
         self.eng.requestExit()
 
-    def getActiveScene(self):
-        return Scene().P(self.eng.getActiveScene())
-        
-    def initializeStepLoop(self): self.eng.initializeStepLoop()
+    property active_scene:
+        def __get__(self):
+            return Scene().P(self.eng.getActiveScene())
 
-    def stepOneFrame(self):
+    def _step_one_frame(self):
         try:
-            evaluate_input_callbacks()
-            evaluate_collision_callbacks()
-            evaluate_tick_callbacks()
+            evaluate_all_callbacks()
         except SystemExit:
             return False
+        except:
+            traceback.print_exc()
         return self.eng.stepOneFrame()
     
-    def loadBlend(self, bfile, seek=0):
+    def load_blend(self, bfile, seek=0):
         cdef gkScene* scn
         
         b = BlendFile()
             scn.createInstance()
             
     def run(self):
-        while self.stepOneFrame():
+        while self._step_one_frame():
             pass
 
 cdef class TickSensor(Sensor):
     
     def __init__(self):
-        self.callback_list = tick_callback
+        self.init_sensor(tick_callback)
         
     def __nonzero__(self):
         return True
             
 cdef void evaluate_tick_callbacks() except *:
-    cdef TickSensor t = tick_callback.next_non_empty()
-    while t!=None:
-        t.execute()
-        t = t.next_non_empty()
+    for s in tick_callback[:]:
+        (<TickSensor>s).execute()
+    
+cdef public void evaluate_all_callbacks() except *:
+    
+    #TODO: make tick time configurable (now fixed at 60)
+    
+    #For the moment will not compensate slow graphics with substeps,
+    #so use tickSensor.elapsedTime to make your interactions proportional.
+    
+    #TODO: now I'm blocking to limir overall FPS, to fix collisions
+    cdef int us=currentEngine.timer.getMicroseconds()
+    if us<16666:
+        usleep(16666-us)
+    if 1:#currentEngine.timer.getMicroseconds()>16666: #60 FPS
+        currentEngine.timer.reset()
+        evaluate_input_callbacks()
+        evaluate_collision_callbacks()
+        evaluate_timer_callbacks()
+        evaluate_tick_callbacks()
         
-def _evaluate_all_callbacks():
-    evaluate_input_callbacks()
-    evaluate_collision_callbacks()
-    evaluate_tick_callbacks()
-        
-def getEngine():
-    e = Engine(None, None, False)
-    e.eng = gkEngine_getSingleton()
-    return e
+def get_engine():
+    if currentEngine: return currentEngine
     
-def getActiveScene():
+def get_active_scene():
     cdef gkEngine* e = gkEngine_getSingleton()
     return Scene().P(e.getActiveScene())
 
 sys.meta_path.append(TextBlockImporter())
 del TextBlockImporter
 
-def hasTextBlock(name):
+def has_text_block(name):
     if initialized: return gkTextManager_exists(to_stdstring(name))
     
-def getTextBlock(name):
+def get_text_block(name):
     if initialized:
         return str((<gkTextFile*>gkTextManager_getByName(to_stdstring(name))).getText().c_str())
     
+def reload_init():
+    pass
+
+def destroy_all_links():
+    for c in tick_callback, key_callbacks, mouse_move_callbacks, mousebutton_callbacks, timer_callbacks:
+        for s in c:
+            (<Sensor>s).unlink_all()
+        del(c[:])
 
-include "prerequisites.pxi"
+include "pywrap.pxi"
 include "sensor.pxi"
+include "controller.pxi"
+include "actuator.pxi"
 include "gameobject.pxi"
 include "scene.pxi"
 include "engine.pxi"
 include "blendfile.pxi"
 include "input.pxi"
-import sys
+#include "overlay.pxi"
 
 #gkLogger_enable(to_stdstring("AppCppDemo.log"), GK_CPP_VERBOSE_LOG)
 

File gameobject.pxd

 from scene cimport *
 cimport gkmath
 
+#cdef class GameObject(pywrap):
+    #pass
+
 cdef extern from "OgreSceneNode.h":
     cdef cppclass Ogre_SceneNode "Ogre::SceneNode":
         const_std_string& getName()
         gkVariable* createVariable(const_std_string& name, bool debug)
         gkVariable* getVariable(const_std_string& name)
         bool        hasVariable(const_std_string& name)
+        void        removeVariable(const_std_string& name)
         void        clearVariables()
     
         gkGameObject* clone(const_std_string& name)
         #bool _markDbvt(bool v)
         
         #btCollisionShape* _createShape()
+

File gameobject.pxi

 
 OBJECT_TYPES = 'NULL', 'CAMERA', 'LIGHT', 'ENTITY', 'OBJECT', 'SKELETON', 'PARTICLES'
 
-cdef CollisionSensor collision_callbacks = CollisionSensor()
+cdef list collision_callbacks = []
 
 cdef gkGameObject* cloneRecursiveImpl(gkGameObject* ob, int lifespan=0, bool instance=True):
     
         else:
             raise TypeError("Unsupported type for property "+str(item)+" (type is "+str(type(value))+")")
         
+    def __delitem__(self,item):
+        (<gkGameObject*>self._p).removeVariable(to_stdstring(item))
+        
     def __contains__(self,item):
         cdef gkGameObject* o = <gkGameObject*>self._p
         
         return GameObject().P((<gkGameObject*>self._p).clone(s.assign(name)))
         #TODO: use scn.cloneObject() instead
         
-    def cloneRecursive(self, lifespan=0):
+    def clone_recursive(self, lifespan=0):
         cdef gkGameObject *ob = cloneRecursiveImpl(<gkGameObject*>self._p, lifespan)
         if ob:
             return GameObject().P(ob)
 
             (<gkGameObject*>self._p).setPosition(v)
 
-    property positionWorld:
+    property position_world:
         
         def __get__(self):
             cdef gkVector3 v = (<gkGameObject*>self._p).getWorldPosition()
             r.z = gkRadian(rot[2])
             (<gkGameObject*>self._p).setOrientation(r)
             
-    property rotationWorld:
+    property rotation_world:
 
         def __get__(self):
             cdef gkEuler r = (<gkGameObject*>self._p).getWorldRotation()
             v.z = pos[2]
             (<gkGameObject*>self._p).setScale(v)
 
-    property linearVelocity:
+    property linear_velocity:
         
         def __get__(self):
             cdef gkVector3 v = (<gkGameObject*>self._p).getLinearVelocity()
             v.z = pos[2]
             (<gkGameObject*>self._p).setLinearVelocity(v,TRANSFORM_PARENT)
             
-    property angularVelocity:
+    property angular_velocity:
         
         def __get__(self):
             cdef gkVector3 v = (<gkGameObject*>self._p).getAngularVelocity()
 
         (<gkGameObject*>self._p).translate(v, TRANSFORM_PARENT)
 
-    def translateLocal(self, pos):
+    def translate_local(self, pos):
         cdef gkVector3 v = gkVector3()
         v.x = pos[0]
         v.y = pos[1]
 
         (<gkGameObject*>self._p).translate(v, TRANSFORM_LOCAL)
 
-    def translateWorld(self, pos):
+    def translate_world(self, pos):
         cdef gkVector3 v = gkVector3()
         v.x = pos[0]
         v.y = pos[1]
         r.z = gkRadian(drot[2])
         (<gkGameObject*>self._p).rotate(r, TRANSFORM_PARENT)
 
-    def rotateLocal(self, drot):
+    def rotate_local(self, drot):
         cdef gkEuler r = gkEuler()
         r.x = gkRadian(drot[0])
         r.y = gkRadian(drot[1])
         r.z = gkRadian(drot[2])
         (<gkGameObject*>self._p).rotate(r, TRANSFORM_LOCAL)
 
-    def rotateWorld(self, drot):
+    def rotate_world(self, drot):
         cdef gkEuler r = gkEuler()
         r.x = gkRadian(drot[0])
         r.y = gkRadian(drot[1])
         
     # Rigid body stuff
     
-    def applyTorque(self, t):
+    def apply_torque(self, t):
         cdef gkVector3 v = gkVector3()
         v.x = t[0]
         v.y = t[1]
 
         (<gkGameObject*>self._p).applyTorque(v, TRANSFORM_PARENT)
 
-    def applyTorqueLocal(self, t):
+    def apply_torque_local(self, t):
         cdef gkVector3 v = gkVector3()
         v.x = t[0]
         v.y = t[1]
 
         (<gkGameObject*>self._p).applyTorque(v, TRANSFORM_LOCAL)
 
-    def applyTorqueWorld(self, t):
+    def apply_torque_world(self, t):
         cdef gkVector3 v = gkVector3()
         v.x = t[0]
         v.y = t[1]
 
         (<gkGameObject*>self._p).applyTorque(v, TRANSFORM_WORLD)
 
-    def applyForce(self, f):
+    def apply_force(self, f):
         cdef gkVector3 v = gkVector3()
         v.x = f[0]
         v.y = f[1]
 
         (<gkGameObject*>self._p).applyForce(v, TRANSFORM_PARENT)
 
-    def applyForceLocal(self, f):
+    def apply_force_local(self, f):
         cdef gkVector3 v = gkVector3()
         v.x = f[0]
         v.y = f[1]
 
         (<gkGameObject*>self._p).applyForce(v, TRANSFORM_LOCAL)
 
-    def applyForceWorld(self, f):
+    def apply_force_world(self, f):
         cdef gkVector3 v = gkVector3()
         v.x = f[0]
         v.y = f[1]
 
         (<gkGameObject*>self._p).applyForce(v, TRANSFORM_WORLD)
 
-    def suspendDynamics(self):
+    def suspend_dynamics(self):
         (<gkGameObject*>self._p).getPhysicsController().suspend(True)
 
-    def resumeDynamics(self):
+    def resume_dynamics(self):
         (<gkGameObject*>self._p).getPhysicsController().suspend(False)
 
     @property
     def animations(self):
         return AnimationList().P(self._p)
         
-    def collisionSensor(self, prop):
-        return CollisionSensor()._init(<gkGameObject*>self._p, prop)
+    def add_sensor(self, Sensor sensor):
+        old = getattr(sensor,'owner',None)
+        if old is not None and old!=self:
+            sensor = sensor.copy()
+        sensor.owner = self
+        sensor._init()
+        return sensor
+        
+    def add_actuator(self, actuator):
+        old = getattr(actuator,'owner',None)
+        if old is not None and old!=self:
+            actuator = actuator.copy()
+        actuator.owner = self
+        actuator._init()
+        return actuator
+        
+    def __richcmp__(self, other, op):
+        if isinstance(other, GameObject):
+            if op==2:   # __eq__
+                return (<GameObject>other)._p == <void *>self._p
+            elif op==3: # __ne__
+                return (<GameObject>other)._p != <void *>self._p
+        return False
         
 cdef class Entity(GameObject):
     
 
 cdef class Skeleton(GameObject):
     
-    def something(self, a, b, c, d):
-        cdef gkBone *b1 = (<gkSkeleton*>self._p).getBone(to_stdstring('tizq'))
-        cdef gkBone *b2 = (<gkSkeleton*>self._p).getBone(to_stdstring('tder'))
-        cdef gkTransformState t1 = gkTransformState()
-        cdef gkTransformState t2 = gkTransformState()
-        cdef gkVector3 v1, v2
-        t1.loc.x = a
-        t1.loc.z = b
-        t2.loc.x = c
-        t2.loc.z = d
-        t1.loc.y=0.5
-        t2.loc.y=0.5
-        b1.applyChannelTransform(t1, 1)
-        b2.applyChannelTransform(t2, 1)
-        v1 = b1.getPose().loc
-        v2 = b2.getPose().loc
-        #print v1.x, v1.y, v1.z, "   ", v2.x, v2.y, v2.z
+    #def something(self, a, b, c, d):
+        #cdef gkBone *b1 = (<gkSkeleton*>self._p).getBone(to_stdstring('tizq'))
+        #cdef gkBone *b2 = (<gkSkeleton*>self._p).getBone(to_stdstring('tder'))
+        #cdef gkTransformState t1 = gkTransformState()
+        #cdef gkTransformState t2 = gkTransformState()
+        #cdef gkVector3 v1, v2
+        #t1.loc.x = a
+        #t1.loc.z = b
+        #t2.loc.x = c
+        #t2.loc.z = d
+        #t1.loc.y=0.5
+        #t2.loc.y=0.5
+        #b1.applyChannelTransform(t1, 1)
+        #b2.applyChannelTransform(t2, 1)
+        #v1 = b1.getPose().loc
+        #v2 = b2.getPose().loc
+        ##print v1.x, v1.y, v1.z, "   ", v2.x, v2.y, v2.z
 
-    def getBone(self, name):
+    property bones:
+        def __get__(self):
+            return BoneList().P(self._p)
+
+cdef class Bone(pywrap):
+    
+    pass
+
+cdef class BoneList(pywrap):
+    
+    def __getitem__(self, name):
         cdef gkBone *b = (<gkSkeleton*>self._p).getBone(to_stdstring(name))
         if b:
             return Bone().P(b)
         return None
 
-cdef class Bone(pywrap):
-    
-    pass
-
 cdef class GameObjectList(pywrap):
         
     def __list__(self):
         return (<gkScene*>self._p).getObjects().size()
     
 cdef class GameObjectArray(pywrap):
+    
+    cdef list list
         
     def __list__(self):
         cdef gkGameObjectArrayIterator it = (<gkGameObjectArray*>self._p).iterator()
         
+        if self.list: return self.list
+        
         ret = []
         
         while (it.hasMoreElements()):
         
     def __iter__(self):
         return self.__list__().__iter__() #TODO: can be made more efficient
+        
+    def __getitem__(self, item):
+        return self.__list__().__getitem__(item)
 
     def __len__(self):
         return (<gkGameObjectArray*>self._p).size()
         return (<gkGameObject*>self._p).getAnimations().size()
         
 
-cdef class CollisionSensor(Sensor):
+cdef class Collision(Sensor):
     
     cdef gkPhysicsController *pc
     cdef std_string *prop
     cdef gkGameObjectArray *objlist
     
-    cdef _init(self, gkGameObject *ob, prop):
-        self.prop = new std_string(prop) #is this freed?
-        self.pc = ob.getPhysicsController()
+    def __init__(self, _prop):
+        self.prop = new std_string(_prop) #is this freed?
+        self.init_sensor([])
+        
+    cdef void _init(self):
+        self.pc = (<gkGameObject*>self.owner._p).getPhysicsController()
         self.objlist = new gkGameObjectArray()
         self.callback_list = collision_callbacks
-        return self
-    
+        
     def __nonzero__(self):
-        return self.pc.sensorCollides(self.prop[0], to_stdstring(""), False, False, self.objlist)
+        if self.pc!=NULL:
+            return self.pc.sensorCollides(self.prop[0], to_stdstring(""), False, False, self.objlist)
             
-    property hitObjects:
+    property hit_objects:
         
         def __get__(self):
             return GameObjectArray().P(self.objlist)
             
     def __str__(self):
-        if self: return "<CollisionSensor Active>"
-        else: return "<CollisionSensor>"
+        if self: return "<Collision Active>"
+        else: return "<Collision>"
         
 cdef void evaluate_collision_callbacks() except *:
     cdef bool s
-    cdef CollisionSensor e
+    cdef Collision e
     
-    e = collision_callbacks.next_non_empty()
-    while e != None:
+    for e in collision_callbacks:
         if e.pc:
             s = e.pc.sensorCollides(e.prop[0], to_stdstring(""), False, False, <gkGameObjectArray*>e.objlist)
-            if not e.prevstate and s:
+            if e.prevstate!=s:
                 e.execute()
             e.prevstate = s
             
-        e = e.next_non_empty()
-        #TODO: where the callbacks are removed and freed?
         
 class WrongInputError(BaseException):
     pass
 
-cdef Sensor key_callbacks = Sensor()
-cdef Sensor mouse_move_callbacks = Sensor()
-cdef Sensor mousebutton_callbacks = Sensor()
+cdef list key_callbacks = []
+cdef list mouse_move_callbacks = []
+cdef list mousebutton_callbacks = []
 cdef int previous_keys[256] #TODO: use KC_MAX
 cdef int previous_mb[3]
 cdef gkVector2 prev_mouse
             raise WrongInputError('Key name not in '+str(KEYS))
         self.key = getKeyboard().keys + keycode
         self.keynum = keycode
-        self.callback_list = key_callbacks
+        self.init_sensor(key_callbacks)
         
     def __nonzero__(self):
         return self.key[0] == 1
 
     def __str__(self):
-        if self.but[0] == 1: return "<Key Pressed>"
-        else: return "<Key>"
+        if self.key[0] == 1: return "<Key %s Pressed>" % KEYS[self.keynum]
+        else: return "<Key %s>" % KEYS[self.keynum]
 
 cdef class MouseButton(Sensor):
     
         
         self.but = &getMouse().buttons[button-1]
         self.butnum = button
-        self.callback_list = mousebutton_callbacks
+        self.init_sensor(mousebutton_callbacks)
     
     def __nonzero__(self):
         return self.but[0] == 1
     def __init__(self, butnum=-1):
         self.mouse = getMouse()
         self.butnum = butnum
-        self.callback_list = mouse_move_callbacks
+        self.init_sensor(mouse_move_callbacks)
         
     @property
     def position(self):
         cdef gkVector2 v = self.mouse.getRelative()
         return v.x, v.y
         
-    def isButtonDown(self, button):
-        return self.mouse.isButtonDown(button)
+    #def isButtonDown(self, button):
+        #return self.mouse.isButtonDown(button)
         
-    def mouseMoved(self):
-        return self.mouse.mouseMoved()
+    #def mouseMoved(self):
+        #return self.mouse.mouseMoved()
            
 cdef class Accelerometer:
     cdef Vector v
     cdef Sensor e
     cdef int *mousebuttons = getMouse().buttons, b
     
-    e = key_callbacks.next_non_empty()
-    while e != None:
+    for e in key_callbacks:
         k = (<Key>e).keynum
         if keys[k] != previous_keys[k]:
             e.execute()
-        e = e.next_non_empty()
 
     memcpy(previous_keys, keys, sizeof(int)*256) #TODO: use KC_MAX
     
         rel.y = pos.y - prev_mouse.y
         
     if not rel.isZeroLength():
-        e = mouse_move_callbacks.next_non_empty()
-        print 1
-        while e != None:
-            print 2
+        for e in mouse_move_callbacks:
             b = (<MouseMotion>e).butnum
             if 1 or b==-1 or mousebuttons[b]:
-                print 3
                 e.execute()
-            e = e.next_non_empty()
     
     prev_mouse = pos
     
-    e = mousebutton_callbacks.next_non_empty()
-    while e != None:
+    for e in mousebutton_callbacks:
         k = (<MouseButton>e).butnum
         if mousebuttons[k] != previous_mb[k]:
             e.execute()
-        e = e.next_non_empty()
         
     memcpy(previous_mb, mousebuttons, sizeof(int)*3)

File mathutils.pxd

 
 cdef class Vector:
     cdef gkmath.Vector3 *v
+
+    cdef Vector assign(self, gkmath.Vector3 v)
         
 cdef class Quaternion:
     cdef gkmath.Quaternion *q

File mathutils.pyx

 
 cdef class Vector:
     
-    def __init__(Vector self, ini=None, ini2=None, ini3=None):
+    def __init__(self, ini=None, ini2=None, ini3=None):
         if ini3!=None:
             self.v = new gkmath.Vector3(ini,ini2,ini3)
         elif isinstance(ini, Vector):
 
     def __dealloc__(self):
         del self.v
+        
+    cdef Vector assign(self, gkmath.Vector3 v):
+        self.v.assign(v)
+        return self
             
     property x:
-        def __get__(Vector self): return self.v.x
-        def __set__(Vector self, v): self.v.x=v 
+        def __get__(self): return self.v.x
+        def __set__(self, v): self.v.x=v 
 
     property y:
-        def __get__(Vector self): return self.v.y
-        def __set__(Vector self, v): self.v.y=v 
+        def __get__(self): return self.v.y
+        def __set__(self, v): self.v.y=v 
 
     property z:
-        def __get__(Vector self): return self.v.z
-        def __set__(Vector self, v): self.v.z=v
+        def __get__(self): return self.v.z
+        def __set__(self, v): self.v.z=v
         
     property length:
-        def __get__(Vector self): return self.v.length()
+        def __get__(self):
+            return self.v.length()
+            
+        def __set__(self, Real v):
+            self.v.normalise()
+            self.v.imul(v)
         
-    def normalize(Vector self):
+    def normalize(self):
         return self.v.normalise()
 
-    def normalized(Vector self):
+    def normalized(self):
         cdef Vector v = Vector(self)
         v.v.normalise()
         return v
         
-    def copy(Vector self):
+    def copy(self):
         return Vector(self)
 
     def __len__(self): return 3
 
-    def __getitem__(Vector self, i):
+    def __getitem__(self, i):
         return self.v.getitem(i)
         
-    def __add__(Vector self, v):
+    def __add__(self, v):
         cdef Vector ret = Vector(self)
         if isinstance(v, Vector):
             (ret.v).iadd((<Vector>v).v[0])
             (ret.v).iadd(gkmath.Vector3(v[0],v[1],v[2]))
         return ret
 
-    def __sub__(Vector self, v):
+    def __sub__(self, v):
         cdef Vector ret = Vector(self)
         if isinstance(v, Vector):
             (ret.v).isub((<Vector>v).v[0])
             (ret.v).isub(gkmath.Vector3(v[0],v[1],v[2]))
         return ret
 
-    def __iadd__(Vector self, v):
+    def __iadd__(self, v):
         if isinstance(v, Vector):
             (self.v).iadd((<Vector>v).v[0])
         else:
             (self.v).iadd(gkmath.Vector3(v[0],v[1],v[2]))
         return self
 
-    def __isub__(Vector self, v):
+    def __isub__(self, v):
         cdef Vector ret = Vector(self)
         if isinstance(v, Vector):
             (self.v).isub((<Vector>v).v[0])
             (self.v).isub(gkmath.Vector3(v[0],v[1],v[2]))
         return self
         
-    def __mul__(Vector self, v):
+    def __mul__(self, v):
         cdef Vector ret = Vector(self)
         if isinstance(v, Vector):
             (ret.v).imul((<Vector>v).v[0])
             (ret.v).imul(<Real>v)
         return ret
 
-    def __div__(Vector self, v):
+    def __div__(self, v):
         cdef Vector ret = Vector(self)
         if isinstance(v, Vector):
             (ret.v).idiv((<Vector>v).v[0])
         else:
             (ret.v).idiv(<Real>v)
         return ret
-    __truediv__ = __div__
 
-    def __imul__(Vector self, v):
+    def __truediv__(self, v):
+        cdef Vector ret = Vector(self)
+        if isinstance(v, Vector):
+            (ret.v).idiv((<Vector>v).v[0])
+        elif getattr(v, '__getitem__', False):
+            (ret.v).idiv(gkmath.Vector3(v[0],v[1],v[2]))
+        else:
+            (ret.v).idiv(<Real>v)
+        return ret
+
+    def __imul__(self, v):
         if isinstance(v, Vector):
             (self.v).imul((<Vector>v).v[0])
         elif getattr(v, '__getitem__', False):
             (self.v).imul(<Real>v)
         return self
 
-    def __idiv__(Vector self, v):
+    def __idiv__(self, v):
         if isinstance(v, Vector):
             (self.v).idiv((<Vector>v).v[0])
         elif getattr(v, '__getitem__', False):
             (self.v).idiv(<Real>v)
         return self
 
-    def __pos__(Vector self): return self
+    def __itruediv__(self, v):
+        if isinstance(v, Vector):
+            (self.v).idiv((<Vector>v).v[0])
+        elif getattr(v, '__getitem__', False):
+            (self.v).idiv(gkmath.Vector3(v[0],v[1],v[2]))
+        else:
+            (self.v).idiv(<Real>v)
+        return self
+
+    def __pos__(self): return self
     
-    def __neg__(Vector self):
+    def __neg__(self):
         return self*-1 #optimize this?
 
-    def __getitem__(Vector self, i):
+    def __getitem__(self, i):
         if isinstance(i,slice):
             return [self.v.x,self.v.y,self.v.z][i]
         elif i<3:
         else:
             raise IndexError
 
-    def __setitem__(Vector self, i, v):
+    def __setitem__(self, i, v):
         if not isinstance(i,slice) and i<3:
             self.v.ptr()[i%3]=v
         else:
             raise IndexError
         
-    def __repr__(Vector self):
+    def __repr__(self):
         return "Vector(%f, %f, %f)"%(self.v.x,self.v.y,self.v.z)
         
-    def angleBetween(Vector self, other):
+    def angle_between(self, other):
         return self.v.angleBetween(Vector(other).v[0]).valueRadians()
         
-    def getRotationTo(Vector self, other, fallbackAxis=None):
+    def get_rotation_to(self, other, fallbackAxis=None):
         cdef Quaternion q = Quaternion()
         if fallbackAxis!=None:
             q.q.assign(self.v.getRotationTo(Vector(other).v[0], Vector(fallbackAxis).v[0]))
             q.q.assign(self.v.getRotationTo(Vector(other).v[0]))
         return q
         
-    def lerp(Vector self, other, factor):
+    def lerp(self, other, factor):
         factor = max(0.0,min(factor,1.0))
         invf = 1.0-factor
         return Vector(self.x*invf + other[0]*factor,
                       self.y*invf + other[1]*factor,
                       self.z*invf + other[2]*factor)
         
-    #cdef assignv(Vector self, gkmath.Vector3 v):
+    #cdef assignv(self, gkmath.Vector3 v):
     #    memcpy((<gkmath.Vector3*>self.v).ptr(),v.ptr(),sizeof(Real)*3)
         
 cdef class Quaternion:
         else:
             self.q = new gkmath.Quaternion()
             
+    def __dealloc__(self):
+        del self.q
+            
     property w:
         def __get__(self): return self.q.w
         def __set__(self, v): self.q.w=v 
     def lerp(self, Quaternion other, factor):
         cdef Quaternion q = Quaternion()
         q.q.assign(gkmath.quat_nlerp(factor, self.q[0], other.q[0], False))
+        return q
         
     def slerp(self, Quaternion other, factor):
         cdef Quaternion q = Quaternion()
         q.q.assign(gkmath.quat_Slerp(factor, self.q[0], other.q[0], False))
+        return q
         

File prerequisites.pxd

 
 cdef extern from "stdlib.h":
      void *memcpy(void *dst, void *src, long n)
+
+cdef extern from "time.h":
+    int usleep(int usec)
      
 ctypedef float Real
 
         GK_PLATFORM_LINUX
         GK_PLATFORM_ANDROID
         GK_PLATFORM
+
+    cppclass gkClock "Ogre::Timer":
+        void reset()
+        unsigned long int getMilliseconds()
+        unsigned long int getMicroseconds()
         
 cdef extern from "string": 
     cppclass std_string "std::string": 
 cdef extern from *:
     cppclass gkColor:
         gkColor(float r, float g, float b, float a)
+        gkColor(float r, float g, float b)
+        
+    ctypedef gkColor Ogre_ColourValue "Ogre::ColourValue"
         
     cdef cppclass gkHashedString:
         gkHashedString(const_std_string&)
         const_std_string &str()
         
     ctypedef gkHashedString const_gkHashedString "const gkHashedString"
+    
+    cdef cppclass Ogre_StringVector "Ogre::StringVector":
+        void push_back(std_string)
+#TODO: with cython>0.15.1, replace the lines above with the lines below
+#from libcpp.vector cimport vector
+#ctypedef vector[std_string] Ogre_StringVector "Ogre::StringVector"
 
 ctypedef  int OgreRenderSystem

File prerequisites.pxi

-
-cimport gkmath
-
-cdef class pywrap:
-    cdef void *_p
-    
-    def __cmp__(self, other):
-        return self._getP() - other._getP()
-        
-    cdef P(self, void *p):
-        self._p = p
-        return self
-        
-    cpdef _getP(self):
-        return <long>self._p
-
-# TODO: instead of SomeObject().P(pointer) try SomeObject.__new__(SomeObject).P(pointer)
-#       and comapre the speedup (as it won't have to call __init__, etc)
-#       (maybe change it here to be SomeObject.P(pointer)?)
-
-cdef extern from *:
-    void* getself "__pyx_v_self"
+
+#cdef class pywrap:
+    #cdef void *_p
+
+    #cdef Object P(self, void *p):
+        #pass
+        
+    #cpdef int _getP(self):
+        #pass
+    
+cdef extern from *:
+    void* getself "__pyx_v_self"
+
+    
+
+from pywrap cimport *
+cimport gkmath
+
+cdef class pywrap:
+    cdef void *_p
+    
+    def __cmp__(self, other):
+        return self._getP() - other._getP()
+        
+    cdef P(self, void *p):
+        self._p = p
+        return self
+        
+    cpdef _getP(self):
+        return <long>self._p
+
+# TODO: instead of SomeObject().P(pointer) try SomeObject.__new__(SomeObject).P(pointer)
+#       and comapre the speedup (as it won't have to call __init__, etc)
+#       (maybe change it here to be SomeObject.P(pointer)?)
+
         void setHorizonColor(gkColor&)
         void setAmbientColor(gkColor&)
         void setGravity(gkmath.Vector3)
+        gkmath.Vector3& getGravity()
         
         void createInstance()
         
                                     const_std_string& sceneName, const_std_string& cameraName = "", const_std_string& group="")
     cdef gkScene* copyObjects "gkSceneManager::getSingleton().copyObjects"(gkScene* fromScene, gkScene* toScene, int exceptObjectTypes)
     
+#cdef extern from "OgreTerrain.h":
     
+    #cdef cppclass Ogre_Terrain "Ogre::Terrain":
+        #Ogre_Terrain(Ogre_SceneManager *sm)
+        #void addLayer (Real worldSize, Ogre_StringVector*)
+        #void dirty()
+        #void update()
+        #void updateGeometry()
+    #cppclass Terrain_ImportData:
+        #pass
+    #cppclass Terrain_LayerInstanceList:
+        #pass
+    
+    #cdef enum Alignment:
+        #ALIGN_X_Z = 0, 
+        #ALIGN_X_Y = 1, 
+        #ALIGN_Y_Z = 2
+
+    #cdef cppclass Ogre_TerrainGroup "Ogre::TerrainGroup":
+        #Ogre_TerrainGroup(Ogre_SceneManager *sm, Alignment, unsigned short terrainSize, Real terrainWorldSize)
+        #void defineTerrain (long x, long y)
+        #void defineTerrain (long x, long y, float constantHeight)
+        #void defineTerrain (long x, long y, Terrain_ImportData *importData)
+        ##void defineTerrain (long x, long y, Image *img, Terrain_LayerInstanceList *layers=0)
+        #void defineTerrain (long x, long y, float *pFloat, Terrain_LayerInstanceList *layers=0)
+        #void defineTerrain (long x, long y, std_string &filename)
 
 cdef class Scene(pywrap):
 
     cdef public TickSensor tickSensor
+    #cdef Ogre_Terrain *terrain
     
     def __init__(self):
         self.tickSensor = TickSensor()
+
+    #def setTerrain(self):
+        #self.terrain = new Ogre_Terrain((<gkScene *>self._p).getManager())
+        #cdef Ogre_StringVector tlist
+        #tlist.push_back(to_stdstring("terrain.png"))
+        #self.terrain.addLayer(300.0, &tlist)
+        #self.terrain.dirty()
+        #self.terrain.update()
+        #self.terrain.updateGeometry()
+        
+    property gravity:
+        def __get__(self):
+            return Vector().assign((<gkScene *>self._p).getGravity())
+        def __set__(self,g):
+            (<gkScene *>self._p).setGravity(Vector(g).v[0])
     
-    def setGravity(self,g):
-        (<gkScene *>self._p).setGravity(Vector(g).v[0])
-    
-    def getMainCamera(self):
+    property main_camera:
+        def __get__(self):
+            
+            return Camera().P((<gkScene *>self._p).getMainCamera())
         
-        return Camera().P((<gkScene *>self._p).getMainCamera())
-    
-    #TODO: make sure you pass one of the correct types
-    
-    def setMainCamera(self, GameObject cam):
-        (<gkScene *>self._p).setMainCamera(<gkCamera *>cam._p)
+        #TODO: make sure you pass one of the correct types
         
-    def addObject(self, GameObject ob):
+        def __set__(self, GameObject cam):
+            (<gkScene *>self._p).setMainCamera(<gkCamera *>cam._p)
+        
+    def add_object(self, GameObject ob):
         (<gkScene *>self._p).addObject(<gkGameObject *>ob._p)
         
-    def removeObject(self, GameObject ob):
+    def remove_object(self, GameObject ob):
         (<gkScene *>self._p).removeObject(<gkGameObject *>ob._p)
         
-    def destroyObject(self, GameObject ob):
+    def destroy_object(self, GameObject ob):
         (<gkScene *>self._p).destroyObject(<gkGameObject *>ob._p)
         
-    def cloneObject(self, GameObject ob, lifeSpan=0, instantiate=False):
+    def clone_object(self, GameObject ob, lifeSpan=0, instantiate=False):
         cdef gkGameObject* o = <gkGameObject *>ob._p
         o = (<gkScene *>self._p).cloneObject(o, lifeSpan, instantiate)
         return GameObject().P(o)
     def objects(self):
         return GameObjectList().P(self._p)
         
-    def suspendDynamics(Scene self):
+    def suspend_dynamics(Scene self):
         (<gkScene *>self._p).setUpdateFlags((<gkScene *>self._p).getUpdateFlags()&~UF_PHYSICS)
         
-    def resumeDynamics(Scene self):
+    def resume_dynamics(Scene self):
         (<gkScene *>self._p).setUpdateFlags((<gkScene *>self._p).getUpdateFlags()|UF_PHYSICS)
-        
-    def setShadowTextureSelfShadow(self,b):
-        (<gkScene *>self._p).getManager().setShadowTextureSelfShadow(b)
-        
-    def setShadowCasterRenderBackFaces(self,b):
-        (<gkScene *>self._p).getManager().setShadowCasterRenderBackFaces(b)
-        
-    def setShadowTextureSize(self,size):
-        (<gkScene *>self._p).getManager().setShadowTextureSize(size)
-        
-    def setShadowFarDistance(self,d):
-        (<gkScene *>self._p).getManager().setShadowFarDistance(d)
+    
+    property shadow:
+        def __get__(self):
+            return _ShadowProperties()
         
     
     #def __init__(self, sceneName = "", cameraName = "", group = ""):
         #self.objects.scn = scn
         #self.objects.hashmap = scn.getObjects()
         
+cdef class _ShadowProperties(pywrap):
+    @property
+    def texture_self_shadow(self,b):
+        (<gkScene *>self._p).getManager().setShadowTextureSelfShadow(b)
+        
+    @property
+    def cast_backfaces(self,b):
+        (<gkScene *>self._p).getManager().setShadowCasterRenderBackFaces(b)
+    
+    @property
+    def texture_size(self,size):
+        (<gkScene *>self._p).getManager().setShadowTextureSize(size)
+    
+    @property
+    def far_distance(self,d):
+        (<gkScene *>self._p).getManager().setShadowFarDistance(d)
+
+from libcpp cimport bool
+from prerequisites cimport *
+
+'''How to make a sensor:
+
+cdef list my_callback_list = []
+
+cdef class mySensor(Sensor):
+
+    def __init__(self):
+        self.init_sensor(my_callback_list)   # it adds itself when needed
+        # add any other initialization
+    
+    def __nonzero__(self):
+        return state_of_this_sensor
+
+def evaluate_my_callbacks():
+    cdef mySensor sensor
+    for sensor in reversed(my_callback_list):  # remember sensors may remove themselves while iterating!!
+        if sensor_state_just_changed:
+            sensor.execute()
+            
+'''
+
+
+cdef class Sensor:
+    
+    # This list contains all sensors that may be called.
+    # The sensor will add itself when you link it.
+    # Sensor subtypes must assign this.
+    cdef list callback_list
+    #cdef bool _im_in_list
+    
+    # This list contains callables (functions, controllers, actuators) to be called
+    # when the sensor state changes.
+    # TODO: change it to be a property so it adds itself (see link())
+    cdef public list links
+    
+    cdef readonly GameObject owner
+    
+    cdef bool prevstate #used for some callbacks
+    # TODO: do we need justActivated/justDeactivated/justChanged?
+    
+    # Time
+    cdef readonly unsigned long int last_time
+
+    cdef gkClock *timer
+    
+    def __init__(self):
+        self.init_sensor([])
+        
+    def link(self, *actuators):
+        if self not in self.callback_list:
+            self.callback_list.append(self)
+        self.links.extend(actuators)
+        for a in actuators:
+            if isinstance(a,Controller):
+                a.sensors.append(self)
+    
+    def unlink(self, *actuators):
+        self.links = list(set(self.links)-set(actuators))
+        for a in actuators:
+            if isinstance(a,Controller) and self in a.sensors:
+                a.remove(self)
+    
+    def unlink_all(self):
+        for c in self.links:
+            if isinstance(c,Controller):
+                c.sensors.remove(self)
+        del(self.links[:])
+        
+    def with_links_of(self, sensor):
+        self.link(sensor.links)
+        return self
+
+    cdef void _init(self):
+        pass
+    
+    cdef void _set_owner(self, GameObject obj):
+        self.owner = obj
+    
+    # Implementation methods
+    cdef void init_sensor(self, callback_list):
+        self.timer = new gkClock()
+        self.callback_list = callback_list
+        self.links = []
+
+    cdef void execute(self) except *:
+        if self.links:
+            self.reset_time()
+            for f in self.links:
+                f(self)
+        else:
+            self.callback_list.pop(self.callback_list.index(self))
+            
+    cdef void reset_time(self):
+        self.last_time = self.timer.getMilliseconds()
+            
+    property elapsed_time:
+        def __get__(self):
+            return self.timer.getMilliseconds() - self.last_time
+
+    def __str__(self):
+        if len(self.links):
+            return "<Sensor connected to: %s>" % str(self[:])
+        return "<Sensor>"
+
+    def __repr__(self):
+        if len(self.links):
+            return "<Sensor connected to: %s>" % str(self[:])
+        return "<Sensor>"
+    
+
+
+cdef list timer_callbacks = []
+
+cdef class Timer(Sensor):
+    
+    cdef long endtime, relatime, pausedrem
+    cdef bool triggered  # also True when stopped, so it's not evaluated
+    
+    def __init__(self, time=0):
+        self.init_sensor(timer_callbacks)
+        if time:
+            self.start(time)
+        
+    def start(self, time):
+        self.reset_time()
+        self.relatime = time
+        self.endtime = time+self.last_time
+        self.triggered = False
+        self.pausedrem = 0
+        
+    def restart(self):
+        self.start(self.relatime)
+        
+    def stop(self):
+        self.endtime = 0
+        self.triggered = True
+        self.pausedrem = 0
+        
+    def pause(self):
+        if not self.triggered:
+            self.pausedrem = self.endtime-self.timer.getMilliseconds()
+        self.endtime=0
+        self.triggered = True
+        
+    def resume(self):
+        if self.pausedrem:
+            self.endtime = self.timer.getMilliseconds() + self.pausedrem
+        self.triggered = False
+        self.pausedrem = 0
+        
+    property elapsed:
+        def __get__(self):
+            return self.relatime-(self.endtime-self.timer.getMilliseconds())
+            
+    property remaining:
+        def __get__(self):
+            return self.endtime-self.timer.getMilliseconds()
+            
+    property running:
+        def __get__(self):
+            return not self.triggered and self.endtime!=0
+        
+    property paused:
+        def __get__(self):
+            return self.pausedrem!=0
+        
+    property stopped:
+        def __get__(self):
+            return not self.triggered and self.endtime!=0 and self.pausedrem!=0
+        
+    def __nonzero__(self):
+        return self.endtime!=0 and (self.triggered or self.endtime<=self.timer.getMilliseconds())
+    
+    def __str__(self):
+        return "<Timer triggered at %i, current %i>" % (self.endtime,self.timer.getMilliseconds())
+
+    def __repr__(self):
+        return "<Timer triggered at %i, current %i>" % (self.endtime,self.timer.getMilliseconds())
+
+
+cdef void evaluate_timer_callbacks():
+    cdef Timer t
+    for t in reversed(timer_callbacks):
+        if not t.triggered and t.endtime<=t.timer.getMilliseconds():
+            t.triggered = True
+            t.execute()
+    
+    
+    
+    
+    
+        

File standalone.cpp

 PyMODINIT_FUNC PyInit_mathutils(void);
 #endif
 
+#include "standalone.py.h"
+
 int main(int argc, char *argv[]){
   
   Py_SetProgramName(argv[0]);
   #endif
   PySys_SetArgvEx(argc, argv, 0);
 
-  PyRun_SimpleString(
-    "import gamekit, sys\n"
-    "print sys.argv\n"
-    "bname = sys.argv[0]\n"
-    "ext = bname.split('.')[-1].lower()\n"
-    "if ext in ('exe', 'bin', 'bin32', 'bin64'):\n"
-    "    bname = bname[:-len(ext)-1]\n"
-    "bname += '.blend'\n"
-    "p = ''\n"
-    "cfgfile = None\n"
-    "for a in sys.argv[1:]:\n"
-    "    if p:\n"
-    "        if p=='-c':\n"
-    "            cfgfile = a\n"
-    "        elif p=='--pythonpath':\n"
-    "            sys.path.append(a)\n"
-    "        elif p=='--':\n"
-    "            bname = a\n"
-    "        else:\n"
-    "            print('Unrecognized option %s'%p)\n"
-    "        p = ''\n"
-    "    else:\n"
-    "        if a.startswith('-'):\n"
-    "            p = a\n"
-    "        else:\n"
-    "            bname = a\n"
-    "e = gamekit.Engine(bname,cfgfile)\n"
-    "try:\n"
-    "    import init\n"
-    "except ImportError:\n"
-    "    print('Error: Can\\'t import init.py')\n"
-    "e.run()\n"
-  );
+  standalone_py[standalone_py_len-1] = '\0'; // Replace last \n with \0
+  PyRun_SimpleString((char *)standalone_py);
 
   Py_Finalize();
   return 0;

File standalone.py

+import gamekit, sys
+print sys.argv
+bname = sys.argv[0]
+ext = bname.split('.')[-1].lower()
+if ext in ('exe', 'bin', 'bin32', 'bin64'):
+    bname = bname[:-len(ext)-1]
+bname += '.blend'
+p = ''
+cfgfile = None
+for a in sys.argv[1:]:
+    if p:
+        if p=='-c':
+            cfgfile = a
+        elif p=='--pythonpath':
+            sys.path.append(a)
+        elif p=='--':
+            bname = a
+        else:
+            print('Unrecognized option %s'%p)
+        p = ''
+    else:
+        if a.startswith('-'):
+            p = a
+        else:
+            bname = a
+e = gamekit.Engine(bname,cfgfile)
+try:
+    import init
+    def r():
+         import time, traceback
+         gamekit.destroy_all_links()
+         loaded = False
+         tb_printed = False
+         while not loaded:
+             try:
+                 reload(init)
+                 loaded = True
+             except:
+                 if not tb_printed: traceback.print_exc()
+                 tb_printed = True
+                 time.sleep(1)
+         print('Reloaded successfully.')
+    gamekit.reload_init=r
+except ImportError:
+    print("Error: Can't import init.py")
+e.run()

File test.blend

Binary file removed.

File test.py

-#!/usr/bin/python
-
-# for this test, set the appropiate paths below
-import sys
-sys.path.append('../../linux64/Samples/pygamekit')
-sys.path.append('../linux/pygamekit')
-import gamekit, random
-
-eng = gamekit.Engine('test.blend')
-
-k = gamekit.Keyboard()
-m = gamekit.Mouse()
-
-scn = eng.getActiveScene()
-cam = scn.objects['Camera']
-
-ob = scn.objects['Physics']
-
-sk = scn.objects['Armature']
-
-cube = scn.objects['Cube.003']
-
-
-print sk.animations
-sk.animations['Foo'].play()
-#sk.animations['Action'].play()
-
-for p in scn.objects:
-    
-    print p.type, p.name
-    for c in p.children:
-        print "  ",c.type, c.name  #peta! :(
-
-x,y = cam.rotation[0], cam.rotation[2]
-
-pos = [0,0,3]
-
-SPEED=0.5
-
-i = 0
-
-mon=0
-
-espacio = gamekit.Key('SPACE')
-arriba =  gamekit.Key('UPARROW')
-abajo  =  gamekit.Key('DOWNARROW')
-izquierda= gamekit.Key('LEFTARROW')
-derecha  = gamekit.Key('RIGHTARROW')
-
-boton = gamekit.MouseButton(1)
-
-lastpos = None
-
-def cosa(datos):
-    cube.applyForce((0,0,1000))
-    
-def mueve(datos):
-    global x,y
-    if boton:
-        x+=datos.rel[0]/-1000.0
-        y+=datos.rel[1]/-1000.0
-        
-        y=max(0,min(y,3.1415926))
-        #cam.position = 10,x,y
-        cam.rotation=(y,0,x)
-
-arriba.onPress = cosa
-m.onMouseMove = mueve
-
-boton.onPress = cosa
-coll = cube.collisionSensor('floor')
-coll.onCollision = cosa
-
-def tick(data):
-    
-    if arriba:
-        cam.translateLocal((0,0,-SPEED))
-        
-    if abajo:
-        cam.translateLocal((0,0,SPEED))
-        
-    if izquierda:
-        cam.translateLocal((-SPEED,0,0))
-        
-    if derecha:
-        cam.translateLocal((SPEED,0,0))
-        
-    if espacio:
-        ob2 = ob.cloneRecursive()
-        ob2.position = random.random()*20,random.random()*20,random.random()*200
-        list(ob2.children)[0].animations['Action'].play()
-        mon+=1
-        print mon
-    #print m.isButtonDown(0), m.isButtonDown(1), m.isButtonDown(2)
-    #print
-    
-eng.onTick = tick
-eng.run()