본문 바로가기

프로그래밍/cocos2d

스프라이트 동적으로 생성하고 삭제하기



//

//  GameLayer.h

//  GameDemo

//

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

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

//


#import "cocos2d.h"


// 적이 쓰러질 방향

typedef enum {

    kFallRight,

    kFallLeft

}EnemyFallDirection;


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

    

    // 캐릭터

    CCSpriteSheet *enemySpriteSheet;

    

    // 캐릭터 걷기 애니메이션

    CCAnimation   *enemyWalkAnimation;

}


@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) CCSpriteSheet *enemySpriteSheet;

@property (nonatomic, retain) CCAnimation   *enemyWalkAnimation;


- (void) createBackgroundParallax;

- (void) createArrowButtons;

- (void) createPrinceAndAnimation;

- (void) createEnemyAndAnimation;


- (void) moveBackground;


- (void) startPrinceWalking;

- (void) stopPrinceWalking;


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


@end






//

//  GameLayer.m

//  GameDemo

//

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

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

//


#import "GameLayer.h"


#define IMG_WIDTH 1600


enum {

    kTag_Parallax,

    kTag_Enemy,

    kTag_Prince,

    kTag_Effect,

    kTag_ControlButtonPressed,

    kTag_ControlButton

};



@implementation GameLayer


@synthesize rightSprite, rightPressedSprite, leftSprite, leftPressedSprite;

@synthesize kickSprite, kickPressedSprite;

@synthesize princeSprite, princeWalkAnimate, princeKickAnimate;

@synthesize enemySpriteSheet, enemyWalkAnimation;


- (id) init {

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

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

        self.isTouchEnabled = YES;

        

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

        winSize = [[CCDirector sharedDirector] winSize];

        

        [self createBackgroundParallax];

        [self createPrinceAndAnimation];

        [self createEnemyAndAnimation];

        [self createArrowButtons];

    }

    

    return self;

}


- (void) onExit {

    [super onExit];

    

    // sprite sheet texture 캐시를 모두 지웁니다.   

    // 이상 사용하지않는 캐시를 반드시 지워주세요.

    [[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];

}


- (void) createPrinceAndAnimation {

    // 위치정보 파일을 읽어들여 바로 CCSpriteFrame 만들어 캐시에 저장합니다.

    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"prince_walk_trim.plist"];

    

    // 프레임을 담을 Array 만듭니다.

    NSMutableArray *aniFrames = [NSMutableArray array];

    

    // 아주 간단히 프레임을 만들어 배열에 저장할 있습니다. 스프라이트 시트를 만들 사용된

    // 개별 이미지의 파일 이름을 사용하여 개별 프레임을 읽어들입니다.

    for(NSInteger idx = 1; idx <= 15; idx++) {

        CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache

                                spriteFrameByName:[NSString stringWithFormat:@"prince_walk_%02d.png", idx]];

        [aniFrames addObject:frame];

    }

    

    // 프레임으로 CCAnimation 만듭니다 프레임당 시간을 0.05초로 정해줍니다.

    CCAnimation *animation = [CCAnimation animationWithName:@"prince_walk" delay:0.05f frames:aniFrames];

    

    // CCAnimation action CCAnimate 만듭니다.

    CCAnimate *animate = [[CCAnimate alloc] initWithAnimation:animation restoreOriginalFrame:NO];

    self.princeWalkAnimate = animate;

    [animate release];

    

    // 첫번째 프레임을 만들 사용했던 이미지 파일 이름을 사용하여 주인공 sprite 만듭니다.

    CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:@"prince_walk_01.png"];

    self.princeSprite = sprite;

    [self addChild:self.princeSprite z:kTag_Prince tag:kTag_Prince];

    

    // 위치계산이 편하도록 주인공의 anchorPoint 가운데 아래로 잡습니다.

    self.princeSprite.anchorPoint = ccp(0.5, 0);

    

    // 주인공을 화면 가운데 아래에서 13픽셀 위에 위치시킵니다.

    self.princeSprite.position = ccp(winSize.width / 2, 13);

    

    [sprite release];

// 발차기 애니메이션에 쓰일 스프라이트 시트의 위치정보 파일을 읽어들인다.

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"prince_kick_notrim.plist"];

[aniFrames removeAllObjects];

