Commits

Anonymous committed 6be7cc0

World joint and body list properties return copies now instead of the
real lists.
Renamed World.body_list to World.bodies.
Renamed World.joint_list to World.joints.
Fixed RectShape inheritance.
Added documentation notes.

  • Participants
  • Parent commits 91cc95d
  • Branches physics

Comments (0)

Files changed (7)

     pygame.draw.polygon(surface,color,l)
 
 def render_world(world,surface,color):
-    for body in world.body_list:
+    for body in world.bodies:
         render_body(body,surface,color)
         
 
 	pygame.draw.lines(surface,color,False,l)
 
 def render_world(world,surface,body_color,joint_color):
-    for body in world.body_list:
+    for body in world.bodies:
         render_body(body,surface,body_color)
-    for joint in world.joint_list:
+    for joint in world.joints:
         render_joint(joint,surface,joint_color)        
 
 def init_world():
     pygame.draw.polygon(surface,color,l)
 
 def render_world(world,surface,color):
-    for body in world.body_list:
+    for body in world.bodies:
         render_body(body,surface,color)
         
 
 	pygame.draw.lines(surface,color,False,l)
 
 def render_world(world,surface,body_color,joint_color):
-    for body in world.body_list:
+    for body in world.bodies:
         render_body(body,surface,body_color)
-    for joint in world.joint_list:
+    for joint in world.joints:
         render_joint(joint,surface,joint_color)        
 
 def init_world():

include/pgShapeObject.h

  * @param shape
  * @param refbody
  */
-int PyShapeObject_UpdateAABB (PyShapeObject *shape, PyBodyObject *refbody);
+int PyShapeObject_UpdateAABB (PyBodyObject *refbody);
 
 /**
  * TODO
  * @param incbody
  * @param conactlist
  */
-int PyShapeObject_Collision (PyShapeObject *shape, PyBodyObject *refbody,
-    PyBodyObject *incbody, PyObject *contactlist);
+int PyShapeObject_Collision (PyBodyObject *refbody, PyBodyObject *incbody,
+    PyObject *contactlist);
 
 /**
  * Python C API export hook

src/pgShapeObject.c

 static void _RectShape_InitInternal (PyRectShapeObject *shape, double width,
     double height, double seta);
 static PyObject* _RectShapeNew(PyTypeObject *type, PyObject *args, PyObject *kwds);
-
+static PyObject* _RectShape_collision(PyRectShapeObject* shape, PyObject *args);
+static PyObject* _RectShape_updateAABB(PyRectShapeObject* shape, PyObject *args);
 
 static int _RectShapeCollision(PyBodyObject* selfBody,
     PyBodyObject* incidBody, PyObject* contactList);
 
+/* C API */
+static PyObject *PyShape_New (void);
+static PyObject *PyRectShape_New (double width, double height, double seta);
 
 /* collision test for RectShape */
 
+/**
+ * TODO
+ */
 #define MAX_CONTACTS 16
 
+/**
+ * TODO
+ */
 typedef struct _Candidate_
 {
     PyVector2 normal;
 }_Candidate;
 
 
+/**
+ * TODO
+ *
+ * @param box
+ * @param points
+ * @param candi
+ * @return
+ */
 static int _ClipTest(AABBBox* box, PyVector2* points, _Candidate* candi)
 {
     int  i, i1;
     return 1;
 }
 
+/**
+ * TODO
+ * 
+ * @param selfBody
+ * @param incBody
+ * @param selfBox
+ * @param incBox
+ * @param candi
+ * @param ans_ref
+ * @param ans_inc
+ */
 static void _SATFindCollisionProperty(PyBodyObject* selfBody,
     PyBodyObject* incBody, AABBBox* selfBox, AABBBox* incBox, _Candidate *candi,
     PyBodyObject** ans_ref, PyBodyObject** ans_inc)
     int size;
     double tmp1, tmp2;
     
+    /*
+     * TODO: describe the magic here.
+     */
     for(i = 0; i < candi->contact_size; ++i)
     {
         conts[0][i] = candi->contacts[i];
                 min_dep[k] = deps[i];
             }
     }
+
+    /*
+     * TODO describe the magic here
+     */
     
     //now select min depth one
     k = min_dep[0] < min_dep[1] ? 0 : 1;
         assert(0);
     }
     
