核心運動(1)

介紹:


iOS 應用程序中,嘗試使用加速度計或者陀螺儀之前,必須先檢測應用程序所運行的設備的傳感器是否可用。


我們舉一個簡單的例子,這樣你就可以嘗試找出陀螺儀的價值所在。當你穩穩地拿着終端,坐在一個電腦椅上,順時針或者逆時針旋轉時,終端的加速計是沒辦法在它的垂直軸檢測到終端的旋轉的。從地板或者地球的角度來說,設備正圍繞垂直軸旋轉,但它並沒有圍繞它自己的垂直軸(即終端的垂直軸心)旋轉。因此,加速計此時並不會檢測到任何的動作。

但是,裝備有陀螺儀的 IOS 終端就可以檢測到上面提到過的動作。這就讓我們在檢測終 端運動時更加流暢。這點對於遊戲而言尤其有用,遊戲開發中,開發者不僅要知道由加速計 提供的 x,y,z 軸的信息,而且還要得到終端 x,y,z 軸的變化與地球的相對關係,而這,正是陀螺儀爲我們提供的。


要用Core Motion 框架來訪問加速計和陀螺儀的數據


1.檢測加速計的可用性

1.1. 問題 在你的程序中,你想要檢測加速計硬件是否可用。

1.2. 方案
用 CMMotionManager 的 isAccelerometerAvailable 方法可以檢測加速計硬件,還可以用 於檢測加速計硬件是否正在向程序發送更新。
首先我們要確認我們導入了要求的頭文件。   /ək,selə'rɒmɪtə/ 加速計

#import <CoreMotion/CoreMotion.h>

然後我們就可以在我們應用的代理實現類中進行加速計的可用性檢測了。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    CMMotionManager *motionManager = [[CMMotionManager alloc]init];

    if ([motionManager isAccelerometerAvailable]) {

        NSLog(@"Accelerometer is available");

    }else{

        NSLog(@"Accelerometer is not available");

    }

    if ([motionManager isAccelerometerActive]) {

        NSLog(@"Accelerometer is active");

    }else{

        NSLog(@"Accelerometer is not active");

    }

    return YES;

}


1.3. 討論
一部 iOS 終端可能有一個內置的加速計。由於我們不能確定某個 iOS 終端是否裝備有內 置加速計,所以我們最好在用前檢測一下可加速計是否可用。
要檢測加速計硬件的可用性,你可以實例化一個 CMMotionManager 的對象並訪問它的isAccelerometerAvailable 方法。這個 BOOL 類型的方法在加速計可用時會返回 YES,反之返 回 NO。
另外,你可以通過 CMMotionManager 的 isAccelerometerAvailable 方法來檢測加速計是否在向你的程序發送更新(即是否是激活的)。你會在 3 小節中學習如何獲取加速計的數據。


2.檢測陀螺儀的可用性

2.1. 問題
想要知道運行你程序的當前 iOS 終端的陀螺儀是否可用。

2.2. 方案
用 CMMotionManager 的實例方法 isGyroAvailable 可以檢測陀螺儀硬件的可用性。 isGyroActive 方法還可以檢測陀螺儀是否在向你的程序發送更新(即是否是激活的)。

 if ([motionManager isGyroAvailable]) {

        NSLog(@"Gyro is available");

    }else{

        NSLog(@"Gyro is not available");

    }

    if ([motionManager isGyroActive]) {

        NSLog(@"Gyro is active");

    }else{

        NSLog(@"Gyro is not active");

    }


2.3. 討論
要是你打算髮布一款會使用陀螺儀的應用,你要保證 iOS 終端在沒有陀螺儀硬件時也可以跑你的應用。比如,當你把陀螺儀作爲你的遊戲的一部分時,你要確保版本匹配的終端即便沒有安裝陀螺儀也可以玩這個遊戲。



3.獲取加速計的數據

3.1. 問題
如果你想讓 iOS 向你的應用發送加速計的數據。

3.2. 方案
使用 CMMotionManager 的實例方法:startAccelerometerUpdatesToQueue:withHandler:。 下面是使用 CMMotionManager 獲取加速計更新的試圖控制器的頭文件:

#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface ViewController : UIViewController


@property (nonatomic ,strong)CMMotionManager *motionManager;


@end



