본문 바로가기

프로그래밍/cocos2d

cocos2d와 UIView로 게임 일시정지/플레이 구현하기

cocos2d와 UIView를 함께 사용하는 방법을 학습합니다.

작업 할 파일은 다음과 같습니다.
(1) GameResumeViewController.xib
(2) GameResumeViewController.h
(3) GameResumeViewController.m
(4) GameDemoAppDelegate.h
(5) GameDemoAppDelegate.m
(6) GameLayer.h
(7) GameLayer.m




//

//  GameResumeViewController.h

//  GameDemo

//

//  Created by Chang-Min Pak on 6/15/10.

//  Copyright 2010 thefirstgood.com. All rights reserved.

//


#import <UIKit/UIKit.h>


@class GameLayer;


@interface GameResumeViewController : UIViewController {

    GameLayer *gameLayer

}


// 버튼이 눌렸을 호출됩니다.

- (IBAction) buttonTouchUpHandler:(id)sender;


// GameLayer에서 일시정지 버튼이 눌렸을 GameResumeView 보여주기 위해 사용됩니다.

- (void) showResumeView:(GameLayer*)layer;


@end








//

//  GameResumeViewController.m

//  GameDemo

//

//  Created by Chang-Min Pak on 6/15/10.

//  Copyright 2010 thefirstgood.com. All rights reserved.

//


#import "GameResumeViewController.h"

#import "GameLayer.h"


@implementation GameResumeViewController


/*

 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {

        // Custom initialization

    }

    return self;

}

*/


/*

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad {

    [super viewDidLoad];

}

*/


/*

// Override to allow orientations other than the default portrait orientation.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

    // Return YES for supported orientations

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

*/


- (void)didReceiveMemoryWarning {

    // Releases the view if it doesn't have a superview.

    [super didReceiveMemoryWarning];

    

    // Release any cached data, images, etc that aren't in use.

}


- (void)viewDidUnload {

    [super viewDidUnload];

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

}


- (void) showResumeView:(GameLayer*)layer {

    // buttonTouchUpHandler 메소드에서 사용됩니다.

    gameLayer = layer;

    

    // 현재 뷰를 보여줍니다.

    self.view.hidden = NO;

}


- (IBAction) buttonTouchUpHandler:(id)sender {

    if(self.view.hidden == YES)

        return;

    

    

    // 현재 뷰를 감춥니다.

    self.view.hidden = YES;

    

    // GameLayer resumeGame 메소드를 호출하여 다시 게임이 진행되도록 처리합니다.

    [gameLayer resumeGame];

}


- (void)dealloc {

    [super dealloc];

}



@end









//

//  GameDemoAppDelegate.h

//  GameDemo

//

//  Created by cmpak on 5/11/10.

//  Copyright 2010 thefirstgood.com. All rights reserved.

//


#import <UIKit/UIKit.h>


@class GameResumeViewController;


@interface GameDemoAppDelegate : NSObject <UIApplicationDelegate> {

UIWindow *window;

    

    GameResumeViewController *gameResumeViewController;

}


@property (nonatomic, retain) UIWindow *window;

@property (nonatomic, readonly) GameResumeViewController *gameResumeViewController;


@end









//

//  GameDemoAppDelegate.m

//  GameDemo

//

//  Created by cmpak on 5/11/10.

//  Copyright 2010 thefirstgood.com. All rights reserved.

//


#import "GameDemoAppDelegate.h"

#import "cocos2d.h"

#import "GameScene.h"

#import "GameResumeViewController.h"


@implementation GameDemoAppDelegate


@synthesize window;

@synthesize gameResumeViewController;


- (void) applicationDidFinishLaunching:(UIApplication*)application