+    /*
+     * TODO: describe the magic here.
+     */
+
     //translate to global coordinate
     PyVector2_Rotate(&(candi->normal), self[k]->fRotation);
     for(i = 0; i < candi->contact_size; ++i)
     *ans_inc = inc[k];
 }
 
+/**
+ * TODO
+ *
+ * @param selfBody
+ * @param incidBody
+ * @param contactList
+ */
 static int _RectShapeCollision(PyBodyObject* selfBody, PyBodyObject* incidBody, 
     PyObject* contactList)
 {
     p_in_inc[2] = PyBodyObject_GetRelativePos(incidBody, selfBody, &(self->topright));
     p_in_inc[3] = PyBodyObject_GetRelativePos(incidBody, selfBody, &(self->topleft));
     
-    
+
     box_self = AABB_Gen(self->bottomleft.real, self->topright.real,
         self->bottomleft.imag, self->topright.imag);
     box_inc = AABB_Gen(inc->bottomleft.real, inc->topright.real,
     
     _SATFindCollisionProperty(selfBody, incidBody, &box_self, &box_inc, &candi, &ans_ref, &ans_inc);
     
-    
     pAcc = PyObject_Malloc(sizeof(PyVector2));
     pAcc->real = pAcc->imag = 0;
     pSplitAcc = PyObject_Malloc(sizeof(PyVector2));
 
     return 1;
 }
-
-
 #undef MAX_CONTACTS
 
-
-/* C API */
-static PyObject *PyShape_New (void);
-static PyObject *PyRectShape_New (double width, double height, double seta);
-
+/**
+ Methods used by the Shape.
+ */
 static PyMethodDef _Shape_methods[] = {
     { "_collision",(PyCFunction)_Shape_collision,METH_VARARGS,"" },
     { "_update_aabb",(PyCFunction)_Shape_updateAABB,METH_VARARGS,"" },
     { NULL, NULL, 0, NULL }   /* Sentinel */
 };
 
-
 PyTypeObject PyShape_Type =
 {
     PyObject_HEAD_INIT(NULL)
     0                           /* tp_del */
 };
 
-//functions of pgShapeObject
-
+/**
+ * Creates a new PyShapeObject and initializes its internals.
+ */
 static PyObject* _ShapeNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
     /* In case we have arguments in the python code, parse them later
     return (PyObject*) shape;
 }
 
+/**
+ * Deallocates a PyShapeObject
+ */
 static void _ShapeObjectDestroy(PyShapeObject* shape)
 {
     shape->ob_type->tp_free((PyObject*)shape);
 }
 
+/* Shape methods */
+
+/**
+ * Shape._collision
+ */
 static PyObject* _Shape_collision(PyShapeObject* shape, PyObject *args)
 {
     PyErr_SetString (PyExc_NotImplementedError, "method not implemented");
     return NULL;
 }
 
+/**
+ * Shape._update_aabb
+ */
 static PyObject* _Shape_updateAABB(PyShapeObject* shape, PyObject *args)
 {
     PyErr_SetString (PyExc_NotImplementedError, "method not implemented");
     return NULL;
 }
 
+/**
+ Methods used by the RectShape.
+ */
+static PyMethodDef _RectShape_methods[] = {
+    { "_collision",(PyCFunction)_RectShape_collision,METH_VARARGS,"" },
+    { "_update_aabb",(PyCFunction)_RectShape_updateAABB,METH_VARARGS,"" },
+    { NULL, NULL, 0, NULL }   /* Sentinel */
+};
+
 PyTypeObject PyRectShape_Type =
 {
     PyObject_HEAD_INIT(NULL)
     0,                          /* tp_weaklistoffset */
     0,                          /* tp_iter */
     0,                          /* tp_iternext */
-    0,				/* tp_methods */
+    _RectShape_methods,         /* tp_methods */
     0,	                        /* tp_members */
-    0,				/* tp_getset */
-    0,				/* tp_base */
+    0,                          /* tp_getset */
+    0,				            /* tp_base */
     0,                          /* tp_dict */
     0,                          /* tp_descr_get */
     0,                          /* tp_descr_set */
     0                           /* tp_del */
 };
 
-//functions of pgRectShape
+/**
+ * Initializes the internals of the passed PyRectShapeObject.
+ *
+ * @param shape The PyRectShapeObject to initialize
+ * @param width The width of the rectangular shape area.
+ * @param height The height of the rectangular shape area.
+ * @param seta The initial rotation angle of the rectangular area.
+ */
+static void _RectShape_InitInternal (PyRectShapeObject *shape, double width,
+    double height, double seta)
+{
+    PyVector2_Set(shape->bottomleft, -width/2, -height/2);
+    PyVector2_Set(shape->bottomright, width/2, -height/2);
+    PyVector2_Set(shape->topright, width/2, height/2);
+    PyVector2_Set(shape->topleft, -width/2, height/2);
+    PyVector2_Rotate(&(shape->bottomleft), seta);
+    PyVector2_Rotate(&(shape->bottomright), seta);
+    PyVector2_Rotate(&(shape->topright), seta);
+    PyVector2_Rotate(&(shape->topleft), seta);
+}
 
+/**
+ * Initializes the passed PyRectShapeObject (from python code).
+ */
+static int _RectShape_init(PyRectShapeObject* shape,PyObject *args, PyObject *kwds)
+{
+    double width, height, seta = 0;
+    if (PyShape_Type.tp_init((PyObject*)shape, args, kwds) < 0)
+        return -1;
+    if (!PyArg_ParseTuple (args, "dd|d", &width, &height, &seta))
+        return -1;
+
+    _RectShape_InitInternal (shape, width, height, seta);
+    return 0;
+}
+
+/**
+ * Creates a new PyRectShapeObject.
+ */
+static PyObject* _RectShapeNew(PyTypeObject *type, PyObject *args,
+    PyObject *kwds)
+{
+    PyRectShapeObject *shape = (PyRectShapeObject*) _ShapeNew (type, args, kwds);
+    if (!shape)
+        return NULL;
+    
+    shape->shape.UpdateAABB = _RectShapeUpdateAABB;
+    shape->shape.Collision = _RectShapeCollision;
+    shape->shape.type = ST_RECT;
+    return (PyObject*)shape;
+}
+
+/**
+ * Internal RectShape._update_aabb implementation.
+ */
 static void _RectShapeUpdateAABB(PyBodyObject* body)
 {
     int i;
     }
 }
 
