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

664

CHAPTER 19: Whee! Gyro and Accelerometer!

hardware, but it does simulate the shake event, so the version of the application in 19 ShakeAndBreak - Motion Method will work with the simulator.

Go have some fun with it. When you’re finished, come on back, and you’ll see how to use the accelerometer as a controller for games and other programs.

Accelerometer As Directional Controller

Commonly, instead of using buttons to control the movement of a character or object in a game, the accelerometer is used. In a car-racing game, for example, twisting the iOS device like a steering wheel might steer your car, while tipping it forward might accelerate, and tipping back might brake.

Exactly how you use the accelerometer as a controller will vary greatly depending on the specific mechanics of the game. In the simplest cases, you might just take the value from one of the axes, multiply it by a number, and tack that on to the coordinates of the controlled objects. In more complex games where physics are modeled more realistically, you would need to make adjustments to the velocity of the controlled object based on the values returned from the accelerometer.

The one tricky aspect of using the accelerometer as a controller is that the delegate method is not guaranteed to call back at the interval you specify. If you tell the motion manager to read the accelerometer 60 times a second, all that you can say for sure is that it won’t update more than 60 times a second. You’re not guaranteed to get 60 evenly spaced updates every second. So, if you’re doing animation based on input from the accelerometer, you must keep track of the time that passes between updates and factor that into your equations to determine how far objects have moved.

Rolling Marbles

For our next trick, we’re going to let you move a sprite around iPhone’s screen by tilting the phone. This is a very simple example of using the accelerometer to receive input. We’ll use Quartz 2D to handle our animation.

NOTE: As a general rule, when you’re working with games and other programs that need smooth animation, you’ll probably want to use OpenGL ES. We’re using Quartz 2D in this application for the sake of simplicity and to reduce the amount of code that’s unrelated to using the

accelerometer. The animation won’t be quite as smooth as if we were using OpenGL, but it will

be a lot less work.

In this application, as you tilt your iPhone, the marble will roll around as if it were on the surface of a table (see Figure 19–7). Tip it to the left, and the ball will roll to the left. Tip it farther, and it will move faster. Tip it back, and it will slow down and then start going in the other direction.

www.it-ebooks.info

CHAPTER 19: Whee! Gyro and Accelerometer!

665

Figure 19–7. The Ball application lets you roll a marble around the screen.

In Xcode, create a new project using the Single View Application template, and call this one Ball. In the 19 - Ball folder in the project archive, you’ll find an image called ball.png. Drag that to your project.

Now, single-click the Ball folder, and select File New New File…. Select Objective-C class from the Cocoa Touch category, click Next, and name the new class BIDBallView. Select UIView in the Subclass of popup, and click Create to save the class files. We’ll get back to editing this class a little later.

Select BIDViewController.xib to edit the file in Interface Builder. Single-click the View icon, and use the identity inspector to change the view’s class from UIView to BIDBallView. Next, switch to the attributes inspector, and change the view’s Background to Black Color. Then save the nib.

Now it’s time to edit BIDViewController.h. All we need to do here is prepare for Core Motion, so make the following changes:

#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface BIDViewController : UIViewController

@property (strong, nonatomic) CMMotionManager *motionManager;

@end

www.it-ebooks.info

666

CHAPTER 19: Whee! Gyro and Accelerometer!

Next, switch to BIDViewController.m, and add the following lines toward the top of the file:

#import "BIDViewController.h"

#import "BIDBallView.h"

#define kUpdateInterval

(1.0f / 60.0f)

@implementation BIDViewController

@synthesize motionManager;

.

.

.

Next, populate viewDidLoad with this code:

