The classic chicken-and-egg problem haunts us again. You learned in the last chapter that we have a correspondence between world units (for example, meters) and pixels. Our objects are defined physically in world space. Bounding shapes and positions are given in meters; velocities are given in meters per second. The graphical representations of our objects are defined in pixels though, so we have to have some sort of mapping. We overcome this problem by first defining a target resolution for our graphical assets. As with Mr. Nom, we will use a target resolution of 320×480 pixels (aspect ratio of 1.5). We're using this target because it's the lowest practical resolution but, if you're targeting tablets specifically, you may want to use a resolution like 800×1280 or perhaps something in between, such as 480×800 (a typical Android handset). Despite your target resolution, the principals remain the same.
The next thing we have to do is establish a correspondence between pixels and meters in our world. The mock-up in Figure 9–1 gives us a sense of how much screen space different objects use, as well as their proportions relative to each other. We recommend choosing a mapping of 32 pixels to 1 meter for 2D games. So let's overlay our mock-up, which is 320×380 pixels in size, with a grid where each cell is 32×32 pixels. In our world space, this would map to 1×1 meter cells. Figure 9–3 shows our mock-up and the grid.
Figure 9–3 is of course a little bit cheated. We arranged the graphics in a way so that they line up nicely with the grid cells. In the real game, we'll place the objects at noninteger positions.
So, what can we make of Figure 9–3? First of all, we can directly estimate the width and height of each object in our world in meters. Here are the values we'll use for the bounding rectangles of our objects:
With those sizes, we also have the sizes of the bounding rectangles of our objects for collision detection. We can adjust them if they turn out to be a little too big or small, depending on how the game plays out with those values.
Another thing we can derive from Figure 9–3 is the size of our view frustum. It will show us 10×15 meters of our world.
The only thing left to define are the velocities and accelerations we have in the game. This is highly dependent on how we want our game to feel. Usually, you'd have to do some experimentation to get those values right. Here's what we came up with after a few iterations of tuning:
So how will Bob's horizontal movement work? The movement speed we defined before is actually Bob's maximum horizontal speed. Depending on how much the player tilts his or her phone, Bob's horizontal movement speed will be between 0 (no tilt) and 20 m/s (fully tilted to one side).
We'll use the value of the accelerometer's x-axis since our game will run in portrait mode. When the phone is not tilted, the axis will report an acceleration of 0 m/s2. When fully tilted to the left so that the phone is in landscape orientation, the axis will report roughly –10 m/s2. When fully tilted to the right, the axis will report an acceleration of roughly 10 m/s2. All we need to do is normalize the accelerometer reading by dividing it by the maximum absolute value (10) and then multiplying Bob's maximum horizontal speed by that. Bob will thus travel 20 m/s to the left or right when the phone is fully tilted to one side and less if the phone is tilted less. Bob can move around the screen twice per second when the phone is fully tilted.
We'll update this horizontal movement velocity each frame based on the current accelerometer value on the x-axis and combine it with Bob's vertical velocity, which is derived from the gravity acceleration and his current vertical velocity, as we did for the cannonball in the earlier examples.
One essential aspect of the world is the portion we see of it. Since Bob will die when he leaves the screen on the bottom edge, our camera also plays a role in the game mechanics. While we'll use a camera for rendering and move it upward when Bob jumps, we won't use it in our world simulation classes. Instead we record Bob's highest y-coordinate so far. If he's below that value minus half the view frustum height, we know he has left the screen. Thus, we don't have a completely clean separation between the model (our world simulation classes) and the view, since we need to know the view frustum's height to determine whether Bob is dead. We can live with this.
Let's have a look at the assets we need.
13.58.201.235