본문 바로가기

프로그래밍/cocos2d

CCTargetedTouchDelegate

CCStandardTouchDelegate는 CCLayer에서 발생한 모든 터치 이벤트를 프로토콜에 포함된 메서드에 계속 인자로 넘겨주는 반면
CCTargetedTouchDelegate를 사용하면 ccTouchBegan 메서드에 발생한 터치 이벤트를 하나씩 넘겨주고 조건을 만족하는 터치 이벤트만 골라서 다른 메서드에 전달 합니다.
각 터치 이벤트를 사용할 지 말지는 ccTouchBegan에서 자신의 필요에 따라 구현하면 됩니다.

여기서는 방향 버튼에서 발생한 터치 이벤트만 사용하게 구현합니다.


/

//  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 = 0,

    kTag_ArrowButtonPressed = 1,

    kTag_ArrowButton = 2

};



@implementation GameLayer


@synthesize rightSprite, rightPressedSprite, leftSprite, leftPressedSprite;


- (id) init {

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

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

        self.isTouchEnabled = YES;

        

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

        winSize = [[CCDirector sharedDirector] winSize];

        

        [self createBackgroundParallax];

        [self createArrowButtons];

    }

    

    return self;

}


// CCTargetedTouchDelegate 이용하기 위해서는 registerWithTouchDispatcher 메소드를 override하여야 합니다.

// addTargeredDelegate self 설정하였기 때문에 GameLayer안에서 터치이벤트를 핸들링하겠다는 말입니다.

- (void) registerWithTouchDispatcher {

    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];

}


- (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_ArrowButton];

    [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_ArrowButtonPressed];

    [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_ArrowButton];

    [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_ArrowButtonPressed];

    [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)];

}


- (void) stopMovingBackground {

    NSLog(@"stop moving");

    [self unschedule:@selector(moveBackground)];

}



- (void) moveBackground {

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

    CCNode *voidNode = [self getChildByTag:kTag_Parallax];

    

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

    CGPoint moveStep = ccp(3, 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;

    

    voidNode.position = newPos;

}


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

}



#pragma mark StandardTouchDelegate

/*

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

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

    UITouch *touch = [touches anyObject];

    

    // 아래 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 TargetedTouchDelegate

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {

    BOOL ret = NO;

    

    // 아래 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];

        ret = YES;

    }

    

    return ret;

}


- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {

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

    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)ccTouchEnded:(UITouch *)touch 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)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event {}


#pragma mark -

#pragma mark Memory Release


- (void) dealloc {

    [rightSprite release];

    [rightPressedSprite release];

    [leftSprite release];

    [leftPressedSprite release];

    

    [super dealloc];

}


@end