Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Beginning iOS5 Development.pdf
Скачиваний:
7
Добавлен:
09.05.2015
Размер:
15.6 Mб
Скачать

CHAPTER 19: Whee! Gyro and Accelerometer!

653

Figure 19–2. MotionMonitor running on an iPhone 4. Unfortunately, you’ll get only a pair of error messages if you run this app in the simulator.

If you run this on a device with a gyroscope, you’ll see how those values change as well. Whenever the device is standing still, no matter which orientation it is in, the gyroscope values will hover around zero. As you rotate the device, you’ll see that the gyroscope values change, depending on how you rotate it on its various axes. The values will always move back to zero when you stop moving the device.

Proactive Motion Access

You’ve seen how to access motion data by passing CMMotionManager blocks to be called as motion occurs. This kind of event-driven motion handling can work well enough for the average Cocoa app, but sometimes it doesn’t quite fit an application’s particular needs. Interactive games, for example, typically have a perpetually running loop that processes user input, updates the state of the game, and redraws the screen. In such a case, the event-driven approach isn’t such a good fit, since you would need to implement an object that waits for motion events, remembers the latest positions from each sensor as they’re reported, and is ready to report the data back to the main game loop when necessary.

Fortunately, CMMotionManager has a built-in solution. Instead of passing in blocks, we can just tell it to activate the sensors using the startAccelerometerUpdates and

www.it-ebooks.info

654

CHAPTER 19: Whee! Gyro and Accelerometer!

startGyroUpdates methods, after which we simply read the values any time we want, directly from the motion manager!

Let’s change our MotionMonitor app to use this approach, just so you can see how it works. Start off by making a copy of your MotionMonitor project folder. Next, add a new property to BIDViewController.h, a pointer to an NSTimer that will trigger all our display updates:

#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface BIDViewController : UIViewController

@property (retain) CMMotionManager *motionManager; @property (retain) IBOutlet UILabel *accelerometerLabel; @property (retain) IBOutlet UILabel *gyroscopeLabel;

@property (retain) NSTimer *updateTimer;

@end

Now, switch to BIDViewController.m, where you’ll need to synthesize the new property:

@implementation BIDViewController @synthesize motionManager; @synthesize accelerometerLabel; @synthesize gyroscopeLabel;

@synthesize updateTimer;

Get rid of the entire viewDidLoad method we had before, and replace it with this simpler version, which just sets up the motion manager and provides informational labels for devices lacking sensors:

- (void)viewDidLoad { [super viewDidLoad];

self.motionManager = [[CMMotionManager alloc] init];

if (motionManager.accelerometerAvailable) { motionManager.accelerometerUpdateInterval = 1.0/10.0; [motionManager startAccelerometerUpdates];

} else {

accelerometerLabel.text = @"This device has no accelerometer.";

}

if (motionManager.gyroAvailable) { motionManager.gyroUpdateInterval = 1.0/10.0; [motionManager startGyroUpdates];

} else {

gyroscopeLabel.text = @"This device has no gyroscope.";

}

}

Normally, we use viewDidLoad and viewDidUnload to “bracket” the creation and destruction of properties related to the GUI display. In the case of our new timer, however, we want it to be active only during an even smaller window of time, when the view is actually being displayed. That way, we keep the usage of our main game loop to

www.it-ebooks.info

CHAPTER 19: Whee! Gyro and Accelerometer!

655

a bare minimum. We can accomplish this by implementing viewWillAppear: and viewDidDisappear: as follows. Add this code to those two methods:

- (void)viewWillAppear:(BOOL)animated {

[super viewWillAppear:animated];

self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0 target:self

selector:@selector(updateDisplay)

userInfo:nil

repeats:YES];

}

- (void)viewDidDisappear:(BOOL)animated {

[super viewDidDisappear:animated]; self.updateTimer = nil;

}

The code in viewWillAppear: creates a new timer and schedules it to fire once every 1/10 second, calling the updateDisplay method, which we haven’t created yet. Add this method just below ViewDidDisappear:

- (void)updateDisplay {

if (motionManager.accelerometerAvailable) {

CMAccelerometerData *accelerometerData = motionManager.accelerometerData; accelerometerLabel.text = [NSString stringWithFormat:

@"Accelerometer\n-----------\nx: %+.2f\ny: %+.2f\nz: %+.2f", accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z];

}

if (motionManager.gyroAvailable) {

CMGyroData *gyroData = motionManager.gyroData; gyroscopeLabel.text = [NSString stringWithFormat:

@"Gyroscope\n--------\nx: %+.2f\ny: %+.2f\nz: %+.2f", gyroData.rotationRate.x,

gyroData.rotationRate.y,

gyroData.rotationRate.z];

}

}

Build and run the app on your device, and you should see that it behaves exactly like the first version. Now you’ve seen two ways of accessing motion data. Use whichever suits your application best.

Accelerometer Results

We mentioned earlier that the iPhone’s accelerometer detects acceleration along three axes, and it provides this information using the CMAcceleration struct. Each CMAcceleration has an x, y, and z field, each of which holds a floating-point value. A value of 0 means that the accelerometer detects no movement on that particular axis. A positive or negative value indicates force in one direction. For example, a negative value for y indicates that downward pull is sensed, which is probably an indication that the

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]