下面我們將實現我們的視圖控制器並使用 CMMotionManager 類的 startAccelerometerUpdatesToQueue:withHandler:方法:


- (void)viewDidLoad {

    [super viewDidLoad];

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

    if ([self.motionManager isAccelerometerAvailable]) {

        NSOperationQueue *queue = [[NSOperationQueue alloc]init];

        [self.motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {

            NSLog(@"X = %.04f, Y = %.04f, Z = %.04f",

                  accelerometerData.acceleration.x,

                  accelerometerData.acceleration.y,

                  accelerometerData.acceleration.z);

        }];

    }

}


3.3. 討論
加速計會報告三維數據(三個軸),即iOS會向你的程序報告x, y, z軸的值。這些值是封裝在一個 CMAcceleration 構造器中的。

理解加速計硬件報告的這些值的最好方法就是看些例子。下面就有一個例子:我們假設 你拿着一臺 iOS 終端,它的屏幕對着你,底部朝向地面,頂部指向上面。要是你可以向剛剛 說的那樣拿的很穩,沒有任何偏移的話,你此時得到 x, y, z 軸的值會是( x:0.0, y:-1.0, z:0.0) 。現在你再上面姿勢的基礎上再做下下面的動作:

1. 讓設備順時針旋轉 90 度。此刻你得到的值將是:( x:+1.0, y:0.0, z:0.0)
2. 讓設備再順時針旋轉 90 度。現在終端的頂部一定是指向地面的。此刻你得到的值將是:( x:0.0, y:+1.0, z:0.0)
3. 讓設備再順時針旋轉 90 度。現在終端的頂部一定是指向左邊的。此刻你得到的值將是:( x:-1..0, y:0.0, z:0.0)
4. 最後設備再順時針旋轉 90 度。現在終端的再次底部朝向地面,頂部指向上面。此刻你得到的值將是:( x:0.0, y:-1.0, z:0.0)
從這些值中,我們可以看到終端繞着 z 軸轉時加速計報告 x 和 y 值改變了,z 值不變

我們來做另外一個實驗。首先還是讓終端的屏幕對着你,底部朝向地面,頂部指向上 面。如你所知,此時得到 x, y, z 軸的值會是( x:0.0, y:-1.0, z:0.0) 。現在再做下下面的動作:
1. 讓終端沿着 x 軸向後翻轉 90 度,此時它的頂部會指向後面。換句話說,像把它放在 桌子上並且面朝上那樣拿着它。此刻你得到的值將是:( x:0..0, y:0.0, z:-1.0)
2. 現在讓終端沿着 x 軸再向後翻轉 90 度,此時它的後面會朝向你,它的頂部指向地 面,底部指向天空。此刻你得到的值將是:( x:0..0, y:1.0, z:0.0)
3. 讓終端沿着 x 軸再向後翻轉 90 度,此時它的正面會朝向地面,它的反面指向天空, 頂部指向你。此刻你得到的值將是:( x:0..0, y:0.0, z:1.0)
4. 最後,你再向同樣的方向做一次,此時它的屏幕對着你,底部朝向地面,頂部指向天 空。你得到的值會跟剛開始的時候是一樣的。

因此,我們觀察到當沿着它的 x 軸旋轉時,y 軸跟 z 軸的值會改變,而 x 軸的則不變。 我鼓勵你嘗試一下第三種旋轉的方式—繞着它的y軸(從頂部到底部)旋轉—並觀察x, z軸 的值的變化。



要接收加速計的更新,你有兩個選項:
1. CMMotionManager 的實例方法:startAccelerometerUpdatesToQueue:withHandler:
這個方法會把加速計的更新信息傳遞給一個操作隊列(一種 NSOperationQueue 隊列)並需要有一些 Grand Central Dispatch(GCD)的關於塊的基礎知識。

2. CMMotionManager 的實例方法:startAccelerometerUpdates:withHandler:
一旦你調用了這個方法,加速計(如何可用的話)就會開始在動作管理對象中更 新加速計數據。你需要設置你自己的線程來不斷讀取 CMMotionManager 類的 (類型爲 CMAccelerometerData 的)accelerometerData 屬性的值。



4.檢測iOS設備的搖晃

4.1. 問題
你如果想知道用戶何時晃動了 iOS 終端