{

// Init the window

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

// cocos2d will inherit these values

[window setUserInteractionEnabled:YES];

[window setMultipleTouchEnabled:YES];

// Try to use CADisplayLink director

// if it fails (SDK < 3.1) use the default director

if( ! [CCDirector setDirectorType:CCDirectorTypeDisplayLink] )

[CCDirector setDirectorType:CCDirectorTypeDefault];

// Use RGBA_8888 buffers

// Default is: RGB_565 buffers

[[CCDirector sharedDirector] setPixelFormat:kPixelFormatRGBA8888];

// Create a depth buffer of 16 bits

// Enable it if you are going to use 3D transitions or 3d objects

    // [[CCDirector sharedDirector] setDepthBufferFormat:kDepthBuffer16];

// Default texture format for PNG/BMP/TIFF/JPEG/GIF images

// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565

// You can change anytime.

[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];

// before creating any layer, set the landscape mode

[[CCDirector sharedDirector] setDeviceOrientation:CCDeviceOrientationLandscapeLeft];

[[CCDirector sharedDirector] setAnimationInterval:1.0/60];

[[CCDirector sharedDirector] setDisplayFPS:YES];

// create an openGL view inside a window

[[CCDirector sharedDirector] attachInView:window];

    // cocos2d 돌아가는 EAGLView 위에 GameResumeView 넣습니다.

    gameResumeViewController = [[GameResumeViewController alloc] initWithNibName:@"GameResumeViewController" bundle:nil];

    

    gameResumeViewController.view.frame = CGRectMake(0, 0, 480, 320);

    gameResumeViewController.view.hidden = YES;

    

    // view 옆으로 돌립니다.

    gameResumeViewController.view.transform = CGAffineTransformIdentity;

    CGFloat radian = M_PI * 90 / 180.0;

    gameResumeViewController.view.transform = CGAffineTransformMakeRotation(radian);

    

    // super 뷰와 center 같게 맞춥니다.

    gameResumeViewController.view.center = window.center;

    gameResumeViewController.view.bounds = CGRectMake(0, 0, 480, 320);

    

    [window addSubview:gameResumeViewController.view]; 

    

[window makeKeyAndVisible];

    

    GameScene *gameScene = [[GameScene alloc] init];

    [[CCDirector sharedDirector] runWithScene:(CCScene*)gameScene];

    [gameScene release];

}



- (void)applicationWillResignActive:(UIApplication *)application {

[[CCDirector sharedDirector] pause];

}


- (void)applicationDidBecomeActive:(UIApplication *)application {

[[CCDirector sharedDirector] resume];

}


- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {

[[CCTextureCache sharedTextureCache] removeUnusedTextures];

}


- (void)applicationWillTerminate:(UIApplication *)application {

[[CCDirector sharedDirector] end];

}


- (void)applicationSignificantTimeChange:(UIApplication *)application {

[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];

}


- (void)dealloc {

[[CCDirector sharedDirector] release];

[window release];

[super dealloc];

}


@end








//

//  GameLayer.h

//  GameDemo

//

//  Created by cmpak on 5/10/10.

//  Copyright 2010 thefirstgood.com. All rights reserved.

//


#import "cocos2d.h"


// 적이 쓰러질 방향

typedef enum {

    kFallRight,

    kFallLeft

}FallDirection;


// 현재 게임 진행 상황

typedef enum {

    kGamePlaying,

    kGamePaused

}GameStatus;


@class EnergyBar;


@interface GameLayer : CCLayer {

    CGSize winSize;

    

    // 방향 전환에 쓰일 버튼

    // 눌리기 전과 눌렸을 때에 있도록 방향별로 두개씩 만든다.

    CCSprite  *rightSprite;

    CCSprite  *rightPressedSprite;

    CCSprite  *leftSprite;

    CCSprite  *leftPressedSprite;

// 발차기 버튼

    CCSprite  *kickSprite;

    CCSprite  *kickPressedSprite;

    

    BOOL isLeftPressed;

    BOOL isRightPressed;

    

    // 주인공 캐릭터 - 여자 이미지를 사용하지만 prince라고 부르겠습니다.

    CCSprite *princeSprite;

    

    // 주인공 캐릭터의 걷기 애니메이션

    CCAnimate *princeWalkAnimate;

// 주인공 발차기 애니메이션

    CCAnimate *princeKickAnimate;

// 발차기 애니메이션이 진행 중인지 검사하는데 사용합니다.

    BOOL isAnimating;

    

    // 주인공 에너지 변수와

    NSInteger energyValue;

    EnergyBar *princeEnergyBar;

    

    // 캐릭터

    CCSpriteSheet *enemySpriteSheet;

    

    // 캐릭터 애니메이션

    CCAnimation   *enemyWalkAnimation;

    CCAnimation   *enemyAttackAnimation;

    

    // 점수와 라이프 값을 담을 변수와 화면에 표시할 레이블

    NSInteger scoreValue;

    NSInteger lifeValue;

    

    CCBitmapFontAtlas *scoreLabel;

    CCBitmapFontAtlas *lifeLabel;

    

    // 게임을 일시정지/플레이하기 위해 상용되는 메뉴아이템(버튼)

    CCMenuItem *pauseMenuItem;

    //CCMenuItem *playMenuItem;

    

    // 게임이 일시정지 또는 플레이 중인지 나타냄

    GameStatus gameStatus;

}


@property (nonatomic, retain) CCSprite  *rightSprite;

@property (nonatomic, retain) CCSprite  *rightPressedSprite;

@property (nonatomic, retain) CCSprite  *leftSprite;

@property (nonatomic, retain) CCSprite  *leftPressedSprite;

@property (nonatomic, retain) CCSprite  *kickSprite;

@property (nonatomic, retain) CCSprite  *kickPressedSprite;

@property (nonatomic, retain) CCSprite  *princeSprite;

@property (nonatomic, retain) CCAnimate *princeWalkAnimate;

