IOS 特定於裝置的開發:使用加速器啟動螢幕上的物件

haibo wang發表於2014-12-23

藉助一點程式設計工作,iPhone的機載加速計就可以使物件在螢幕上四處“移動”,實時響應使用者傾斜手機的方式。下面的程式碼就是建立一個動畫式的蝴蝶,使用者可以使之快速移過螢幕。

使之工作的祕密在於:向程式中新增一個所謂的"物理計時器“。他不是直接響應加速中的變化,而是加速計回撥用於測量當前的力。它取決於計時器例程隨著 時間的推移通過改變他的畫面對蝴蝶應用那些力。下面是列出要記住的關鍵點。

   (1).只要力的方向仍然保持相同,蝴蝶就會加速。他的速度會依據加速力在x或y方向上的量度成比例的提高。

   (2).由計時器用的rick例程將通過蝴蝶的原點新增速度向量來移動蝴蝶。

   (3).蝴蝶移動的範圍是有界限的,因此,當他撞到某個邊緣時,將會停止那個方向的移動。還可以一直講蝴蝶保留在螢幕中。tick方法將會檢查界限條件。

   (4).蝴蝶會改變它自身的方向,使之總是下落。可以在tick方法中應用一個簡單的旋轉變換來實現這一點。在使用變換時,還要關注畫面或中心偏移。在應用偏移之前,總是要重置數學處理,然後重新應用任何角度改變。不這樣的話,可能導致畫面出人意料的放大,收縮或扭曲。

程式碼如下:

#define SIGN(_NUM_) ((_NUM_ < 0) ? (-1) : 1)
#define RECTCENTER(RECT) CGPointMake(CGRectGetMidX(RECT), CGRectGetMidY(RECT))

@interface ViewController ()
{
    UIImageView *butterfly;
    
    float xaccel;
    float xvelocity;
    float yaccel;
    float yvelocity;
    
    float mostRecentAngle;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor greenColor];
    [self initButterfly];
    }


- (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];
}

- (void) tick
{
    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;
    
    butterfly.transform = CGAffineTransformMakeRotation(mostRecentAngle + M_PI_2);
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    // extract the acceleration components
    float xx = -acceleration.x;
    float yy = acceleration.y;
    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;
}

 

相關文章