cocos2d環境で、画面回転とカメラビューを共存させる方法

| コメント(0) | トラックバック(0)
こんにちは。開発担当のICTFです。

coco2dでゲーム画面を作成しています。
ゲーム機能の1つとして写真を撮影する必要があり、RootViewControllerを親としてUIImagePickerControllerをModal表示していたのですが、困った現象が起こりました。
撮影画面を表示中に画面を回転させると、撮影画面自体は正常に動作するのですが、裏のcocos2dレイヤーが縦横比が狂った状態で固まってしまうのです。
ログビューにもOpenGLの描画失敗関連のエラーが大量に発生します。
画面全体が1枚の絵のようになってしまい、もちろん貼付けているボタンなども反応しません。
UIImagePickerControllerをModalではなく、AddSubviewした場合はcocos2dレイヤーに問題が発生しませんので、予想ですが恐らく撮影画面をModal表示する事でcocos2d側に画面回転の通知が届かなくなり、結果として「画面横のつもりで描画してみた⇒実は画面縦だった⇒エラー」という流れになっているのではないでしょうか。

上でAddSubviewだと問題無しという表現をしましたが、実はAddSubviewした場合撮影画面の動作がおかしくなってしまいます。
撮影画面を開いた状態で画面を回転させると、iPhoneに表示されている風景画像までもが回転してしまうのです。ですので、やはり撮影画面はModal表示する事が前提に作られているようです。

最終的に撮影画面を表示中は、cocos2d側の画面回転を禁止すれば良いという結論に至り、RootViewControllerに画面回転を抑制する為の機能を盛り込みました。
ついでに単純に画面回転を禁止するだけではなく、動的に「縦のみ」「横のみ」「全方向
」を切換えられるようにもしました。
どちらかというと画面回転抑制機能の実装が今回の主題に近いかもしれません。

RootViewController.hに画面の方向を指す以下の定数を列挙します。

typedef enum {

eOrientationMode_INVALID,

eOrientationMode_Full,

eOrientationMode_Portrait,

eOrientationMode_Landscape,

eOrientationMode_COUNT

} eOrientationMode;


INVALIDとCOUNTは単に私の癖ですので、無くても構いません。
次に、クラスの定義を以下のようにします。

@interface RootViewController : UIViewController

<

UIImagePickerControllerDelegate

, UINavigationControllerDelegate

>

{

BOOL m_isOrientationLock;

eOrientationMode m_OrientationMode;

}


@property (nonatomic, readwrite) BOOL isOrientationLock;

@property (nonatomic, readwrite) eOrientationMode OrientationMode;


isOrientationLockは画面方向のロック状態を表します。
このフラグがYESの場合、どのような状況でも画面回転を許可しません。
OrientationModeは上で定義した列挙子を用います。
Fullは、どの画面方向も許可します。
Landscapeは、画面が横の場合のみ許可します。
Portraitは、画面が縦の場合のみ許可します。

最後にRootViewController.mに画面回転制御の実処理を組み込みます。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

//

// There are 2 ways to support auto-rotation:

//  - The OpenGL / cocos2d way

//     - Faster, but doesn't rotate the UIKit objects

//  - The ViewController way

//    - A bit slower, but the UiKit objects are placed in the right place

//

#if GAME_AUTOROTATION==kGameAutorotationNone

//

// EAGLView won't be autorotated.

// Since this method should return YES in at least 1 orientation, 

// we return YES only in the Portrait orientation

//

return ( interfaceOrientation == UIInterfaceOrientationPortrait );

#elif GAME_AUTOROTATION==kGameAutorotationCCDirector

//

// EAGLView will be rotated by cocos2d

//

// Sample: Autorotate only in landscape mode

//

if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft ) {

[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeRight];

} else if( interfaceOrientation == UIInterfaceOrientationLandscapeRight) {

[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeLeft];

}

// Since this method should return YES in at least 1 orientation, 

// we return YES only in the Portrait orientation

return ( interfaceOrientation == UIInterfaceOrientationPortrait );

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController

//

// EAGLView will be rotated by the UIViewController

//

// Sample: Autorotate only in landscpe mode

//

// return YES for the supported orientations

if (m_isOrientationLock) {

return NO;

}

switch (m_OrientationMode) {

case eOrientationMode_INVALID:

return NO;

break;

case eOrientationMode_Full:

return YES;

break;

case eOrientationMode_Portrait:

return ( UIInterfaceOrientationIsPortrait(interfaceOrientation) );

break;

case eOrientationMode_Landscape:

return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) );

break;

default:

return NO;

break;

}

#else

#error Unknown value in GAME_AUTOROTATION

#endif // GAME_AUTOROTATION

// Shold not happen

return NO;

}


使い方は、UIImagePickerCoontrollerをModal表示する前にRootViewController.isOrientationLockにYESを設定し、撮影画面が消え次第NOに戻すだけです。

トラックバック(0)

トラックバックURL: http://www.ict-fractal.com/MovableType/mt/mt-tb.cgi/16

コメントする

Twitterボタン
Twitterブログパーツ