-static void _RectShape_InitInternal (PyRectShapeObject *shape, double width,
-    double height, double seta)
+/* RectShape methods */
+
+/**
+ * RectShape._collision
+ */
+static PyObject* _RectShape_collision(PyRectShapeObject* shape, PyObject *args)
 {
-    PyVector2_Set(shape->bottomleft, -width/2, -height/2);
-    PyVector2_Set(shape->bottomright, width/2, -height/2);
-    PyVector2_Set(shape->topright, width/2, height/2);
-    PyVector2_Set(shape->topleft, -width/2, height/2);
-    PyVector2_Rotate(&(shape->bottomleft), seta);
-    PyVector2_Rotate(&(shape->bottomright), seta);
-    PyVector2_Rotate(&(shape->topright), seta);
-    PyVector2_Rotate(&(shape->topleft), seta);
+    PyObject *body1, *body2, *list;
+    if (!PyArg_ParseTuple (args, "OOO", &body1, &body2, &list))
+        return NULL;
+
+    if (!PyBody_Check (body1))
+    {
+        PyErr_SetString (PyExc_TypeError, "body1 must be a Body");
+        return NULL;
+    }
+    if (!PyBody_Check (body2))
+    {
+        PyErr_SetString (PyExc_TypeError, "body2 must be a Body");
+        return NULL;
+    }
+    
+    _RectShapeCollision ((PyBodyObject*)body1,(PyBodyObject*)body2,list);
+    Py_RETURN_NONE;
 }
 
-static int _RectShape_init(PyRectShapeObject* shape,PyObject *args, PyObject *kwds)
+/**
+ * RectShape._update_aabb
+ */
+static PyObject* _RectShape_updateAABB(PyRectShapeObject* shape, PyObject *args)
 {
-    double width, height, seta = 0;
-    if (PyShape_Type.tp_init((PyObject*)shape, args, kwds) < 0)
-        return -1;
-    if (!PyArg_ParseTuple (args, "dd|d", &width, &height, &seta))
-        return -1;
+    PyObject *body;
+    if (!PyArg_ParseTuple (args, "O", &body))
+        return NULL;
 
-    _RectShape_InitInternal (shape, width, height, seta);
-    return 0;
+    if (!PyBody_Check (body))
+    {
+        PyErr_SetString (PyExc_TypeError, "body must be a Body");
+        return NULL;
+    }
+    
+    _RectShapeUpdateAABB ((PyBodyObject*)body);
+    Py_RETURN_NONE;
 }
 