for(NSInteger idx = 1; idx <= 15; idx++) {

        CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache

                                spriteFrameByName:[NSString stringWithFormat:@"prince_kick_%02d.png", idx]];

        [aniFrames addObject:frame];

    }

    

    // 프레임으로 CCAnimation 만듭니다 프레임당 시간을 0.04초로 정해줍니다.

    animation = [CCAnimation animationWithName:@"prince_kick" delay:0.04f frames:aniFrames];

    

    // CCAnimation action CCAnimate 만듭니다.

    animate = [[CCAnimate alloc] initWithAnimation:animation restoreOriginalFrame:NO];

    self.princeKickAnimate = animate;

    [animate release];

}


- (void) createEnemyAndAnimation {

    // 위치정보 파일을 읽어들여 바로 CCSpriteFrame 만들어 캐시에 저장합니다.

    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"enemy_walk.plist"];

    

    // 위치정보 파일과 같은 이름을 가진 스프라이트 시트로 CCSpriteSheet 객체를 만듭니다.

    self.enemySpriteSheet = [CCSpriteSheet spriteSheetWithFile:@"enemy_walk.png"];

    [self addChild:self.enemySpriteSheet z:kTag_Enemy];

    

    // 프레임을 담을 Array 만듭니다.

    NSMutableArray *aniFrames = [NSMutableArray array];

    

    // 아주 간단히 프레임을 만들어 배열에 저장할 있습니다. 스프라이트 시트를 만들 사용된

    // 개별 이미지의 파일 이름을 사용하여 개별 프레임을 읽어들입니다.

    for(NSInteger idx = 1; idx <= 15; idx++) {

        CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache

                                spriteFrameByName:[NSString stringWithFormat:@"zombie_walk_%04d.png", idx]];

        [aniFrames addObject:frame];

    }

    

    // 프레임으로 CCAnimation 만듭니다 프레임당 시간을 0.15초로 정해줍니다.

    CCAnimation *walkAnimation = [[CCAnimation alloc] initWithName:@"enemy_walk" delay:0.15f frames:aniFrames];

    self.enemyWalkAnimation = walkAnimation;

    [walkAnimation release];

    

    // TEMP

    // 임시로 두명의 적을 만들어 주인공 캐릭터의 처음 위치의 왼쪽 오른쪽에 각각 위치시킵니다.

    for(NSInteger idx = 0; idx < 2; idx++) {

        // 첫번째 프레임으로 캐릭터 sprite 만듭니다.

        CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:@"zombie_walk_0001.png"];

        sprite.anchorPoint = ccp(0.5, 0);

        

        if(idx == 0) {

            // 첫번째 적은 화면 중앙에서 왼쪽에

            sprite.position = ccp(winSize.width / 2 - 100, 13);

            sprite.flipX = YES;

        }else {

            // 두번째 적은 화면 중앙에서 오른쪽에 위치시킵니다.

            sprite.position = ccp(winSize.width / 2 + 100, 13);

            sprite.flipX = NO;

        }

        

        // 만들어진 스프라이트를 스프라이트 시트에 넣습니다.

        [self.enemySpriteSheet addChild:sprite];

        

        // 걷기 애니메이션을 시작합니다.

        CCAnimate *walkAnimate = [CCAnimate actionWithAnimation:self.enemyWalkAnimation restoreOriginalFrame:NO];

        [sprite runAction:[CCRepeatForever actionWithAction:walkAnimate]];

    }

}


