본문 바로가기

프로그래밍/cocos2d

OpenGL 선 그리기 API로 에너지 바 만들기


작업 할 파일은 다음과 같습니다.
(1) EnergyBar.h
(2) EnergyBar.m
(3) GameLayer.h
(4) GameLayer.m


//

//  EnergyBar.h

//  GameDemo

//

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

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

//


//#import <Foundation/Foundation.h>

#import "cocos2d.h"



//@interface EnergyBar : NSObject {

@interface EnergyBar : CCNode {

    CGFloat maxValue;

    CGFloat curValue;

    

    CGSize  maxSize// 에너지 바의 픽셀 크기

    

}


- (id) initWithMaxSize:(CGSize)size maxValue:(CGFloat)maxVal;


- (void) updateBar:(CGFloat)curValue;


@end


(1) cocos2d의 가장 기본 클래스인 CCNode를 상속받는 EnergyBar 클래스를 정의합니다.






//

//  EnergyBar.m

//  GameDemo

//

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

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

//


#import "EnergyBar.h"



@implementation EnergyBar


- (id) initWithMaxSize:(CGSize)size maxValue:(CGFloat)maxVal {

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

        // anchorPoint 왼쪽 아래로 잡습니다.

        self.anchorPoint = CGPointZero;

        

        // 에너지 바의 이미지 크기

        maxSize = size;

        

        // 전체 에너지 바에 몇개의 에너지가 있는지 설정

        maxValue = maxVal;

        curValue = maxValue;

    }

    

    return self;

}


- (void) draw {

    // 그려야할 길이를 픽셀값으로 계산합니다.

    CGFloat width = maxSize.width * curValue / maxValue;

    

    // 선의 두께를 설정합니다.

    glLineWidth(maxSize.height);

    

    // 색을 설정합니다: RGB Alpha

    // 전체 에너지 값의 40%이내로 떨어지면 빨간색으로 표시합니다.

    glColor4ub(57, 248, 11, 255);

    

    if(curValue / maxValue <= 0.4)

        glColor4ub(217, 79, 62, 255);

    

    ccDrawLine( ccp(0, 0), ccp(width, 0) );

}


- (void) updateBar:(CGFloat)curVal {

    curValue = curVal;

    if(curValue < 0)

        curValue = 0;

    else if(curValue > maxValue)

        curValue = maxValue;

    

    [self draw];

}


@end


(1) glLineWidth와 glColor4ub는 OpenGL ES에서 제공하는 API입니다. glLineWidth 메서드로 선의 두께를 지정합니다.
glColor4ub 메서드를 사용하여 RGB와 알파 값으로 선의 색을 설정한 후 ccDrawLine 메서드로 시작점과 끝점을 지정하여 선을 그립니다.








//

//  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;



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

}


@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) 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;


@end









//

//  GameLayer.m

//  GameDemo

//

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

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

//

#import "EnergyBar.h"

#define INIT_NUM_LIFE 3

#define INIT_NUM_ENERGY 10 


@synthesize  princeEnergyBar;


- (id) init {

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

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

        self.isTouchEnabled = YES;

        

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

        winSize = [[CCDirector sharedDirector] winSize];

        

        // 초기값 설정

        scoreValue = 0;

        //lifeValue = 3;

        lifeValue = INIT_NUM_LIFE;

        energyValue = INIT_NUM_ENERGY;

        

        [self createBackgroundParallax];

        [self createLabels];

        [self createPrinceAndAnimation];

        [self createEnemyAndAnimation];

        [self createArrowButtons];

        [self createEnergyBar];

    }

    

    return self;

}



- (void) createEnergyBar {

    // 에너지 바의 가로*세로 크기를 정하고, 최고 에너지 값을 정해줍니다.

    EnergyBar *bar = [[EnergyBar alloc] initWithMaxSize:CGSizeMake(120, 10) maxValue:INIT_NUM_ENERGY];

    self.princeEnergyBar = bar;

    self.princeEnergyBar.position = ccp(winSize.width / 2 + 75, winSize.height - 22);

    [self addChild:self.princeEnergyBar z:kTag_Label];

    [bar release];

}



- (void) princeAttacked:(FallDirection)fallDirection {

    // 에너지를 감소시킵니다.

    energyValue--;

    

    if(energyValue <= 0) {

        

        // 라이프를 감소시킨다.

        lifeValue--;

        

        if(lifeValue <= 0) {

            NSLog(@"GAME OVER");

            

            // 임시로 다시 원래값으로 리셋합니다.

            lifeValue = INIT_NUM_LIFE;

        }

        

        [self displayLife];

        

        // 에너지를 재충전 시킨다.

        energyValue = INIT_NUM_ENERGY;

    }

    

    // 에너지 바를 업데이트 한다.

    [self.princeEnergyBar updateBar:energyValue];

    

    // 좌우로 60픽셀만큼 밀려나게 합니다.

    CGFloat xDiff = 60.0;

    if(fallDirection == kFallLeft)

        xDiff *= -1.0;

    

    // x좌표의 값이 화면 바깥으로 나가지않도록 합니다.

    CGFloat xPos = self.princeSprite.position.x + xDiff;

    if(xPos < 0)

        xPos = 0;

    else if(xPos > winSize.width)

        xPos = winSize.width;

    

    CGPoint targetPoint = CGPointMake(xPos, self.princeSprite.position.y);

    

    CGFloat duration = 0.5;

    

    // 빨간색으로 변화시킵니다.

    id tint = [CCTintBy actionWithDuration:duration/2.0 red:0 green:-255 blue:-255];

    

    // CCEaseExponentialOut 사용하여 속도감이 있도록 합니다.

    id move = [CCEaseExponentialOut actionWithAction:[CCMoveTo actionWithDuration:duration position:targetPoint]];

    

    id spawn = [CCSpawn actions:tint, move, nil];

    

    [self.princeSprite runAction:[CCSequence actions:

                                  spawn,

                                  [CCCallFunc actionWithTarget:self selector:@selector(princeAttackedCompleteHandler)],

   

                              nil]];

}