본문 바로가기

프로그래밍/cocos2d

저장된 게임 데이터로 게임 화면 재구성하기

로직을 간단히 나타내면 다음과 같습니다.

게임 데이터가 있는가?

1. 있다
(1) MenuScene : RESUME 버튼(CCMenuItem)을 활성화시킨다.
(2) GameScene : 저장된 게임 데이터를 읽어들여 게임 화면을 재구성한 후 게임을 일시정지 상태로 전환하여 플레이어가 화면을 터치하면 게임이 시작된다.

2. 없다 
(1) MenuScene : RESUME 버튼을 비활성화시킨다.
(2) GameScene : 새로운 게임을 시작한다.



작업할 파일은 다음과 같습니다.

1. 새로 추가할 파일
(1) MenuScene.h
(2) MenuScene.m

2, 수정할 파일
(1) GameScene.h
(2) GameScene.m
(3) GameLayer.h
(4) GameLayer.m
(5) GameDemoAppDelegate.h
(6) GameDemoAppDelegate.m




//

//  MenuScene.h

//  GameDemo

//

//  Created by cmpak on 6/16/10.

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

//


#import "cocos2d.h"



@interface MenuScene : CCScene {

    CCMenuItem *newGameMenuItem;

    CCMenuItem *resumeGameMenuItem;

    CCMenuItem *scoreMenuItem;

    CCMenuItem *aboutMenuItem;

}


- (void) showGameSceneWithNewGame:(BOOL)newGame;


@end


//

//  MenuScene.m

//  GameDemo

//

//  Created by cmpak on 6/16/10.

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

//


#import "MenuScene.h"

#import "GameData.h"

#import "GameScene.h"


enum {

    kTagBackground,

    kTagMenu

};


@implementation MenuScene


- (id) init {

if( (self=[super init]) ) {

        // 배경 이미지를 표시하기 위해 Sprite 이용합니다.

        CCSprite *bgSprite = [CCSprite spriteWithFile:@"bg.png"];

        

        // anchorPoint 따로 설명을 첨부하겠습니다.

        bgSprite.anchorPoint = CGPointZero;

        

        // ccp CGPointMake 같습니다.

        [bgSprite setPosition: ccp(0, 0)];

        

        // MenuScene 배경 Sprite Child 넣습니다. z-index 0으로 설정합니다.

        // 위에 선언된 enum 참고하세요모든 CCNode tag 가질 있습니다.

        // tag 값을 주게되면 로컬변수를 사용하여 만들어진 

        // CCNode -(CCNode*) getChildByTag:(int) aTag 메소드를 이용하여 찾을 있습니다.

        [self addChild:bgSprite z:kTagBackground tag:kTagBackground];

        

        

        // 메뉴 버튼을 만듭니다.

        // itemFromNormalImage 버튼이 눌려지기 전에 보여지는 이미지이고

        // selectedImage 버튼이 눌려졌을 보여지는 이미지입니다.

        // target self 것은 버튼이 눌려졌을 발생하는 터치 이벤트를 MeneScene에서 

        // 처리를 하겠다는 것입니다.

        // @selector 이용하여 버튼이 눌려졌을 어떤 메소드에서 처리를 것인지 결정합니다.

        newGameMenuItem     = [CCMenuItemImage itemFromNormalImage:@"new_game.png" 

                                                     selectedImage:@"new_game_s.png" 

                                                            target:self 

                                                          selector:@selector(newGameMenuCallback:)];

        

        resumeGameMenuItem     = [CCMenuItemImage itemFromNormalImage:@"resume_game.png" 

                                                        selectedImage:@"resume_game_s.png" 

                                                               target:self 

                                                             selector:@selector(resumeGameMenuCallback:)];

        

        scoreMenuItem       = [CCMenuItemImage itemFromNormalImage:@"high_score.png" 

                                                     selectedImage:@"high_score_s.png" 

                                                            target:self 

                                                          selector:@selector(highScoreMenuCallback:)];

        

        aboutMenuItem       = [CCMenuItemImage itemFromNormalImage:@"about.png" 

                                                     selectedImage:@"about_s.png" 

                                                            target:self 

                                                          selector:@selector(aboutMenuCallback:)];

        

        // 위에서 만들어지 각각의 메뉴 아이템들을 CCMenu 넣습니다.  

        // CCMenu 각각의 메뉴 버튼이 눌려졌을 발생하는 터치 이벤트를 핸들링하고,

        // 메뉴 버튼들이 어떻게 표시될 것인 레이아웃 처리를 담당합니다.

        CCMenu *menu = [CCMenu menuWithItems: newGameMenuItem, resumeGameMenuItem, scoreMenuItem, aboutMenuItem, nil];

        

        menu.position = ccp(menu.position.x, menu.position.y - 20);

        

        // alignItemsVerticallyWithPadding 메소드는 자동으로 모든 버튼을

        // 세로로 지정된 스페이스(padding) 주고 정렬을 시킵니다.

        // 이미지 자체에 어느정도 여백이 있기때문에 padding 0으로 잡았습니다.

        [menu alignItemsVerticallyWithPadding:0.0f];

        

        // 만들어진 메뉴를 배경 sprite 위에 표시합니다.

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

    }

    

return self;

}


