cocos2dをPortraitとLancscapeの両方に対応させる方法/C言語のマクロ

今週は別の仕事に集中していたため、あまり勉強は進んでいないのですが、cocos2dのサンプルアプリである[Hello World!]



内の「GameConfig.h」ファイル内に以下のようなコードが存在していて、

#ifndef __GAME_CONFIG_H
#define __GAME_CONFIG_H

//
// Supported Autorotations:
//		None,
//		UIViewController,
//		CCDirector
//
#define kGameAutorotationNone 0
#define kGameAutorotationCCDirector 1
#define kGameAutorotationUIViewController 2

//
// Define here the type of autorotation that you want for your game
//
#define GAME_AUTOROTATION kGameAutorotationUIViewController


#endif // __GAME_CONFIG_H

#defineがでてきた時点で「??」という感じだったので、C言語の本や、ネットで調べた「マクロ」ついてまとめてみます。

マクロの基本

5人分のテスト結果を表示させるプログラム↓

#include <stdio.h>

int main(void)

{
     int test[5] = {80,60,22,50,75};
     int i;

     for(i=0, i<5 i++) {
          printf("%D番目の人の点数は%dです。\n",i+test[i]);
     }

    return 0;
}

↑だと、人数が変わったときに

test[5]
for文内の i<5

やらを変更しなくてはならないし、もっと大きなプログラムになると直すのが大変になってくる。
そこで、#define をを用いる↓

#include <stdio.h>
#define NUM 5

int main(void)
{
     int test[NUM] = {80,60,22,50,75};
     int i;

     for(i=0, i<NUM i++) {
          printf("%D番目の人の点数は%dです。\n",i+test[i]);
     }

    return 0;
}

とすることで、

#define NUM 5

の部分だけ編集すればおkになる。

デバック時にマクロを用いる

#include <stadio.h>
#define DEBUG

int main(void)
{
     int i;
     int sum = 0;
     for (i=i, i<=5, i++) {
          #ifdef DEBUG
             fprint(stderr,"変数sumの値は%dとなっています。\n",sum);
          #endif
          sum = i + sum;
     }
     printf("1~5までの合計値は%dです。\n",sum);

return 0;
}

#define DEBUG

が定義されている場合は、

#ifdef DEBUG

以下のコードがコンパイル時にはしり、
定義されていなかった場合には、

#endif

以下の文字がはしる。

他にも以下のような種類があるみたいです。

#ifdef マクロ
  文:
       ・・・
#endif
#if 式1
  文:
       ・・・
#elif 式2
  文:
       ・・・
#else
  文:
       ・・・
#endif

cocos2dで最初に作ったサンプルアプリである[Hello World!]を、Portraitモードにも対応させる方法。

そしていよいよ本題ですが、

プロジェクト内の「GameConfig.h」ファイルを見てみると、

#ifndef __GAME_CONFIG_H
#define __GAME_CONFIG_H

//
// Supported Autorotations:
//		None,
//		UIViewController,
//		CCDirector
//
#define kGameAutorotationNone 0
#define kGameAutorotationCCDirector 1
#define kGameAutorotationUIViewController 2

//
// Define here the type of autorotation that you want for your game
//
#define GAME_AUTOROTATION kGameAutorotationUIViewController


#endif // __GAME_CONFIG_H

となっており、

//
// Define here the type of autorotation that you want for your game
//
#define GAME_AUTOROTATION kGameAutorotationUIViewController

の部分から推測するに、iPhoneを回転させたときに表示を変更するよう指令をだしているのは、ViewControllerクラスと予測をたててみた。

そうすると案の上、viewcontrollerファイル内に以下のメソッドを発見

// Override to allow orientations other than the default portrait orientation.
- (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
	//
	return NO;
	
#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];
	}
	
	return NO;

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController
	//
	// EAGLView will be rotated by the UIViewController
	//
	// Sample: Autorotate only in landscpe mode
	//
	// return YES for the supported orientations
	if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
	   interfaceOrientation == UIInterfaceOrientationLandscapeRight )
		return YES;
	
	// Unsupported orientations:
	// UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown
	return NO;
	
#else
#error Unknown value in GAME_AUTOROTATION
	
#endif // GAME_AUTOROTATION

	
	// Shold not happen
	return NO;
}

このメソッドで判定しているみたい。

#define GAME_AUTOROTATION kGameAutorotationUIViewController

と「GameConfig.h」内で定義していたので、

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController
	//
	// EAGLView will be rotated by the UIViewController
	//
	// Sample: Autorotate only in landscpe mode
	//
	// return YES for the supported orientations
	if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
	   interfaceOrientation == UIInterfaceOrientationLandscapeRight )
		return YES;
	
	// Unsupported orientations:
	// UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown
	return NO;

の部分のコードがコンパイル時にはしっていると予想。


そのため、↓のように変更してみた。

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController
	//
	// EAGLView will be rotated by the UIViewController
	//
	// Sample: Autorotate only in landscpe mode
	//
	// return YES for the supported orientations
	if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft || UIInterfaceOrientationLandscapeRight || UIInterfaceOrientationPortrait || UIInterfaceOrientationPortraitUpsideDown)
		return YES;

と変更してみると、Portrait,Landscapeの両方に対応できました♩


しかし・・・

■Portrait Mode


■Landscape Mode


座標がずれてしまっている。。。
AutoRotationに対応するとコードが複雑になるという噂を聞いていたのですが、こういうことだったのか。。。

おそらく、ViewControllerファイルの

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
	//
	// Assuming that the main window has the size of the screen
	// BUG: This won't work if the EAGLView is not fullscreen
	///
	CGRect screenRect = [[UIScreen mainScreen] bounds];
	CGRect rect;

	if(toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)		
		rect = screenRect;
			
	else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
		rect.size = CGSizeMake( screenRect.size.height, screenRect.size.width );
	
	CCDirector *director = [CCDirector sharedDirector];
	EAGLView *glView = [director openGLView];
	float contentScaleFactor = [director contentScaleFactor];
	
	if( contentScaleFactor != 1 ) {
		rect.size.width *= contentScaleFactor;
		rect.size.height *= contentScaleFactor;
	}
	glView.frame = rect;
}

あたりが臭い気がするので、この辺をいじってみたいと思います。


しかし、、、今日はもう遅いのでこの編で。

C言語

enum
typedef

とかも勉強したいので、後々時間あったらアップしますー