Game Development Reference
In-Depth Information
In Listing 5-6, the first thing we do in viewTapped: is to cast the passed in UIGestureRecognizer to
UITapGestureRecognizer . We then find the point where the tap occurred in the root view by calling
locationInView: . Once we have the point where the tap occurred, we simply set the moveToPoint
property on the viper object. Notice that we did not have to interrupt any existing animation—we
simply update the state of the viper object and, when its updateLocation task is called again, it will start
moving toward this new point. This is a very simple example, but I hope it illustrates an advantage that
frame-by-frame animations have over the predefined animations we looked at in the last chapter.
We have looked at how this simple animation is set up and how it is driven by repeated calls to
updateScene from Listing 5-4. We should take a little time and understand the classes responsible for
making these repeated calls.
Understanding CADisplayLink and NSRunLoop
In general, to create a smooth-looking animation, a picture has to be updated at least 25 times a
second to avoid the eyes seeing each individual frame. That means our game must find a way to call
updateScene at 25 times a second to achieve a smooth animation. This could be done by creating an
NSTimer that calls updateScene at any rate we choose. If we do that, however, our code that updates
the scene will not necessarily be in sync with the hardware's native refresh rate of the screen. The
framework Core Animation provides a class specifically designed for creating the type of animation
we are trying to create: CADisplayLink .
In Listing 5-3, we created a CADisplayLink , specifying that it should call updateScene whenever
the screen is ready to redraw. We then added the CADisplayLink to the same run loop that called
viewDidLoad by calling currentRunLoop on the class NSRunLoop . The class NSRunLoop manages a
thread to produce the kind of loop shown in Figure 5-1 . An NSRunLoop is responsible for processing
input from the user and from the CADisplayLink and scheduling when the corresponding task in
Example01Controller should be called. We don't have to understand too much about how NSRunLoop
works; we just have to understand that the tasks viewTapped: and updateScene will be called by the
same thread so we don't have to worry about multi-threaded complexity.
As mentioned, CADisplayLink —working with our main threads NSRunLoop —causes the task
updateScene to be called once for each time the screen redraws. The property duration of
CADisplayLink reports, in seconds, the time between each screen redraw. A little investigation shows
that this property reports a slightly different value each time updateScene is called, but hovers around
the value 0.0166648757. This value is just shy of 60 frames per second, so we are well above the
required 25 frames per second.
In more complex applications, it is entirely likely that the state of the game cannot be updated in
1.5 milliseconds; there may simply be too much bookkeeping. If this is the case, you can set the
frameInterval property of CADisplayLink to value greater than one. This will cause CADisplayLink
to skip screen redraws. Figure 5-6 shows four different scenarios that can occur when using the
CADisplayLink .
 
Search WWH ::




Custom Search