- (void) onEnter {

    [super onEnter];

    

    // setIsEnabled:NO 테스트하기 위하여 게임데이터를 지웁니다.

    //[GameData deleteGameDataFile];

    

    // 저장된 게임 데이터가 있으면 Resume 메뉴아이템을 enable시킵니다.

    if([GameData hasSavedGameData] == YES)

        [resumeGameMenuItem setIsEnabled:YES];

    else

        [resumeGameMenuItem setIsEnabled:NO];

}


// 메뉴 아이템(버튼) 만들 이벤트 핸들러로 등록된 메소드를 만듭니다.

- (void) newGameMenuCallback: (id) sender {

    [self showGameSceneWithNewGame:YES];

}


- (void) resumeGameMenuCallback: (id) sender {

    [self showGameSceneWithNewGame:NO];

}


- (void) highScoreMenuCallback: (id) sender {

    NSLog(@"High Score 버튼이 눌려졌음");

}


- (void) aboutMenuCallback: (id) sender {

    NSLog(@"About 버튼이 눌려졌음");

}


- (void) showGameSceneWithNewGame:(BOOL)newGame {

    // 새로운 게임을 시작할 경우에는 게임 데이터 파일을 삭제합니다.

    if(newGame == YES && [GameData hasSavedGameData] == YES) {

        [GameData deleteGameDataFile]; 

        NSLog(@"게임 데이터 파일 삭제");

    }

    

    GameScene *scene = [[GameScene alloc] initWithNewGame:newGame];

    [[CCDirector sharedDirector] pushScene:scene];

    [scene release];

}



@end








//

//  GameScene.h

//  GameDemo

//

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

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

//


#import "cocos2d.h"


@class GameLayer;


@interface GameScene : CCScene {

    GameLayer *gameLayer;

}


@property (nonatomic, readonly) GameLayer *gameLayer;


- (id) initWithNewGame:(BOOL)newGame;


@end


//

//  GameScene.m

//  GameDemo

//

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

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

//


#import "GameScene.h"

#import "GameLayer.h"


@implementation GameScene

   

@synthesize gameLayer;


//- (id) init {

- (id) initWithNewGame:(BOOL)newGame {

    if( (self=[super init]) ) {

        //gameLayer = [GameLayer node];

        GameLayer *layer = [[GameLayer alloc] initWithNewGame:newGame];

        gameLayer = layer;

        [self addChild:gameLayer z:0 tag:0];

        [layer release];

    }

    

    return self;

}


@end









//

//  GameLayer.h

//  GameDemo

//

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

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

//


#import "cocos2d.h"


@interface GameLayer : CCLayer {

    CGSize winSize;

    