@property (nonatomic, retain) CCAnimate *princeKickAnimate;

@property (nonatomic, retain) EnergyBar *princeEnergyBar;


@property (nonatomic, retain) CCSpriteSheet *enemySpriteSheet;

@property (nonatomic, retain) CCAnimation   *enemyWalkAnimation;

@property (nonatomic, retain) CCAnimation   *enemyAttackAnimation;


@property (nonatomic, retain) CCBitmapFontAtlas *scoreLabel;

@property (nonatomic, retain) CCBitmapFontAtlas *lifeLabel;


- (void) createBackgroundParallax;

- (void) createLabels;

- (void) createArrowButtons;

- (void) createPrinceAndAnimation;

- (void) createEnemyAndAnimation;

- (void) createEnergyBar;

- (void) createGamePauseResumeMenu;


- (void) moveBackground;


- (void) startPrinceWalking;

- (void) stopPrinceWalking;


- (void) displayScore;

- (void) displayLife;


- (void) princeAttacked:(FallDirection)fallDirection;


- (void) handleKickHit:(CGPoint)effectPoint enemySprite:(CCSprite*)enemy directionToFall:(FallDirection)fallDirection;


- (void) animateScoreSprite:(CGPoint)position;


- (void) pauseGame;

- (void) resumeGame;


@end








//

//  GameLayer.m

//  GameDemo

//

//  Created by cmpak on 5/10/10.

//  Copyright 2010 thefirstgood.com. All rights reserved.

//


#import "GameResumeViewController.h"


- (void) createGamePauseResumeMenu {

    pauseMenuItem = [CCMenuItemImage itemFromNormalImage:@"btn_pause.png"

                                                selectedImage:@"btn_pause_s.png"

                                                       target:self

                                                     selector:@selector(playPauseMenuCallback:)];

    /*

    playMenuItem  = [CCMenuItemImage itemFromNormalImage:@"btn_play.png"

                                                selectedImage:@"btn_play_s.png"

                                                       target:self

                                                     selector:@selector(playPauseMenuCallback:)];

    

    CCMenu *menu = [CCMenu menuWithItems: pauseMenuItem, playMenuItem, nil];   

    */

    CCMenu *menu = [CCMenu menuWithItems: pauseMenuItem, nil]; 

    menu.position = ccp(0, 0);

    

    pauseMenuItem.position = ccp(winSize.width - pauseMenuItem.contentSize.width / 2 -5 ,

                                 winSize.height - pauseMenuItem.contentSize.height / 2 - 5 );

    

    // 플레이 메뉴아이템이 일시정지 메뉴아이템 위에 표시됨.  CCMenu 추가될 z order 하나씩 늘어남.

    //playMenuItem.position = pauseMenuItem.position;

    

    // 처음에는 게임이 플레이 모드이므로 플레이 메뉴아이템을 보이지않도록 합니다.

    //playMenuItem.visible = NO;

    

    [self addChild:menu z:kTag_PauseResumeMenu tag:kTag_PauseResumeMenu];

}



- (void) playPauseMenuCallback:(id)sender {

    

    [self pauseGame];

}



- (void) pauseGame {

    // GameAppDelegate 포인터를 받아서 GameResumeViewController showResumeView 메서드를 호출합니다.

    GameDemoAppDelegate *appDelegate = (GameDemoAppDelegate *)[[UIApplication sharedApplication] delegate];

    

    if(appDelegate != nil) {

        gameStatus = kGamePaused;

        

        [self unschedule:@selector(addNewEnemy)];

        

        // 모든 애니메이션을 일시정지 시킵니다.

        // cocos2d 0.99에서는 pause 시켜도 계속해서 터치이벤트를 받습니다.

        [[CCDirector sharedDirector] pause];

        

        // 일시정지 버튼을 안보이게 감추고 터치를 받지않습니다.

        pauseMenuItem.visible = NO;

        [pauseMenuItem setIsEnabled:NO];

        

        // GameResumeViewController showResumeView 이용하여 화면에 보이도록 합니다.

        [appDelegate.gameResumeViewController showResumeView:self];

    }

}


- (void) resumeGame {

    gameStatus = kGamePlaying;

    

    // 일시정지 버튼을 다시 보이게 하고 터치도 받도록 합니다.

    pauseMenuItem.visible = YES;

    [pauseMenuItem setIsEnabled:YES];

    

    // 모든 애니메이션을 다시 작동시킵니다.

    [[CCDirector sharedDirector] resume];

    

    [self schedule:@selector(addNewEnemy)];

}


(1) GameResumeViewController *gameResumeViewController의 showResumeView메서드를 호출하기 위하여, UIApplication 클래스의 sharedApplication 메서드를 이용하여 GameDemoAppDelegate 객체의 포인터를 받습니다.