1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Lập trình iPhone part 15 pdf

22 292 0
Tài liệu được quét OCR, nội dung có thể không chính xác

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Whee! iPhone accelerometer
Thể loại Chapter
Định dạng
Số trang 22
Dung lượng 723,39 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The iPhone OS uses the accelerometer to handle autorotation, and many games use it as a control mechanism.. iPhone, the accelerometer will detect a greater amount of force on one or more

Trang 1

Whee!

ne of the coolest features of the iPhone and iPod Touch is the built-in acceler-

ometer, the tiny device that lets the iPhone know how it’s being held and if it’s

being moved The iPhone OS uses the accelerometer to handle autorotation,

and many games use it as a control mechanism It can also be used to detect

shakes and other sudden movement

Accelerometer Physics

An accelerometer measures both acceleration and gravity by sensing the

amount of inertial force in a given direction The accelerometer inside iPhone

is a three-axis accelerometer, meaning that it is capable of detecting either

movement or the pull of gravity in three-dimensional space As a result, you

can use the accelerometer to tell not only how the phone is currently being

held (as autorotation does) but also if it’s laying on a table and even whether it’s face down or face up

“Uw

Accelerometers give measurements in g-forces (“g” for gravity), so a value of 1.0 returned by the accelerometer means that 1 g is sensed in a particular

direction If the iPhone is being held still with no movement, there will be

approximately 1 g of force exerted on it by the pull of the earth If the iPhone

is being held upright, in portrait orientation, the iPhone will detect and report about 1 g of force exerted on its y axis If the iPhone is being held at an angle,

that 1 g of force will be distributed along different axes depending on how the iPhone is being held When held at a 45-degree angle, that 1 g of force will be split roughly equally between two of the axes

Sudden movement can be detected by looking for accelerometer values con-

siderably larger than 1 g In normal usage, the accelerometer does not detect

significantly more than 1 g on any axis If you shake, drop, or throw your

Trang 2

iPhone, the accelerometer will detect a greater amount of force on one or more axes Please

do not drop or throw your own iPhone just to test this theory

You can see a graphic representation of the three axes used by iPhone's accelerometer in

Figure 15-1 One thing to notice is that the accelerometer uses the more standard conven-

tion for the y coordinate, with increases in y indicating upward force, which is the opposite

of Quartz 2D’s coordinate system When you are using the accelerometer as a control mecha- nism with Quartz 2D, you have to translate the y coordinate When working with OpenGL ES, which you are more likely to be using if you are using the accelerometer to control anima- tion, no translation is required

Figure 15-1 The ¡Phone accelerometer S axes in three dimensions

Accessing the Accelerometer

The UIAccelerometer class exists as a singleton To retrieve a reference to the class, call the method sharedAccelerometer, like so:

Trang 3

Getting information from the accelerometer is similar to getting information from Core Location You create a class that conforms to the UIAccelerometerDel egate protocol, implement a method to which the accelerometer will provide information, and specify an instance of that class to be the accelerometer’s delegate

When you assign a delegate, you need to specify an update interval in seconds iPhone’s accelerometer supports polling at a rate of up to 100 times per second, although there is

no guarantee that it will actually update you that many times or that those updates will be exactly evenly spaced To assign a delegate and specify a polling interval of 60 times per second, you would do this:

accelerometer.delegate = self;

Once you've done that, all that’s left is to implement the method that the accelerometer uses

to update its delegate, accelerometer: didAccelerate: This method takes two arguments The first is a reference to the shared UIAccelerometer instance The second contains the actual data from the accelerometer, embedded in an object of the class UIAcceleration Before we look at the delegate method, let’s talk about the UIAccel eration object that’s used to pass the information to the delegate

UlAcceleration

We mentioned earlier that the iPhone's accelerometer detects acceleration along three axes, and it provides this information to the delegate using instances of the UIAcceleration class Each UIAcceleration instance has an x, y, and z property, each of which holds a signed float-

ing 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 neg- ative value for y indicates that downward pull is sensed, which is probably an indication that the phone is being held upright in portrait orientation A positive value for y indicates some force is being exerted in the opposite direction, which could mean the phone is being held upside down or that the phone is being moved in a downward direction

Keeping the diagram in Figure 15-1 in mind, let's look at some accelerometer results Note

that, in real life, you will almost never get values this precise, as the accelerometer is sensi- tive enough to pick up even tiny amounts of movement, and you will usually pick up at least

