GSoC/GCI Archive
Google Code-in 2012 Copyleft Games Group

PySoy: Make Scene a Dict of Bodies

completed by: Nikolay Lazarov

mentors: Amaury Medeiros, Arc Riley, Tony Young, David Czech, Mayank Singh

Its intended for soy.scenes.Scene and derived classes to act as a dict of bodies allowing programmers to add and remove them by name. However, PySoy is quite large with many components, so this was skipped early on and nobody has gone back to fix it yet.

The current API, where bodies define the Scene they're to be added to when created, neither provides for a method for removing a body from a scene nor refering to it if Python's reference is lost even as the body continues to render normally.

Take the following example:

>>> import soy >>> client = soy.Client() >>> scene = soy.scenes.Scene() >>> cam = soy.bodies.Camera(scene) >>> cam.position.z = 15 >>> projector = soy.widgets.Projector(client.window, cam) >>> light = soy.bodies.Light(scene) >>> light.position = soy.atoms.Position((-2, 3, 5)) >>> cube = soy.bodies.Box(scene) >>> cube.material = soy.materials.Colored() >>> cube.size = soy.atoms.Size((1,1,1)) >>> scene <Scene with 3 bodies and 1 light> >>> scene[0] TypeError: 'soy.scenes.Scene' object is not subscriptable >>> del(scene[0]) TypeError: 'soy.scenes.Scene' object does not support item deletion >>> del(cube) >>> scene <Scene with 3 bodies and 1 light>

At the end of this example the cube remains in the scene, still renders and functions normally, but there's absolutely no way to access it from Python anymore. As a result, a developer of a game containing a reasonable number of bodies would have to keep a separate container (likely a dict) to reference them all.

If soy.scenes.Scene instead acted as a Python dict (via Mapping Protocol) the above code could be rewritten like this:

>>> import soy >>> client = soy.Client() >>> scene = soy.scenes.Scene() >>> scene['cam'] = soy.bodies.Camera() >>> scene['cam'].position.z = 15 >>> projector = soy.widgets.Projector(client.window, cam) >>> scene['light'] = soy.bodies.Light() >>> scene['light'].position = soy.atoms.Position((-2, 3, 5)) >>> scene['cube'] = soy.bodies.Box() >>> scene['cube'].material = soy.materials.Colored() >>> scene['cube'].size = soy.atoms.Size((1,1,1)) >>> scene {'cam': <Camera>, 'light': <Light>, 'cube': <box>} >>> scene['cube'] <box> >>> del(scene['cube']) >>> scene {'cam': <Camera>, 'light': <Light>}

As with most of our Google Code-In tasks, this would take an experienced PySoy developer 2-3 hours to complete, however it may take a new developer much longer than the average task. Because of this a step-by-step guide is provided here to give you guidance:

  1. brush up on Genie's dict api
  2. change libsoy's Scene.bodies to use dict instead of Gee.HashSet
  3. edit every body class constructor to not require a scene
  4. edit every body property/method to return empty results when not in a scene
  5. write libsoy's Body.add and Body.remove functions
  6. update PySoy's Body tp_new to no longer accept a scene
  7. write mapping methods for PySoy's Scene for adding a body (call Body.add)
  8. write mapping methods for PySoy's Scene for returning an instance
  9. write mapping methods for PySoy's Scene for deleting an instance
  10. rewrite PySoy's Scene tp_repr for returning a dict-like string

This task shouldn't require more than 250 lines of code and you're expected to need some additional guidance from mentors. This task will be considered complete when code resembling the second example above works.

While working on this task you should join and remain in #PySoy on Freenode to get help, feedback, and guidance from mentors and other developers. Code updates which may affect your work are also announced here as they happen.

When you've done, commit your work and post the resulting changeset url to this task.