- Accessing Basic Device Information
- Adding Device Capability Restrictions
- Recipe: Checking Device Proximity and Battery States
- Recipe: Recovering Additional Device Information
- Recipe: Using Acceleration to Locate "Up"
- Working with Basic Orientation
- Retrieving the Current Accelerometer Angle Synchronously
- Recipe: Using Acceleration to Move Onscreen Objects
- Recipe: Accelerometer-Based Scroll View
- Recipe: Core Motion Basics
- Recipe: Retrieving and Using Device Attitude
- Detecting Shakes Using Motion Events
- Recipe: Using External Screens
- Tracking Users
- One More Thing: Checking for Available Disk Space
- Summary
Recipe: Using Acceleration to Move Onscreen Objects
With a bit of programming, the iPhone’s onboard accelerometer can make objects “move” around the screen, responding in real time to the way the user tilts the phone. Recipe 1-4 builds an animated butterfly that users can slide across the screen.
The secret to make this work lies in adding what a “physics timer” to the program. Instead of responding directly to changes in acceleration, the way Recipe 1-3 did, the accelerometer callback measures the current forces. It’s up to the timer routine to apply those forces to the butterfly over time by changing its frame. Here are some key points to keep in mind:
- As long as the direction of force remains the same, the butterfly accelerates. Its velocity increases, scaled according to the degree of acceleration force in the X or Y direction.
- The tick routine, called by the timer, moves the butterfly by adding the velocity vector to the butterfly’s origin.
- The butterfly’s range is bounded. So when it hits an edge, it stops moving in that direction. This keeps the butterfly onscreen at all times. The tick method checks for boundary conditions. For example, if the butterfly hits a vertical edge, it can still move horizontally.
- The butterfly reorients itself so it always falling “down.” This happens by applying a simple rotation transform in the tick method. Be careful when using transforms in addition to frame or center offsets. Always reset the math before applying offsets, and then reapply any angular changes. Failing to do so may cause your frames to zoom, shrink, or skew unexpectedly.
Recipe 1-4. Sliding an Onscreen Object Based on Accelerometer Feedback
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { // Extract the acceleration components float xx = -acceleration.x; float yy = acceleration.y; // Store the most recent angular offset mostRecentAngle = atan2(yy, xx); // Has the direction changed? float accelDirX = SIGN(xvelocity) * -1.0f; float newDirX = SIGN(xx); float accelDirY = SIGN(yvelocity) * -1.0f; float newDirY = SIGN(yy); // Accelerate. To increase viscosity lower the additive value if (accelDirX == newDirX) xaccel = (abs(xaccel) + 0.85f) * SIGN(xaccel); if (accelDirY == newDirY) yaccel = (abs(yaccel) + 0.85f) * SIGN(yaccel); // Apply acceleration changes to the current velocity xvelocity = -xaccel * xx; yvelocity = -yaccel * yy; } - (void) tick { // Reset the transform before changing position butterfly.transform = CGAffineTransformIdentity; // Move the butterfly according to the current velocity vector CGRect rect = CGRectOffset(butterfly.frame, xvelocity, 0.0f); if (CGRectContainsRect(self.view.bounds, rect)) butterfly.frame = rect; rect = CGRectOffset(butterfly.frame, 0.0f, yvelocity); if (CGRectContainsRect(self.view.bounds, rect)) butterfly.frame = rect; // Rotate the butterfly independently of position butterfly.transform = CGAffineTransformMakeRotation(mostRecentAngle + M_PI_2); } - (void) initButterfly { CGSize size; // Load the animation cells NSMutableArray *butterflies = [NSMutableArray array]; for (int i = 1; i <= 17; i++) { NSString *fileName = [NSString stringWithFormat:@"bf_%d.png", i]; UIImage *image = [UIImage imageNamed:fileName]; size = image.size; [butterflies addObject:image]; } // Begin the animation butterfly = [[UIImageView alloc] initWithFrame:(CGRect){.size=size}]; [butterfly setAnimationImages:butterflies]; butterfly.animationDuration = 0.75f; [butterfly startAnimating]; // Set the butterfly's initial speed and acceleration xaccel = 2.0f; yaccel = 2.0f; xvelocity = 0.0f; yvelocity = 0.0f; // Add the butterfly butterfly.center = RECTCENTER(self.view.bounds); [self.view addSubview:butterfly]; // Activate the accelerometer [[UIAccelerometer sharedAccelerometer] setDelegate:self]; // Start the physics timer [NSTimer scheduledTimerWithTimeInterval: 0.03f target: self selector: @selector(tick) userInfo: nil repeats: YES]; }