    BOOL   startNewGame;
...


- (id) initWithNewGame:(BOOL)newGame;

- (void) createEnemySprite:(CGPoint)position speed:(CGFloat)speed flipX:(BOOL)flip;


@end


//

//  GameLayer.m

//  GameDemo

//

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

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

//


//- (id) init {

- (id) initWithNewGame:(BOOL)newGame {

    if( (self=[super init]) ) {

        // CCLayer 터치이벤트를 처리할 있도록 활성화시킵니다.

        self.isTouchEnabled = YES;

        

        // 화면의 픽셀 크기를 구합니다.

        winSize = [[CCDirector sharedDirector] winSize];

        

        startNewGame = newGame;

        

        // 초기값 설정

        gameStatus = kGamePlaying;

        scoreValue = 0;

        //lifeValue = 3;

        lifeValue = INIT_NUM_LIFE;

        energyValue = INIT_NUM_ENERGY;

        

        [self createBackgroundParallax];

        [self createLabels];

        [self createPrinceAndAnimation];

        [self createEnemyAndAnimation];

        [self createArrowButtons];

        [self createEnergyBar];

        [self createGamePauseResumeMenu];

    }

    

    return self;

}


- (void) onEnter {

    [super onEnter];

    

    // random 함수의 수가 행할 때마다 새로운 값이 되도록 합니다.

    srandom(time(NULL));

    

    // 배경음악 연주를 시작합니다.

    [[AudioPlayer sharedAudioPlayer] playAudio:kAudio_Background];

    

    // 저장된 게임데이터로 화면을 재구성합니다.

    if(startNewGame == NO) {

        [self createGameSceneWithSavedGameData];

        

        // 게임을 일시정지 시킵니다.

        [self pauseGame];

    }else {

        // 0.5 간격으로 캐릭터를 만들어냅니다.

        [self schedule:@selector(addNewEnemy) interval:0.5f];

    }

}


- (void) createGameSceneWithSavedGameData {

    // 저장된 게임 데이터를 읽습니다.

    GameData *gameData = [GameData loadGameData];

    

    if(gameData == nil)

        return;

    

    scoreValue = gameData.score;

    [self displayScore];

    

    lifeValue = gameData.numLife;

    [self displayLife];

    

    energyValue = gameData.energy;

    [self.princeEnergyBar updateBar:energyValue];

    

    self.princeSprite.position = ccp(gameData.princeXPos, gameData.princeYPos);

    self.princeSprite.flipX = gameData.princeFlipX;

    

    // sprite 만듭니다.

    if(gameData.enemyDataArr != nil) {

        for(EnemyData *enemyData in gameData.enemyDataArr) {

            // 적의 yPos 사용하지 않습니다.

            [self createEnemySprite:CGPointMake(enemyData.xPos, 13) speed:enemyData.walkingSpeed flipX:enemyData.flipX];

        }

    }

}


- (void) createEnemySprite:(CGPoint)position speed:(CGFloat)speed flipX:(BOOL)flip {

    EnemySprite *enemy = [[EnemySprite alloc] initWithSpriteFrameName:@"zombie_walk_0001.png" 

                                                             position:position 

                                                                speed:speed

                                                            gameLayer:self ];

    enemy.flipX = flip;

    [self.enemySpriteSheet addChild:(CCSprite*)enemy];

    [enemy release];

}







//

//  GameDemoAppDelegate.h

//  GameDemo

//

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

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

//


#import <UIKit/UIKit.h>


@class GameResumeViewController;

//@class GameLayer;


@interface GameDemoAppDelegate : NSObject <UIApplicationDelegate> {

UIWindow *window;

    

    GameResumeViewController *gameResumeViewController;

    

    //GameLayer *gameLayer;

}


@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"

#import "Utils.h"

#import "MenuScene.h"

#import "GameScene.h"



@implementation GameDemoAppDelegate


@synthesize window;

@synthesize gameResumeViewController;



- (void) applicationDidFinishLaunching:(UIApplication*)application

{

...

    

[window makeKeyAndVisible];

    

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

    gameLayer = gameScene.gameLayer;

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

    [gameScene release];*/

    

    // MenuScene 만들어 화면으로 보여준다.

    MenuScene *menuScene = [[MenuScene alloc] init];

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

    [menuScene release];

}


// 버튼이 눌려지면 바로 메소드가 호출이 됩니다.

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

    // GameLayer에서 필요한 정보를 모아 파일에 저장합니다.

    //SaveCurrentGameState(gameLayer);

    

    // 현재 보여지는 scene GameScene 때에만 게임 데이터를 저장합니다.

    CCScene *scene = [[CCDirector sharedDirector] runningScene];

    

    if([scene isMemberOfClass:[GameScene class]] == YES) {

        // GameLayer에서 필요한 정보를 모아 파일에 저장합니다.

        GameScene *gameScene = (GameScene*)scene;

        SaveCurrentGameState(gameScene.gameLayer);

    }

    

[[CCDirector sharedDirector] end];

}