- (void) createArrowButtons {

    // 왼쪽 화살표

    CCSprite *sprite = [[CCSprite alloc] initWithFile:@"arrow_left.png"];

    self.leftSprite = sprite;

    

    // 기본 anchorPoint 가운데, (0.5, 0.5)이므로 이미지의 가로 세로 크기의 반에 5픽셀의 

    // 여유를 두고 화면 아래에 표시합니다.

    self.leftSprite.position = ccp(10 + self.leftSprite.contentSize.width / 2

                                   self.leftSprite.contentSize.height / 2 + 5);

    

    [self addChild:self.leftSprite z:kTag_ControlButton];

    [sprite release];

    

    // 눌렸을 쓰일 왼쪽 화살표 

    sprite = [[CCSprite alloc] initWithFile:@"arrow_left_s.png"];

    self.leftPressedSprite = sprite;

    

    // self.leftSprite 똑같은 위치에 표시합니다.

    self.leftPressedSprite.position = self.leftSprite.position;

    

    // 눌렸을 때의 화살표를 하위 z-order 넣습니다. 그럼, 위에 같은 크기의 화살표가 

    // 똑같은 위치에 있으니까 가려서 화면상에 보이지 않게됩니다.

    [self addChild:self.leftPressedSprite z:kTag_ControlButtonPressed];

    [sprite release];

    

    // 오른쪽 화살표

    sprite = [[CCSprite alloc] initWithFile:@"arrow_right.png"];

    self.rightSprite = sprite;

    

    // 왼쪽 화살표에서 15픽셀 오르쪽에 위치시킵니다.

    self.rightSprite.position = ccp(self.leftSprite.position.x + self.rightSprite.contentSize.width + 15

                                    self.leftSprite.position.y);

    [self addChild:self.rightSprite z:kTag_ControlButton];

    [sprite release];

    

    // 눌렸을 쓰일 오른쪽 화살표 

    sprite = [[CCSprite alloc] initWithFile:@"arrow_right_s.png"];

    self.rightPressedSprite = sprite;

    

    // self.rightSprite 똑같은 위치에 표시합니다.

    self.rightPressedSprite.position = self.rightSprite.position;

    

    // 눌렸을 때의 화살표를 하위 z-order 넣습니다. 그럼, 위에 같은 크기의 화살표가 

    // 똑같은 위치에 있으니까 가려서 화면상에 보이지 않게됩니다.

    [self addChild:self.rightPressedSprite z:kTag_ControlButtonPressed];

    [sprite release];

// 발차기 버튼

    sprite = [[CCSprite alloc] initWithFile:@"kick.png"];

    self.kickSprite = sprite;

    self.kickSprite.position = ccp(winSize.width - self.kickSprite.contentSize.width / 2 - 5, self.leftSprite.position.y);

    [self addChild:self.kickSprite z:kTag_ControlButton];

    [sprite release];

    // 발차기 버튼 눌렸을

    sprite = [[CCSprite alloc] initWithFile:@"kick_s.png"];

    self.kickPressedSprite = sprite;

    self.kickPressedSprite.position = self.kickSprite.position;

    [self addChild:self.kickPressedSprite z:kTag_ControlButtonPressed];

    [sprite release];

}


- (void) createBackgroundParallax {

    // 이미지로 백그라운드에 쓰일 CCSprite 만듭니다.

    CCSprite *bgSprite1 = [CCSprite spriteWithFile:@"background1.png"];

    CCSprite *bgSprite2 = [CCSprite spriteWithFile:@"background2.png"];

    

    // Transform 사용되는 anchorPoint 왼쪽 아래 귀퉁이 (0, 0) 잡습니다

    bgSprite1.anchorPoint = ccp(0, 0);

    bgSprite2.anchorPoint = ccp(0, 0);

    

    // 위에서 만든 sprite 담을 parent CCParallaxNode 만듭니다.

    CCParallaxNode *voidNode = [CCParallaxNode node];

    

    // 배경 sprite Parallax 넣습니다.

    // parallaxRatio 가로/세로로 움직이는 속도라고 보시면 되겠습니다

    // 우리는 가로로만 움직이므로 y 값을 0으로 줍니다.

    

    // background1.png 파일의 세로 크기가 160 픽셀이기 때문에 positionOffset 이용하여 

    // 화면 위에 위치하도록 좌표를 조정합니다.

    // 뒤쪽에 깔릴 배경인 background1.png 천천히 움직이도록 parallaxRatio x 값을 1보다 작은

    // 0.4 설정합니다.

    [voidNode addChild:bgSprite1 z:0 parallaxRatio:ccp(0.4f, 0) positionOffset:ccp(0, winSize.height / 2)];    

    [voidNode addChild:bgSprite2 z:1 parallaxRatio:ccp(1.0f, 0) positionOffset:CGPointZero];

    [self addChild:voidNode z:kTag_Parallax tag:kTag_Parallax];

}



#pragma mark -

#pragma mark Game Play


- (void) startMovingBackground {

    // 만약 버튼 두개가 눌려졌으면 화면을 이동시키지 않습니다.

    if(isLeftPressed == YES && isRightPressed == YES)

        return;

    

    NSLog(@"start moving");

    [self schedule:@selector(moveBackground)];

    

    // 걷기 애니메이션을 시작합니다.

    [self startPrinceWalking];

}


