Box2D Binary Counter
Game Physics with a 2D Physics Engine
Loading...
Searching...
No Matches

1. Introduction

This toy uses Box2D to implement a 5-bit gravity-driven ripple-carry counter that counts from zero to \(2^5 - 1 = 31\). There is an LED readout for the number of balls released and an array of nixie tubes showing that number in binary. It takes a few seconds for the carry to ripple down after the release of a new ball, after which the current binary number represented by the soccer balls is read aloud and the corresponding soccer balls (or lack of them) highlighted by a spinning reticle. Fig. 1 shows the counter in its initial state, that is, at value zero.

Fig. 1: Screen shot in the initial configuration (zero).

The remainder of this page is divided into six sections. Section 2 lists the controls and their corresponding actions, Section 3 tells you how to build it, Section 4 gives you a list of actions to take in the game to see some of its important features, Section 5 gives a breakdown of the code, Section 6 contains some programming problems, and Section 7 addresses the question "what next?".

2. Keyboard Controls

Key
Action
F1
Help (this document)
F2
Toggle draw mode from "sprites only", to "sprites and lines", to "lines only"
Backspace
Reset
Space
Release the next ball to increment the counter
P
Save screenshot to a file
Esc
Quit game and close the window

3. Building the Game

This code uses SAGE and Box2D. Make sure that you have followed the SAGE Installation Instructions and the Box2D Installation Instructions. Navigate to the folder 13. Binary Counter Toy in your copy of the sage-physics repository. Run checkenv.bat to verify that you have set the environment variables correctly. Open Binary Counter Toy.sln with Visual Studio and build the Release configuration. Alternatively, run Build.bat to build both Release and Debug configurations.

4. Game Play

Fig. 2: Single bit counter showing a 0 (left) and a 1 (right).

The key to this toy is the single-bit counter shown in Fig. 2. Bits that are 1 are represented by soccer balls. Bits that are zero are represented by the lack of a soccer ball. For example, the image on the left of Fig. 2 represents a 0, and the image on the right of Fig. 2 represents a 1.

Fig. 3: Labelled screen shot.

Fig. 3 shows the parts of the binary counter toy. There are five bits, which means that the counter can count from zero to \(2^5 - 1 = 31\). Each bit is represented by a copy of the device from Fig. 2 (left). arranged from right to left, top to bottom. That means that the least significant bit (the one representing \(2^0=1\)) is at top right (Fig. 3(a)) and the most significant bit (representing \(2^4 = 16\)) is at bottom left (Fig. 3(b)). The current value of the counter can be read off from right to left using the soccer balls in binary, from left to right in the binary counter display (Fig. 3(c)), and in decimal in the binary counter display (see Fig. 3(d)). Any attempt to count to \(32\) will result in the overflow light (see Fig. 3(e)) flashing red.

Fig. 4: Rest states while counting.

Fig. 4 shows an animation of the rest states, that is, the screen shown when the balls have come to rest and the game is waiting for the user to release the next ball (see Section 2 for keyboard controls). Pay attention to the soccer balls, the binary counter, and the decimal counter (refer back to Fig. 3 is necessary). Let's look a little closer at what happens to a single bit when incrementing from 0 to 1, then incrementing from 1 to 0 resulting in a carry bit. This is shown in Fig. 5.

Fig. 5: Actions when incrementing a single bit twice.