- (void)viewDidLoad { [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

self.motionManager = [[CMMotionManager alloc] init]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; motionManager.accelerometerUpdateInterval = kUpdateInterval; [motionManager startAccelerometerUpdatesToQueue:queue withHandler:

^(CMAccelerometerData *accelerometerData, NSError *error) {

[(BIDBallView *)self.view setAcceleration:accelerometerData.acceleration]; [self.view performSelectorOnMainThread:@selector(update)

withObject:nil waitUntilDone:NO];

}];

}

The viewDidLoad method here is similar to some of what we’ve done elsewhere in this chapter. The main difference is that we are declaring a much higher update interval of 60 times per second. In the block that we tell the motion manager to execute when there are accelerometer updates to report, we pass the acceleration object into our view, and then call a method named update, which updates the position of the ball in the view based on acceleration and the amount of time that has passed since the last update. Since that block can be executed on any thread, and the methods belonging to UIKit objects (including UIView) can be safely used only from the main thread, we once again force the update method to be called in the main thread.

Writing the Ball View

Note that when you entered the code for viewDidLoad in the previous step, you probably saw some error as a result of BIDBallView not being complete. Since we’re doing the bulk of our work in the BIDBallView class, we had better write it, huh? Select BIDBallView.h, and make the following changes:

#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface BIDBallView : UIView

www.it-ebooks.info

CHAPTER 19: Whee! Gyro and Accelerometer!

667

@property (strong, nonatomic) UIImage *image; @property CGPoint currentPoint;

@property CGPoint previousPoint;

@property (assign, nonatomic) CMAcceleration acceleration; @property CGFloat ballXVelocity;

@property CGFloat ballYVelocity; - (void)update;

@end

Let’s look at the properties and talk about what we’re doing with each of them. The first is a UIImage that will point to the sprite that we’ll be moving around the screen.

UIImage *image;

After that, we keep track of two CGPoint variables. The currentPoint property will hold the current position of the ball. We’ll also keep track of the last point where we drew the sprite. That way, we can build an update rectangle that encompasses both the new and old positions of the ball, so that it is drawn at the new spot and erased at the old one.

CGPoint currentPoint;

CGPoint previousPoint;

Next is an acceleration struct, which is how we will get the accelerometer information from our controller.

CMAcceleration acceleration;

We also have two variables to keep track of the ball’s current velocity in two dimensions. Although this isn’t going to be a very complex simulation, we do want the ball to move in a manner similar to a real ball. We’ll calculate the ball movement in the next section.

We’ll get acceleration from the accelerometer and keep track of velocity on two axes with these variables.

CGFloat ballXVelocity;

CGFloat ballYVelocity;

Let’s switch over to BIDBallView.m and write the code to draw and move the ball around the screen. First, make the following changes at the top of BIDBallView.m:

#import "BIDBallView.h"

@implementation BIDBallView

@synthesize image; @synthesize currentPoint; @synthesize previousPoint; @synthesize acceleration; @synthesize ballXVelocity; @synthesize ballYVelocity;

- (id)initWithCoder:(NSCoder *)coder {

if (self = [super initWithCoder:coder]) {

self.image = [UIImage imageNamed:@"ball.png"];

self.currentPoint = CGPointMake((self.bounds.size.width / 2.0f) + (image.size.width / 2.0f),

(self.bounds.size.height / 2.0f) + (image.size.height / 2.0f));

www.it-ebooks.info

668

CHAPTER 19: Whee! Gyro and Accelerometer!

ballXVelocity = 0.0f; ballYVelocity = 0.0f;

}

return self;

}

.

.

.

Now, uncomment the commented-out drawRect: method and give it this simple implementation:

-(void)drawRect:(CGRect)rect {

//Drawing code

[image drawAtPoint:currentPoint];

}

Then add these methods to the end of the class:

.

.

.

#pragma mark -

- (CGPoint)currentPoint { return currentPoint;

}

- (void)setCurrentPoint:(CGPoint)newPoint { previousPoint = currentPoint; currentPoint = newPoint;

if (currentPoint.x < 0) { currentPoint.x = 0; ballXVelocity = 0;

}

if (currentPoint.y < 0){ currentPoint.y = 0; ballYVelocity = 0;

}

if (currentPoint.x > self.bounds.size.width - image.size.width) { currentPoint.x = self.bounds.size.width - image.size.width; ballXVelocity = 0;

}

if (currentPoint.y > self.bounds.size.height - image.size.height) { currentPoint.y = self.bounds.size.height - image.size.height; ballYVelocity = 0;

}

CGRect currentImageRect = CGRectMake(currentPoint.x, currentPoint.y, currentPoint.x + image.size.width,

currentPoint.y + image.size.height);

CGRect previousImageRect = CGRectMake(previousPoint.x, previousPoint.y, previousPoint.x + image.size.width,

currentPoint.y + image.size.width);

www.it-ebooks.info

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