- (void) stopMovingBackground {

    NSLog(@"stop moving");

    [self unschedule:@selector(moveBackground)];

    

    // 걷기 애니메이션을 멈춥니다.

    [self stopPrinceWalking];

}



- (void) moveBackground {

    // GameLayer 들어있는 parallax node 받습니다.

    CCNode *voidNode = [self getChildByTag:kTag_Parallax];

    

    // 프레임마다 움직일 거리

    CGPoint moveStep = ccp(5, 0);

    

    // 오른쪽 버튼이 눌려졌을 때는 반대로 움직임

    if(isRightPressed)

        moveStep.x = -moveStep.x;

    

    CGFloat bgParallaxRatio = 1.0f;

    

    CGPoint newPos = ccp(voidNode.position.x + moveStep.x, voidNode.position.y);

    

    // 배경이 양쪽 끝에 도달하면 이상 움직이지 않음

    if(isLeftPressed == YES && newPos.x > 0)

        newPos.x = 0;

    else if(isRightPressed == YES && newPos.x < -(IMG_WIDTH - winSize.width) / bgParallaxRatio)

        newPos.x = -(IMG_WIDTH - winSize.width) / bgParallaxRatio;

    

    // 주인공이 화면 가운데 있을 경우에만 배경을 움직입니다.

    CGFloat halfWinWidth = winSize.width / 2;

    if(self.princeSprite.position.x == halfWinWidth)

        voidNode.position = newPos;

    

    

    // 주인공의 방향을 정합니다.

    // flipX 이용하여 하나의 이미지로 방향을 표현할 있습니다.

    if(isRightPressed == YES)

        self.princeSprite.flipX = NO;

    else

        self.princeSprite.flipX = YES;

    

    // 만약 주인공이 화면 가운데 있지않을 경우에는 주인공을 화면가운데까지

    // 이동하게 합니다.

    

    if(isRightPressed == YES && self.princeSprite.position.x < halfWinWidth) {

        // moveStep.x 부호를 바꾼 이유는 배경과 주인공의 움직임 방향이 서로 반대이기 때문입니다.

        self.princeSprite.position = ccp(self.princeSprite.position.x + (moveStep.x * -1),

                                         self.princeSprite.position.y);

        // 가운데 이상 움직이지 않도록 체크합니다.

        if(self.princeSprite.position.x > halfWinWidth)

            self.princeSprite.position = ccp(halfWinWidth, self.princeSprite.position.y);

    }else if(isLeftPressed == YES && self.princeSprite.position.x > halfWinWidth) {

        // moveStep.x 부호를 바꾼 이유는 배경과 주인공의 움직임 방향이 서로 반대이기 때문입니다.

        self.princeSprite.position = ccp(self.princeSprite.position.x + (moveStep.x * -1),

                                         self.princeSprite.position.y);

        

        // 가운데 이상 움직이지 않도록 체크합니다.

        if(self.princeSprite.position.x < halfWinWidth)

            self.princeSprite.position = ccp(halfWinWidth, self.princeSprite.position.y);

    }

    

    // 배경의 끝에 도달하면 배경은 움직이지 않고 주인공을 화면 끝까지 이동시킵니다.

    if(newPos.x == 0 || newPos.x == -(IMG_WIDTH - winSize.width)) {

        CGPoint newPrincePos = ccp(self.princeSprite.position.x + (moveStep.x * -1), self.princeSprite.position.y);

        

        // 주인공이 화면의 왼쪽 또는 오른쪽 끝까지 도달했을 때는 이상 움직이지 않습니다.

        CGFloat halfWidth = self.princeSprite.contentSize.width / 2;

        if(newPrincePos.x <= halfWidth)

            newPrincePos.x = halfWidth;

        else if(newPrincePos.x >= winSize.width - halfWidth)

            newPrincePos.x = winSize.width - halfWidth;

        

        self.princeSprite.position = newPrincePos;

    }

}


- (void) startPrinceWalking {

    NSLog(@"주인공 걷기 시작");

    [self.princeSprite runAction:[CCRepeatForever actionWithAction:self.princeWalkAnimate]];

}