-static PyObject* _RectShapeNew(PyTypeObject *type, PyObject *args,
-    PyObject *kwds)
-{
-    PyRectShapeObject *shape = (PyRectShapeObject*) _ShapeNew (type, args, kwds);
-    if (!shape)
-        return NULL;
-    
-    shape->shape.UpdateAABB = _RectShapeUpdateAABB;
-    shape->shape.Collision = _RectShapeCollision;
-    shape->shape.type = ST_RECT;
-    return (PyObject*)shape;
-}
 
-int PyShapeObject_UpdateAABB (PyShapeObject *shape, PyBodyObject *refbody)
+/* Internally used functions */
+
+int PyShapeObject_UpdateAABB (PyBodyObject *refbody)
 {
     PyObject *result;
     int retval;
 
     /* C implementations should fill that */
-    if (shape->UpdateAABB)
+    if (((PyShapeObject*)refbody->shape)->UpdateAABB)
     {
-        shape->UpdateAABB (refbody);
+        ((PyShapeObject*)refbody->shape)->UpdateAABB (refbody);
         return 1;
     }
     /* No internal collision implementation, try the python one. */
-    result = PyObject_CallMethod ((PyObject*)shape, "_update_aabb", "O",
+    result = PyObject_CallMethod (refbody->shape, "_update_aabb", "O",
         (PyObject*)refbody);
     if (!result)
         return 0;
     return retval;
 }
 
-int PyShapeObject_Collision (PyShapeObject *shape, PyBodyObject *refbody,
+int PyShapeObject_Collision (PyBodyObject *refbody,
     PyBodyObject *incbody, PyObject *contactlist)
 {
     PyObject *result;
     int retval;
 
     /* C implementations should fill that */
-    if (shape->Collision)
-        return shape->Collision (refbody, incbody, contactlist);
+    if (((PyShapeObject*)refbody->shape)->Collision)
+        return ((PyShapeObject*)refbody->shape)->Collision (refbody, incbody,
+            contactlist);
 
     /* No internal collision implementation, try the python one. */
-    result = PyObject_CallMethod ((PyObject*)shape, "_collision", "OOO",
+    result = PyObject_CallMethod (refbody->shape, "_collision", "OOO",
         (PyObject*)refbody, (PyObject*)incbody, contactlist);
     if (!result)
         return -1;

src/pgWorldObject.c

 static int PyWorld_Update(PyObject* world, double dt);
 
 /**
- * Here we allow the Python object to do stuff like
- *
- *  myworld.test_noargs ()
- *  myworld.test_args (arg1, arg2, ...)
+ * Getters and setters for the World
  */
 static PyGetSetDef _World_getseters[] = {
     { "damping", (getter)_World_getDamping, (setter)_World_setDamping,
       "damping", NULL },
     { "gravity",(getter)_World_getGravity, (setter)_World_setGravity,
       "gravity",NULL, },
-    { "body_list",(getter)_World_getBodyList,NULL,NULL,NULL },
-    { "joint_list",(getter)_World_getJointList,NULL,NULL,NULL },
+    { "bodies",(getter)_World_getBodyList,NULL,NULL,NULL },
+    { "joints",(getter)_World_getJointList,NULL,NULL,NULL },
     { NULL, NULL, NULL, NULL, NULL }
 };
 
-
+/**
+ * Methods for the world.
+ */
 static PyMethodDef _World_methods[] =
 {
     { "update", (PyCFunction) _World_update, METH_VARARGS, "" },
-    {"add_body",(PyCFunction) _World_addBody, METH_VARARGS, ""},
-    {"add_joint",(PyCFunction) _World_addJoint, METH_VARARGS, ""},
+    { "add_body",(PyCFunction) _World_addBody, METH_VARARGS, "" },
+     {"add_joint",(PyCFunction) _World_addJoint, METH_VARARGS, "" },
     { NULL, NULL, 0, NULL } /* The NULL sentinel is important! */
 };
 
     0,                          /* tp_iter */
     0,                          /* tp_iternext */
     _World_methods,             /* tp_methods */
-    0,             /* tp_members */
+    0,                          /* tp_members */
     _World_getseters,           /* tp_getset */
     0,                          /* tp_base */
     0,                          /* tp_dict */
     0                           /* tp_del */
 };
 
+/**
+ * Updates the velocity of the bodies attached to the world.
+ *
+ * @param world The PyWorldObject to update the bodies for.
+ * @param stepTime The time passed since the last update.
+ */ 
 static void _FreeBodySimulation(PyWorldObject* world,double stepTime)
 {
     Py_ssize_t i;
     }
 }
 
+/**
+ * Checks the bodies and joints attached to the world for collisions and
+ * updates them accordingly.
+ *
+ * @param world The PyWorldObject to check the bodies and joints for.
+ * @param step The time passed since the last update.
+ */
 static void _BodyCollisionDetection(PyWorldObject* world, double step)
 {
     Py_ssize_t i, j, body_cnt, contact_cnt;
     for(i = 0; i < body_cnt; ++i)
     {
         refBody = (PyBodyObject*)(PyList_GetItem(world->bodyList, i));
-        refShape = (PyShapeObject*)refBody->shape;
-        PyShapeObject_UpdateAABB (refShape, refBody);
+        PyShapeObject_UpdateAABB (refBody);
     }
     
     //collision test
             incShape = (PyShapeObject*)incBody->shape;
             if(AABB_IsOverlap(&(refShape->box), &(incShape->box), 1e-8))
             {
-                PyShapeObject_Collision (refShape, refBody, incBody,
-                    world->contactList);
+                PyShapeObject_Collision (refBody, incBody, world->contactList);
             }
         }
     }
     }
 }
 
