Read my book

I wrote books about Webpack and React. Check them out!

Thursday, January 21, 2010

Placidity - Part 12, Bounce

In the previous part of the series we finally managed to implement a proper way to quit from the application. As a side benefit scenario tester gained some meta functionality that may be used to restart the application and check its state (is it running or not?). In this part I will look into implementing a simple "bounce" command that just shows a simple bouncing ball in a window.

During an earlier experiment based on VPython I noticed that this is not quite a straightforward thing to do. The ball bounced just fine but the problem was that running the command blocked input. Probably the most straightforward way to handle the issue is to come up with a threaded solution. The idea is that there should be a repeating thread that handles redrawing the bouncing ball and a "master" thread that constantly polls for user input. As I have not used Python threading module earlier I had to do bit of research. I managed to find this post that got me going.

After tinkering around with the snippet in the post I managed to come up with a prototype. It's probably far from perfect but at least it seems to work just fine. Only major issue I have not managed to solve yet is the fact that if you close the window spawned by VPython it kills the whole application. There might be some workaround for this but I haven't managed to find it yet. Perhaps I should just take a look at VPython code. :P I also have to figure out how to spawn multiple VPython windows (handle with separate processes?).

I'm going to integrate the threading behavior in the actual application itself next. First I will replace the current input logic with threaded one. After that I will focus on implementing "bounce".

Modifying Input Logic

The current main loop of the application looks like this:

In my prototype it looks like this:

There's a slight mismatch between the implementations. As you may remember the implementation scenario tester expects that the application has both input and output methods. So those have to remain, one way or another.

Hooking up output is quite simple:

After that change the application runs just fine but the tests won't pass due to the input method that has not been hooked up yet. Let's handle that next. We can safely remove the method altogether. This breaks the prefix ('>>> ') test but that's fixable. All we need to do is to make sure the input method gets called at "input_evaluator" during testing. To allow this Application has to be instrumented so that a custom input source may be provided it during testing. Hopefully that made some sense. :) If not, you can find the source including those changes here.

As it's uncool to have a failing test, let's take a look at the prefix test (test_input_prefix). Considering input has been separated to KeyboardInput class now we can test that directly. I came up with the following test for this case:

Now all tests should pass with no hiccups. It's a good time to look at the real goal of this part, implementation of "bounce".

Implementation of Bounce

In this case the implementation can be mostly derived from the prototype and some existing code (Eliza command). I came up with this sort of solution:

The file should go in /placidity/commands/bounce/ .The cool thing is that it actually works! You can alter the camera rotation by dragging in the while pressing down the right mouse button. If you press both left and right mouse buttons simultaneously you can alter zoom.


In this relatively brief part I looked into integrating some prototype code (threaded polling + VPython bounce) into the main application. As a result it's possible to add simple animated VPython commands to the system now. The architecture probably should be tweaked to make this easier but the essential groundwork has been done.

Instead of doing something more or less funky with code, I will look into analysing the work done so far in the next part of the series. I will try to come up with some sort of list of lessons learned, recap the main points and ponder the future.

You may find the source code of this part here.