- (void) stopPrinceWalking {

    NSLog(@"주인공 걷기 ");

    [self.princeSprite stopAllActions];

}


- (void) kickAnimateCompleteHandler {

    // 버튼을 다시 보이도록 합니다.

    self.kickSprite.visible = YES;

    [self.princeSprite stopAllActions];

isAnimating = NO;

}


- (void) handleKickHit:(CGPoint)effectPoint enemySprite:(CCSprite*)enemy directionToFall:(EnemyFallDirection)fallDirection {

    // 발차기 공격 이펙트

    CCSprite *hitEffectSprite = [CCSprite spriteWithFile:@"hit_effect.png"];

    hitEffectSprite.position = effectPoint;

    [self addChild:hitEffectSprite z:kTag_Effect];

    

    // 발차기 이펙트 애니메이션

    hitEffectSprite.scale = 0.3;

    

    // CCSequence 사용하면 여러개의 action 순서대로 있습니다.

    [hitEffectSprite runAction:[CCSequence actions:

                                // 주인공 발차기 애니메이션이 이루어지는 시간동안 잠시 기다린다.

                                [CCDelayTime actionWithDuration:0.05],

                                

                                [CCScaleTo actionWithDuration:2.0 scale:1.0],

                                

                                // scale 액션이 끝나면 hitEffectCompleteHandler 메소드를 호출합니다.

                                [CCCallFuncN actionWithTarget:self selector:@selector(hitEffectCompleteHandler:)],

                                nil]];

    

    // 캐릭터 넘어지는 애니메이션

    CGFloat xDiff = 120;

    CGFloat angle = 180;

    if(fallDirection == kFallLeft) {

        xDiff = -120;

        angle = -180;

    }

    

    CGPoint targetPoint = CGPointMake(effectPoint.x + xDiff, enemy.position.y);

    

    // CCSpawn 사용하면 여러 종류의 action 동시에 있습니다.

    id spawn = [CCSpawn actions:[CCJumpTo actionWithDuration:2.0 position:targetPoint height:80 jumps:1],

                [CCRotateBy actionWithDuration:2.0 angle:angle],

                nil];

    [enemy runAction:[CCSequence actions:

                      [CCEaseIn actionWithAction:spawn rate:2.0f],

                      [CCCallFuncND actionWithTarget:self selector:@selector(enemyFallCompleteHandler: enemySprite:) data:(void*)enemy],

                      nil]];

}


- (void) hitEffectCompleteHandler:(CCNode*)node {

    if(node != nil)

        [self removeChild:node cleanup:YES];

}


- (void) enemyFallCompleteHandler:(CCNode*)node enemySprite:(CCSprite*)enemy {

    [self.enemySpriteSheet stopAllActions];

    

    if(enemy != nil)

        [self.enemySpriteSheet removeChild:enemy cleanup:YES];

}


#pragma mark -

#pragma mark Touch Event Handling


// 터치가 버튼 Sprite안에서 이루어졌는지 확인합니다.

- (BOOL) isTouchInside:(CCSprite*)sprite withTouch:(UITouch*)touch {

    // Cocoa 좌표 

CGPoint location = [touch locationInView: [touch view]];

    

    // Cocoa 좌표를 cocos2d 좌표로 변환합니다

CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];

    

    CGFloat halfWidth = sprite.contentSize.height / 2.0;

    CGFloat halfHeight = sprite.contentSize.height / 2.0;

    

    if(convertedLocation.x > (sprite.position.x + halfWidth) ||

       convertedLocation.x < (sprite.position.x - halfWidth) ||

       convertedLocation.y < (sprite.position.y - halfHeight) ||

       convertedLocation.y > (sprite.position.y + halfHeight) ) {

        return NO;

    }

    

    return YES;

}


// 손가락이 닫는 순간 호출됩니다.