some tiny amount of force on all three axes This is real-world physics and not high school

physics lab

Trang 4

X:0.0 y:-1.0 Z:0.0

x;1.0 y:0.0 z:0.0

X30.0 ÿ‡1‹0 Z?70:0 » ;=1.,0 y:0.0 z:0.0

S——— x:0.0 y:0.0 z:-1.0

a x:¿ooy:o.oz:i.o

Figure 15-2 Idealized acceleration values for different device orientations

Implementing the accelerometer:didAccelerate: Method

In order to receive accelerometer information, the class you specify as the accelerometer’s delegate needs to implement the accelerometer: didAccelerate: method If you wanted

to display the acceleration values in a UILabel, you would implement that method like this:

Trang 5

- (void)accelerometer: (UIAccelerometer *)accelerometer

didAccelerate: (UIAcceleration *)acceleration {

NSString *newText = [[NSString alloc]

initWwithFormat:@"Max: x: %g\ty:%g\tz:%g", acceleration.x,

To check for a shake, check for an absolute value greater than 1.5 for a slight shake and 2.0 for a strong shake, like this:

- (void)accelerometer: (UIAccelerometer *)accelerometer

didAccelerate: (UIAcceleration *)acceleration {

- (void)accelerometer: (UIAccelerometer *)accelerometer

didAccelerate: (UIAcceleration *)acceleration {

Trang 6

static NSInteger shakeCount = 0;

static NSDate *shakeStart;

NSDate *now = [[NSDate alloc] init];

NSDate *checkDate = [[NSDate alloc] initWithTimeInterval:1.5f

sinceDate: shakeStart] ;

if C[now compare: checkDate] ==

NSOrderedDescending || shakeStart == nil) {

shakeStart = [[NSDate alloc] init];

This method keeps track of the number of times the accelerometer reports a value above 2, and if it happens four times within a second and a half span of time, it registers as a shake

Accelerometer as Directional Controller

Probably the most common usage of the accelerometer in third-party applications is as

a controller for games 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

iPhone 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 is going to 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 have to make adjustments to the velocity of the controlled object based on the values returned from the accelerometer

Trang 7

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 accelerometer to update your delegate class 60 times a second, all that you can say for sure is that it won't update you 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 have to keep track of the time that passes between delegate method calls

We'll create a program that uses the accelerometer for input a little later in the chapter, but

first, we're going to break your phone

Shake and Break

OK, we're not really going to break your phone, but we're going to write an application that

detects shakes and then makes your phone look and sound like it broke as a result of the shake When you launch the application, the program will display a picture that looks like the iPhone home page (see Figure 15-3)

Shake the phone hard

enough, though, and your

poor phone will make

a sound that you never

want to hear coming out

of a consumer electronics

device What's more, your

screen will look like the one

shown in Figure 15-4 Why

do we do these evil things?

Not to worry You can reset

the iPhone to its previously

pristine state by touching

the screen Figure 15-3 The ShakeAnd- Figure 15-4 but handle it

innocuous enough

Trang 8

The Code That Breaks

Create a new project in Xcode using the view-based application template Call the new proj- ect ShakeAndBreak In the 75 ShakeAnaBreak folder of the project archive, we've provided you the two images and the sound file you need for this application, so drag home.png, homebroken.png, and glass.wav to the Resources folder of your project There’s also an icon

png in that folder Add that to the Resources folder as well

Next, expand the Resources folder, and single-click info.plist We need to add an entry to the property list to tell our application not to use a status bar, so single-click the row that says Information Property List, and click the button that appears at the end of the row to add a new

child Change the new row’s Key to U/StatusBarHidden Now, control-click (or right-click if you

have a two-button mouse) the empty Value column in the row you just added A contextual menu should appear (see Figure 15-5) From that menu, select the Value Type submenu, and then select Boolean The row should change to have a checkbox Click the checkbox so that it

is checked Finally, type icon.png in the Value column next to the /con file key

Localization native development re en Copy

Bundle display name - ${PROE Paste

Executable file ${EXEC

Icon file Shift Row Right

InfoDictionary version 6.0

Bundle creator OS Type code 777? Add Row

Bundle version 1.0 Show Raw Keys/Values

LSRequiresIPhoneOS ww Data

Reveal in Finder Number

Reveal in Group Tree v String

Add to Bookmarks Get Info

Figure 15-5 Changing the Value Type for UIStatusBarHidden

Now, expand the Classes folder We’re going to need to create an outlet to point to an image view so that we can change the displayed image We'll also need a couple of UIImage instances to hold the two pictures, a sound ID to refer to the sound, and a Boolean to keep track of whether the screen needs to be reset Single-click ShakeAndBreakViewController.h, and add the following code:

Trang 9

@property Cnonatomic, retain) UIImageView *imageView;

@property Cnonatomic, retain) UIImage *fixed;

@property Cnonatomic, retain) UIImage *broken;

@end

In addition to the instance variables and properties, notice that we’ve conformed the class

to the UIAccelerometerDelegate protocol and defined two constants, one for the update frequency and the other to define how many g-forces the accelerometer has to detect before

it qualifies as a shake We've defined the update frequency at a fairly low frequency of ten

updates a second, which is sufficient for detecting a shake Generally, you want to poll at the

lowest frequency that will meet your needs When using the accelerometer as a controller, you'll need to poll at a considerably faster rate, usually between 30 and 60 updates per second Save the header file, and double-click ShakeAndBreakViewController.xib to open the file in Interface Builder Single-click the View icon, and press 883 to bring up the size inspector Change the view's height from 460 to 480 so that it takes up the additional screen space made available by getting rid of the status bar Drag an Image View over from the library

to the window labeled View The image view should automatically resize to take up the full window, so just place it so that it sits perfectly within the window

Control-drag from the File’s Owner icon to the image view, and select the imageView outlet Now save and close the nib file, and go back to Xcode When you get there, single-click the ShakeAndBreakController.m file, and make the following changes:

NSString *path = [L[LNSBundle mainBundle] pathForResource:@"glass"

ofType: @"wav"];

Trang 10

AudioServicesCreateSystemSoundID(C(CFURLRef) [NSURL

fileURLWithPath: path], &soundID);

self.fixed = [UIImage imageNamed:@"home.png"] ;

self.broken = [UIImage imageNamed:@"homebroken.png"];

imageView.image = fixed;

brokenScreenShowing = NO;

(BOOL) shouldAutorotateToInterfaceOrientation:

(UIInterfaceOrientation)interfaceOrientation {

// Return YES for supported orientations

return CinterfaceOrientation == UIInterfaceOrientationPortrait);

(void) didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Releases the view if it doesn't have a superview

// Release anything that's not essential, such as cached data (void)dealloc {

- (void) accelerometer: (UIAccelerometer *)accelerometer

didAccelerate: (UIAcceleration *)acceleration {

Trang 11

The first method we implement is vi ewDidLoad, where we get a reference to the shared accelerometer instance, set self to be the accelerometer’s delegate, and then set the update frequency using the constant we defined earlier:

UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];

accel.delegate = self;

accel.updateInterval = kUpdatelInterval;

Load the Simulation Files

Next, we load the glass sound file into memory and save the assigned identifier in the soundID instance variable

NSString *path = [L[NSBundle mainBundle] pathForResource:@"glass"

ofType:@"wav”];

fileURLWithPath:path], &soundID);

We then load the two images into memory:

self.fixed = [UIImage imageNamed:@"home.png"] ;

self.broken = [UIImage imageNamed:@"homebroken.png"] ;

Finally, we set imageVi ew to show the unbroken screenshot and set brokenScreenShowing

to NO to indicate that the screen does not currently need to be reset:

imageView.image = fixed;

brokenScreenShowing = NO;

The next new method is the accelerometer delegate method In it, we check

brokenScreenShowing If it is NO, we know the screen is already showing the broken

image, so we don’t want to do anything

if C! brokenScreenShowing) {

Otherwise, we check all three of the axes passed in and see if any of them exceed the accel- eration threshold we defined earlier If any of the three axes do, we set the image view to

show the broken image, play the sound, and set brokenScreenShowing to YES so that we

don't do this again until the user has reset the screen:

if Cacceleration.x > kAccelerationThreshold || acceleration.y > kAccelerationThreshold || acceleration.z >

kAccelerationThreshold) {

imageView.image = broken;

AudioServicesPlaySystemSound CsoundTD);

brokenScreenShowing = YES;

Ngày đăng: 26/01/2014, 10:20

TỪ KHÓA LIÊN QUAN