iPhone Game Development - Chris Craft [72]
Animating the road
We can now focus on how to best animate the road to create the illusion of traveling down the road in a car. There are many ways we could do this. Consider the following options:
Scroll new road images down from the top of the screen as needed.
Cut the road image up into horizontal pieces and when one falls off the bottom, move it back to the top of the screen.
Take advantage of the iPhone SDK's ability to tile an image on the screen for you.
The first option is fairly easy, but it would mean you would have to keep track of multiple road objects. This introduces additional complexity that you should try to avoid. The next option goes back to the idea of cutting up the road into many pieces and working with them as a group. This option is related to the first option, except instead of using a second option it reuses itself—not an ideal solution, since it is actually a little harder than the first solution. The best solution is the third idea, which is to let the iPhone SDK figure it out for you.
Tiling an image
The iPhone SDK has a great method called CGContextDrawTiledImage that will tile an image for you. Its job is to repeatedly draw an image, scaled to the provided rectangle, to fill the current clip region. The CGContextDrawTiledImage method does all the heavy lifting, but it does expect a few parameters from you:
Context. The graphics context in which to draw the image. Basically this is any object that knows how to display an image.
Rect. A rectangle that specifies the tile size and offset. You can increase or decrease the image size.
Image. The image to draw.
You already know the image you want to display. It is the road.png file. And you already know the size you want to display this image. You want it to match the iPhone screen size of 320 pixels wide by 480 pixels high. You want to use the Main View's background to show the road image so you know what the context is.
One thing you may not know is what the offset values are for. They allow you to start reading the image from a location other than the top-left corner. For example, by default Quartz draws an image to the screen by reading from the (0, 0) position in the image file (see Figure 5.14).
But if you tell Quartz to start at another location—say (160, 0)—Quartz will slide the image over 160 pixels to the left, and any pixels that got moved off of the screen to the left will be wrapped around the right of the screen. Consider what Quartz would do if you used an offset of (160, 240). Figure 5.15 shows an example of the output that would be produced.
One way to imagine this would be to take a piece of paper that is 320 mm wide and 480 mm tall and cut it in half at the 160 mm wide mark. Now take the left piece of the paper and move it to the right side of the other piece of paper. You could do a similar action for the top and bottom 240 mm parts of the paper. This would represent a vertical offset of 240 pixels.
The important thing to realize is this creates the effect you want to achieve. When any of the road falls off the bottom of the screen, you want it to reappear at the top of the screen. This way the road could go on forever if you needed it to. You will have to do a little work to get the CGContextDrawTiledImage function to work as needed.
You will need to add a class level variable named currentImage to keep an instance of the road image in memory to avoid reading from the device memory each time. Many developers think of programming as the art of caching data. If you can read an cached image ten times faster than reading it from a file, you can make that part of your application ten times faster simply by taking advantage of caching. Add a variable named tileOffset to keep up with the road's current vertical offset. Then you will need to assign the road.png image to the currentImage inside the awakeFromNib method. It's best if the road has its own timer that can be