- (void) ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {

// 발차기를 하고 있는 동안에는 움직일 없도록 합니다

// 또한 발차기 애니메이션이 진행되는 동안에는 다시 발차기를 없습니다.

if(isAnimating == YES) {

        NSLog(@"Touch Began ignored");

        return;

    }

    UITouch *touch = [touches anyObject];

    

// 발차기 버튼이 터치되었는지 검사

    if([self isTouchInside:self.kickSprite withTouch:touch] == YES) {

        self.kickSprite.visible = NO;

        // 발차기 공격의 유효 타격거리 안에 들어와 있는 적이 있는지 확인합니다.

        // 주인공 sprite 중심에서 40 픽셀, sprite 중심에서 30픽셀 되는 거리를 발차기 유효거리로 정합니다.

        // 위에서 사용된 수치는 현재 사용중인 이미지의 모양과 크기에 따라서 정한 숫자이므로

        // 자신이 사용할 이미지에 맞게 조정하시면 됩니다

        NSArray *enemies = [self.enemySpriteSheet children];

        for(CCSprite *enemy in enemies) {

            if(self.princeSprite.flipX == NO  &&

               self.princeSprite.position.x + 40 >= enemy.position.x - 30 &&

  self.princeSprite.position.x + 40 <= enemy.position.x + 30)

            {

                [self handleKickHit:CGPointMake(self.princeSprite.position.x + 55, self.princeSprite.position.y + 113)

enemySprite:enemy directionToFall:kFallRight];

            }else if(self.princeSprite.flipX == YES &&

self.princeSprite.position.x - 40 <= enemy.position.x + 30 &&

self.princeSprite.position.x - 40 >= enemy.position.x - 30)

            {

                [self handleKickHit:CGPointMake(self.princeSprite.position.x - 55, self.princeSprite.position.y + 113)

enemySprite:enemy directionToFall:kFallLeft];

            }

        }

        

isAnimating = YES// 발차기 애니메이션이 진행

        [self.princeSprite runAction:[CCSequence actions:

  self.princeKickAnimate,

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

  nil]];

    }

    // 아래 Boolean 변수 대신에 leftSprite rightSprite visible 값을 직접 사용해도 무방합니다.

    isLeftPressed = NO;

    isRightPressed = NO;

    

    // 터치가 왼쪽 또는 오른쪽 화살표 안에 들어왔는지 확인합니다.

    if([self isTouchInside:self.leftSprite withTouch:touch] == YES) {

        // 왼쪽 화살표를 안보이게 합니다. 그럼 아래에 있던 눌릴 보여지는 이미지가 나타날 것입니다.

        self.leftSprite.visible = NO;

        

        isLeftPressed = YES;

    }else if([self isTouchInside:self.rightSprite withTouch:touch] == YES) {

        // 오른쪽 화살표를 안보이게 합니다.

        self.rightSprite.visible = NO;

        

        isRightPressed = YES;

    }

    

    // 버튼이 눌려졌으면 화면을 움직입니다.

    if(isLeftPressed == YES || isRightPressed == YES)

        [self startMovingBackground];

}


// 손가락을 떼는 순간 호출됩니다.

- (void)ccTouchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {

    // 배경화면을 멈춥니다.

    if(isLeftPressed == YES || isRightPressed == YES)

        [self stopMovingBackground];

    

    // 감춰졌던 버튼이미지를 다시 보이게 합니다.

    if(isLeftPressed == YES)

        self.leftSprite.visible = YES;

    

    if(isRightPressed == YES

        self.rightSprite.visible = YES;

}


// 손가락을 움직일 계속해서 호출됩니다.

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch *touch = [touches anyObject];

    

    // 손가락이 버튼을 벗어나면 움직임을 중단합니다.

    if(isLeftPressed == YES && [self isTouchInside:self.leftSprite withTouch:touch] == NO) {

        self.leftSprite.visible = YES;

        [self stopMovingBackground];

    }else if(isRightPressed == YES && [self isTouchInside:self.rightSprite withTouch:touch] == NO) {

        self.rightSprite.visible = YES;

        [self stopMovingBackground];

    }

}



//- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {}


#pragma mark -

#pragma mark Memory Release


- (void) dealloc {

    [rightSprite release];

    [rightPressedSprite release];

    [leftSprite release];

    [leftPressedSprite release];

[kickSprite release];

    [kickPressedSprite release];

    

    [princeSprite release];

    [princeWalkAnimate release];

[princeKickAnimate release];

    

    [enemySpriteSheet release];

    [enemyWalkAnimation release];

    

    [super dealloc];

}


@end


(1) 이펙트 스프라이트에 여러가지 액션을 연속으로 실행하려고 CCSequence 클래스를 사용합니다.

(2) 여러 종류의 액션을 동시에 사용하려면 CCSpawn 클래스르르 이용해야 합니다.