4.2. 方案
使用你的應用的窗口對象的 motionEnded:withEvent:方法

4.3. 討論
當 iOS 終端捕獲到一個動作時,你應用的窗口的 motionEnded:withEvent:方法就會被調用。下面是這個方法的簡單實現:

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{

    

if (motion == UIEventSubtypeMotionShake) {

        NSLog(@"Detected a shake");

    }

}

typedef NS_ENUM(NSInteger, UIEventSubtype) {

    // available in iPhone OS 3.0

    UIEventSubtypeNone                              = 0,

    

    // for UIEventTypeMotion, available in iPhone OS 3.0

    UIEventSubtypeMotionShake                       = 1,

    

    // for UIEventTypeRemoteControl, available in iOS 4.0

    UIEventSubtypeRemoteControlPlay                 = 100,

    UIEventSubtypeRemoteControlPause                = 101,

    UIEventSubtypeRemoteControlStop                 = 102,

    UIEventSubtypeRemoteControlTogglePlayPause      = 103,

    UIEventSubtypeRemoteControlNextTrack            = 104,

    UIEventSubtypeRemoteControlPreviousTrack        = 105,

    UIEventSubtypeRemoteControlBeginSeekingBackward = 106,

    UIEventSubtypeRemoteControlEndSeekingBackward   = 107,

    UIEventSubtypeRemoteControlBeginSeekingForward  = 108,

    UIEventSubtypeRemoteControlEndSeekingForward    = 109,

};



5.獲取陀螺儀的數據

5.1. 問題
如果你想讓 iOS 向你的應用發送加速計的數據。

5.2. 方案
遵循下列步驟:
1. 判斷iOS終端的陀螺儀硬件是否可用。

2. 如果陀螺儀硬件可用,確保它已經在爲你發送更新。 


3. 使用 CMMotionManager 類的實例方法 setGyroUpdateInterval:來設置每秒你想接收到的更新信息數。例如,要設置爲 20 條更新信息每秒,那麼值就設置爲 1.0/20.0。

4. 調用 CMMotionManager 類的實例方法 startGyroUpdatesToQueue:withHandler:.這個隊列對象可以簡單作爲主操作隊列並且處理塊必須遵循
CMGyroHandler 的格式。下面是上述步驟的代碼實現:

if ([motionManager isGyroAvailable]) {

        if ([motionManager isGyroActive] == NO) {

            [motionManager setGyroUpdateInterval:1.0f/40.0f];

            NSOperationQueue *queue = [[NSOperationQueue alloc]init];

            [motionManager startGyroUpdatesToQueue:queue withHandler:^(CMGyroData *gyroData, NSError *error) {

                NSLog(@"Gyro Rotation x = %.04f", gyroData.rotationRate.x);

                NSLog(@"Gyro Rotation y = %.04f", gyroData.rotationRate.y);

                NSLog(@"Gyro Rotation z = %.04f", gyroData.rotationRate.z);

            }];

        }

    }

5.3. 討論


調用 CMMotionManager 的實例方法 setGyroUpdateInterval:來設置你想要 每秒從陀螺儀硬件接收到的更新信息數。例如,你想要每秒接收到 N 條更新信息,那麼就 設值爲 1.0/N。
設置完更新間隔後,你就可以調用 CMMotionManager 的實例方法 startGyroUpdatesToQueue:withHandler:來爲更新設置一個處理塊了。要了解更多關於塊的信 息,請參閱第五章。你的塊對象類型必須爲 CMGyroHandler,接收兩個參數:
gyroData
來自陀螺儀硬件的數據,包含在一個 CMGyroData 類型的對象中。你可以使用CMGyroData 的 rotationRate 屬性來訪問數據的 x, y, z 值,它代表了 3 個歐拉角,即旋轉,傾 斜和平搖。你可以閱讀飛行動力學來了解更多相關信息。
Error: 當陀螺儀在給我們發送更新數據時可能會產生一個 NSError 類型的錯誤。


要是你不想使用塊對象,你必須調用 CMMotionManager 的實例方法 startGyroUpdates 來替代 startGyroUpdatesToQueue:withHandler:實例方法,並設置你自己的線程來持續讀取你使 用的 CMMotionManager 實例的,gyroData 屬性發布的陀螺儀硬件更新信息。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章