+/**
+ * Updates all joints attached to the world.
+ *
+ * @param world The PyWorldObject to update the joints for.
+ * @param stepTime The time passed since the last update.
+ */
 static void _JointSolve(PyWorldObject* world,double stepTime)
 {
     Py_ssize_t size = PyList_Size((PyObject*)(world->jointList));
     }
 }
 
+/**
+ * Updates the positions of the bodies attached to the world.
+ *
+ * @param world The PyWorldObject to update the body positions for.
+ * @param stepTime The time passed since the last update.
+ */
 static void _BodyPositionUpdate(PyWorldObject* world,double stepTime)
 {
     Py_ssize_t size = PyList_Size(world->bodyList);
     }
 }
 
+/**
+ * Performs any necessary position correction for the attached bodies.
+ *
+ * @param world The PyWorldObject to update the bodies for.
+ * @param stepTime The time passed since the last update.
+ */
 static void _BodyPositionCorrection(PyWorldObject* world,double stepTime)
 {
     Py_ssize_t size = PyList_Size((PyObject*)(world->bodyList));
     }
 }
 
+/**
+ * Performs a full world update inluding body updates, collision dection and
+ * any necessary correctins.
+ *
+ * @param world The PyWorldObject to update.
+ * @param stepTime The time passed since the last update.
+*/
 static void _Update(PyWorldObject* world,double stepTime)
 {
     int i;
 	
 }
 
+/**
+ * Initializes the internals of the passed PyWorldObject with their defaults.
+ *
+ * @param world The PyWorldObject to initialize.
+ */
 static void _WorldInit(PyWorldObject* world)
 {
     world->bodyList = PyList_New(0);
     world->fTotalTime = 0.0;
 }
 
+/**
+ * Creates a new PyWorldObject and initializes it.
+ */
 static PyWorldObject* _WorldNewInternal(PyTypeObject *type)
 {
     PyWorldObject* op = (PyWorldObject*)type->tp_alloc(type, 0);
     return op;
 }
 