Fig 5(a) shows a single zero bit. When a ball is released (either a carry from the previous bit or, if it's the least significant bit, then from the top of window when the user hits the increment key as described in Section 2), it falls onto the top right platform and rolls right as shown in Fig 5(b) and gets trapped in the pit shown in Fig 5(c). The bit has now been incremented from 0 to 1. Now we show what happens when we increment from 1 to 0. The next ball again enters from top right, but this time it rolls over the ball in the pit and down the slope on the left of Fig 5(d). It hits the lower platform in Fig 5(e) and rolls right, having been deflected by the slope. This ball hits the vertical leg holding up a swing arm at the bottom of the pit containing the previous ball and exits the toy to the right of Fig 5(f), ending up with a collection of balls at the bottom of the window. The previous ball is released in Fig 5(f) and rolls to the left in Fig 5(g) on the lower platform, which is in fact the upper platform of the next bit counter. This is the carry bit. Meanwhile, when released of the weight of the carry ball, the swing arm returns to its initial position in Fig 5(h).

5. Code Breakdown

Let \(x\) and \(y\) be single bits. When \(x\) and \(y\) are added together, the result is the exclusive-or \(z = x \oplus y\) and the carry bit is the conjunction \(x \wedge y\). This gives us the single-bit counter shown in Fig. 6.

Fig. 6: Single bit counter.

Our single bit counter consists of two rectangular blocks (primary and secondary), a triangular ramp, a rectangular swing arm, and two rectangular legs, and three revolute joints as shown in Fig. 7. There is a revolute joint at the center of the swing arm connecting it to the null background, and a revolute joint at the top of each leg joining it to one of the two ends of the swing arm. It is implemented in code by CBitCounter. Its constructor CBitCounter::CBitCounter takes as parameters the coordinates of its center in render world coordinates and a Boolean variable that is true if this is the last (i.e. null) bit counter. It uses CBitCounter::CreateRamp to create the ramp and CBitCounter::CreateBlock to create the blocks, swing arm, and legs.

Fig. 7: Shapes and joints for single bit counter.

Now suppose we wish to increment the binary number \(x_4x_3x_2x_1x_0\) to get the result \(z_4z_3z_2z_1z_0\) and an overflow bit. We simply cascade five single bit counters with the carry from one going to the input of the next as shown in Fig. 8. This should be familiar to you if you have taken an elementary hardware or computer organization class.

Fig. 8: Ripple-carry counter with 5 bits.

Our ripple-carry increment will be constructed from five single-bit counters as shown in Fig. 7 spaced out vertically and shifted to the left so that the carry from one becomes the input to the next. Its left leg will rest on the primary block of the single bit counter below it so that the ball can rest on it when the it has value 1 as shown in Fig. 9. There will be a sixth sentinel single bit counter that consists of just the primary block.

Fig. 9: Shapes for single bit counter at 1.

Our counter is implemented as an instance of CCounter, which stores an array of pointers to instances of CBitCounter created in its constructor. An instance of CCounter is created in CObjectManager::CreateCounter which is called from CGame::BeginGame.

6. Problems

Problem 13.1

There are many ways to build a binary counter. Suppose we represent a single bit as a triangle that tips left for zero (Fig. 10, left) and right for one (Fig. 10, right). Let's call this a gadget for short. Dropping a ball from above the middle of this triangle will tip it from one side to the other.
Fig. 10: A single bit at zero (left) and one (right).
Your task is to build a 4-bit counter from 4 of these gadgets arranged one above the other as shown in Fig. 11 with some extra shapes that makes the balls cascade on the left (what a one changes to a zero) from one gadget to the next. Note that the gadgets are arranged from the least significant bit at the top to the most significant bit at the bottom as above.
Fig. 11: A four bit counter at zero.
Make a copy of the folder 11. Box2D Blank Game in some place convenient (for example, the Desktop or your Documents folder) and modify it so that a ball is dropped from the top center of the window when the Space bar is pressed. Each ball cascades off the gadgets and collects at the bottom of the window having incremented the binary number represented by the gadgets from bottom to top. Fig. 12 shows the rest states representing the 4-bit binary numbers.
Fig. 12: Rest states while counting.
Notice that in Fig. 12 the number represented is written in binary at top right of the window and the bit represented by each gadget is indicated by a 0 and a 1 character printed above the gadget so that the triangle points to the right bit. It's not necessary for you to do that.

7. What Next?

Next, take a look at the Cannon Lullaby Toy.