+/**
+ * Creates a new PyWorldObject and initializes it.
+ */
 static PyObject* _WorldNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
     /* In case we have arguments in the python code, parse them later
     return (PyObject*) _WorldNewInternal(type);
 }
 
+/**
+ * Deallocates the passed PyWorldObject.
+ *
+ * @param world The PyWorldObject to deallocate.
+ */
 static void _WorldDestroy(PyWorldObject* world)
 {
     /*
     world->ob_type->tp_free((PyObject*)world);
 }
 
-static PyObject* _World_update (PyWorldObject* world, PyObject* args)
-{
-    double dt;
-    
-    if (!PyArg_ParseTuple(args,"|d", &dt))
-        dt = 0.1;
-    if (dt < 0)
-    {
-        PyErr_SetString (PyExc_ValueError,
-            "step time must not be smaller than 0");
-        return NULL;
-    }
-    _Update (world,dt);
-    Py_RETURN_NONE;
-}
+/* World getters/setters */
 
-static PyObject* _World_addBody(PyWorldObject* world, PyObject* args)
-{
-    PyObject* body;
-    if (!PyArg_ParseTuple(args,"O",&body) || !PyBody_Check (body))
-    {
-        PyErr_SetString(PyExc_ValueError, "argument must be a body");
-        return NULL;
-    }
-
-    if(!PyWorld_AddBody((PyObject*)world, body))
-    {
-        Py_RETURN_FALSE;
-    }
-    else
-    {
-        Py_RETURN_TRUE;
-    }
-}
-
-static PyObject* _World_addJoint(PyWorldObject* world,PyObject* args)
-{
-    PyObject* joint;
-    if (!PyArg_ParseTuple(args,"O",&joint) || !PyJoint_Check (joint))
-    {
-        PyErr_SetString(PyExc_ValueError,"argument must be a joint");
-        return NULL;
-    }
-    if(!PyWorld_AddJoint((PyObject*)world,joint))
-    {
-        Py_RETURN_FALSE;
-    }
-    else
-    {
-        Py_RETURN_TRUE;
-    }
-}
-
+/**
+ * Getter for World.gravity.
+ */
 static PyObject* _World_getGravity(PyWorldObject* world,void* closure)
 {
     return Py_BuildValue ("(ff)", world->vecGravity.real,
         world->vecGravity.imag);
 }
 
+/**
+ * Setter for World.gravity = (x, y)
+ */
 static int _World_setGravity(PyWorldObject* world,PyObject* value,void* closure)
 {
     PyObject *item;
     return 0;
 }
 
+/**
+ * Getter for World.damping
+ */
 static PyObject* _World_getDamping(PyWorldObject* world,void* closure)
 {
     return PyFloat_FromDouble (world->fDamping);
 }
 
+/**
+ * Setter for World.damping = x
+ */
 static int _World_setDamping(PyWorldObject* world,PyObject* value,
     void* closure)
 {
     
 }
 
+/**
+ * Getter for World.bodies
+ */
 static PyObject* _World_getBodyList(PyWorldObject* world,void* closure)
 {
-    Py_INCREF (world->bodyList);
-    return world->bodyList;
+    /* Return a copy of the list, so the user cannot manipulate the bodies
+     * directly. */
+    return PySequence_List (world->bodyList);
 }
 
+/**
+ * Getter for World.joints
+ */
 static PyObject* _World_getJointList(PyWorldObject* world,void* closure)
 {
-    Py_INCREF (world->jointList);
-    return world->jointList;
+    /* Return a copy of the list, so the user cannot manipulate the bodies
+     * directly. */
+    return PySequence_List (world->jointList);
 }
 
 
+/* World methods */
+
+/**
+ * World.update (x)
+ */
+static PyObject* _World_update (PyWorldObject* world, PyObject* args)
+{
+    double dt;
+    
+    if (!PyArg_ParseTuple(args,"|d", &dt))
+        dt = 0.1;
+    if (dt < 0)
+    {
+        PyErr_SetString (PyExc_ValueError,
+            "step time must not be smaller than 0");
+        return NULL;
+    }
+    _Update (world,dt);
+    Py_RETURN_NONE;
+}
+
+/**
+ * World.add_body (x)
+ */
+static PyObject* _World_addBody(PyWorldObject* world, PyObject* args)
+{
+    PyObject* body;
+    if (!PyArg_ParseTuple(args,"O",&body) || !PyBody_Check (body))
+    {
+        PyErr_SetString(PyExc_ValueError, "argument must be a body");
+        return NULL;
+    }
+
+    if(!PyWorld_AddBody((PyObject*)world, body))
+    {
+        Py_RETURN_FALSE;
+    }
+    else
+    {
+        Py_RETURN_TRUE;
+    }
+}
+
+/**
+ * World.add_joint (x)
+ */
+static PyObject* _World_addJoint(PyWorldObject* world,PyObject* args)
+{
+    PyObject* joint;
+    if (!PyArg_ParseTuple(args,"O",&joint) || !PyJoint_Check (joint))
+    {
+        PyErr_SetString(PyExc_ValueError,"argument must be a joint");
+        return NULL;
+    }
+    if(!PyWorld_AddJoint((PyObject*)world,joint))
+    {
+        Py_RETURN_FALSE;
+    }
+    else
+    {
+        Py_RETURN_TRUE;
+    }
+}
+
 /* C API */
 static PyObject* PyWorld_New (void)
 {