cocos2d study #11

터치


1. 터치 동작 연구

오늘은 터치에 대해 연구해 보자.

(1) 반드시 확인할 것

간혹 터치 관련 메소드를 넣었으나 반응이 없을 경우가 있다.

터치 활성화 코드를 넣지 않은 경우가 많으므로, 반드시 확인해야 한다.

아래 코드를 init 메소드에 넣으면 된다.

self.isTouchEnabled = YES;

(2) 터치가 발생하면 실행되는 메소드

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)withEvent
{
    [ball1 stopActionByTag:1];	// 태그 1 액션을 stop

    NSLog("Touch!");
}

터치 이벤트 코드는 매우 자주 사용하므로 필요할 때마다 copy&paste로 사용하면 된다.

(3) 드래그 동작

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)Event
{
    // …
}

드래그를 처리할 경우에는 ccTouchesBegan을 ccTouchesMoved로 바꿔 사용하면 된다.

(4) 터치가 끝났을 때

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)Event
{
    // …
}

화면에서 손가락을 떼었는지 판단한다.

2. OpenGL 좌표로 변환

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)withEvent
{
    // UITouch는 좌상단이 (0,0) 이다.
    UITouch *touch=[touches anyObject];

    CGPoint touchPoint;

    // 터치가 발생한 좌표를 얻는다.
    touchPoint = [touch locationInView:[touch view]];
    
    // OpenGL 좌표로 변환한다.
    touchPoint = [[CCDirector sharedDirector] convertToGL:touchPoint];
}

아이폰 좌표를 OpenGL 좌표로 변환하는 방법이다.

변환을 하는 이유는, 터치가 발생했을 때 받는 좌표가 아이폰의 좌표계이기 때문에 cocos2d에서는 그 좌표를 곧바로 쓸 수 없기 때문이다.

위의 코드를 수정할 일은 거의 없으므로 필요할 때마다 copy&paste 하면 된다.



PS

터치도 알아야 할 것이 많다.

아직은 기초 활용법만 익혔을 뿐이다.

더 열심히 하자!

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #13  (0) 2012.10.26
cocos2d study #12  (0) 2012.10.26
cocos2d study #10  (0) 2012.10.26
cocos2d study #09  (0) 2012.10.26
cocos2d study #08  (0) 2012.10.25

cocos2d study #10

다양한 액션


액션 예제

액션은 매우 많으므로 모두 기억하는 것은 어렵다.

주요 부분을 주석으로 설명한다.

-(void)testAction
{
    CCSprite *ball1;
    CCSprite *ball2;
    CCSprite *ball3;
 
    ball1 = [CCSprite spriteWithFile:@"ball.png"];
    ball2 = [CCSprite spriteWithFile:@"ball.png"];
    ball3 = [CCSprite spriteWithFile:@"ball.png"];
 
    ball1.position=ccp(50,50);
    ball2.position=ccp(50,150);
    ball3.position=ccp(50,250);
 
    [self addChild:ball1];
    [self addChild:ball2];
    [self addChild:ball3];
    
    // CCEaseIn은 점점 빠르게. rate는 비율(얼마나 잘 일어나게 할 것인가)
    id rightMove1 = [CCMoveBy actionWithDuration:4 position:ccp(400,0)];
    id fasterBall = [CCEaseIn actoinWithAction:rightMove1 rate:3.0];        
    [ball1 runAction:fasterBall];
 
    // CCEaseOut 점점 느리게
    id rightMove2 = [CCMoveBy actionWithDuration:4 position:ccp(400,0)];
    id slowerBall = [CCEaseOut actoinWithAction:rightMove2 rate:3.0];        
    [ball2 runAction:slowerBall];
 
    // CCEaseInOut 빨라지다가 느려지게
    id rightMove3 = [CCMoveBy actionWithDuration:4 position:ccp(400,0)];
    id totalSpeed = [CCEaseInOut actoinWithAction:rightMove3 rate:3.0];    
    [ball3 runAction:totalSpeed];
 
    // CCEaseElastic 뒤로 살짝 갔다가 튕겨서 앞으로 이동
    id rightMove4 = [CCMoveBy actionWithDuration:4 position:ccp(400,0)];
    id test4 = [CCEaseElasticIn actoinWithAction:rightMove4 period:1.0];    
    [ball1 runAction:test4];
 
    // CCEaseBounceIn 튕기면서 이동, Out형태도 있음
    id rightMove5 = [CCMoveBy actionWithDuration:4 position:ccp(400,0)];
    id test5 = [CCEaseBounceIn actionWithAction:rightMove4];
    [ball1 runAction:test5];
 
    // CCScale 액션과 CCEaseBounce 액션과 섞기
    id scale = [CCScaleBy actionWithDuration:4 scale:3.0];
    id test6 = [CCEaseBounceOut actionWithAction:scale];
    [ball1 runAction:test6];
 
    // fadeout 점점 사라짐 | fadein 점점 나타남
    id fadeOut = [CCFadeOut actionWithDuration:3.0];
    [ball1 runAction:fadeOut];
 
    // fadein일 때 처음 스프라이트가 깜빡이거나 또는
    // 나타났다가 사라질 수 있기 때문에 애초부터 투명하게 시작한다.
    ball1.opacity = 0;
    id fadeIn = [CCFadeIn actionWithDuration:3.0];
    [ball1 runAction:fadeIn];
 
    // CCFadeTo 원하는 투명도 0부터 투명도 100까지 변화
    ball1.opacity = 0;
    id fadeTo = [CCFadeIn actionWithDuration:3.0 opacity:100];
    [ball1 runAction:fadeTo];
 
    // CCRepeat 액션을 반복 
    // right는 오른쪽 이동, left는 왼쪽 이동
    // total에 right와 left를 넣어 순차 실행, 세 번 반복 (repeat)
    id right  = [CCMoveBy actionWithDuration:2 position:ccp(400,0)];
    id left   = [CCMoveBy actionWithDuration:2 position:ccp(-400,0)];
    id total  = [CCSequence actions:right,left,nil];
    id repeat = [CCRepeat actionWithAction:total times:3];
    [ball1 runAction:repeat];
 
    // CCRepeatForever 액션을 무한 반복
    id right = [CCMoveBy actionWithDuration:2 position:ccp(400,0)];
    id left  = [CCMoveBy actionWithDuration:2 position:ccp(-400,0)];
    id total = [CCSequence actions:right,left,nil];
    id repeatForever = [CCRepeatForever actionWithAction:total];
    [ball1 runAction:repeatForever];
}
 
// 버튼 누르면 액션을 멈추는 예제
// 위의 CCRepeatForever 예제를 조금 더 확장한 것
-(id)init
{
    if ( (self=[super init]) )
    {
        // 터치 이벤트를 받기 위해 넣어야 하는 코드 (반드시!)
        self.isTouchEnabled = YES;    
 
        CCSprite *ball1;
        CCSprite *ball2;
        CCSprite *ball3;
 
        ball1 = [CCSprite spriteWithFile:@"ball.png"];
        ball2 = [CCSprite spriteWithFile:@"ball.png"];
        ball3 = [CCSprite spriteWithFile:@"ball.png"];
 
        ball1.position = ccp(50,50);
        ball2.position = ccp(50,150);
        ball3.position = ccp(50,250);
 
        [self addChild:ball1];
        [self addChild:ball2];
        [self addChild:ball3];
 
        // CCRepeatForever 액션을 무한 반복!
        id right = [CCMoveBy actionWithDuration:2 position:ccp(400,0)];
        id left  = [CCMoveBy actionWithDuration:2 position:ccp(-400,0)];
        id total = [CCSequence actions:right,left,nil];    //순차적으로 액션
        CCRepeatForever *repeatForever = [CCRepeatForever actionWithAction:total];
        // 액션도 CCNode를 상속받은 클래스이므로 tag를 쓸 수 있다.
        repeatForever.tag = 1;
        [ball1 runAction:repeatForever];
    }
    return self;
}
 
// 터치 이벤트가 발생하면 실행되는 메소드
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)withEvent
{
    // tag 1인 액션을 중지한다.
    // 위에서 repeatForever의 태그를 1로 설정했으므로
    // 최종적으로, 무한 반복하는 액션을 중지시킨다.
    [ball1 stopActionByTag:1];
    
    NSLog("Touch!");
}


여러 개의 스프라이트

지금까지는 1개의 스프라이트에 액션을 주어 동작을 하게 만들었다. 그런데 여러 개의 스프라이트를 동시에 움직이게 하려면 어떻게 해야 할까?

예제

id move = [CCMoveBy actionWithDuration:3 position:ccp(400,0)];

[ball1 runAction:move];
[ball2 runAction:move];
[ball3 runAction:move]; // 동작하지 않는다. ball1만 움직임

스프라이트를 여러 개 만들어 각각 액션을 주어 보았다.

그런데, 실제로 동작을 확인해보면 첫 번째 스프라이트만 움직인다.

수정한 코드

id move = [CCMoveBy actionWithDuration:3 position:ccp(400,0)];

[ball1 runAction:move];
[ball2 runAction:[move copy]];
[ball3 runAction:[move copy]]; // NSCopying을 이용!

move 액션에 copy 메시지를 보내 해결할 수 있다.



PS

XCode는 Visual Studio처럼 자동 완성 기능이 있는데, 보통 메소드를 입력할 때 사용 가능한 메소드가 뜨는 것을 볼 수 있다. 그런데 한 번 입력한 후 메소드 목록을 다시 보고 싶을 때가 있다. 이 때 ESC 키를 누르면 사용 가능한 수많은 메소드를 보여준다. 이 기능을 잘 활용하자.

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #12  (0) 2012.10.26
cocos2d study #11  (0) 2012.10.26
cocos2d study #09  (0) 2012.10.26
cocos2d study #08  (0) 2012.10.25
cocos2d study #07  (0) 2012.10.25

cocos2d study #09

액션


1. CCActionTo/By 클래스

스프라이트를 움직이려면 액션을 사용해야 한다.

대표적인 액션 클래스에는 다음과 같은 것들이 있다.

CCMoveTo, CCMoveBy: 이동

CCRotateTo, CCRotateBy: 회전

CCScaleTo, CCScaleBy: 크기 변화

액션 클래스의 접미사로 To와 By가 붙어있는 것을 알 수 있는데, To와 By의 차이점은 다음과 같다.

To는 절대좌표를 기준으로, By는 현재 위치를 기준으로 움직인다.

예를 들어 현재 위치가 (80,80)이라고 하자. 이 때 좌표를 (180,80)으로 즉, 현재 위치에서 우측으로 100만큼 이동하고 싶다면 By를 이용하여 x 좌표에 100을 더하면 된다. (x+100)

현재 위치에서 바로 (0,0)으로 이동하고 싶다면 To를 써서 ccp(0,0) 하면 된다.

2. 기본 코드

(1) 액션 사용하기

[실행할노드객체 runAction:액션];

(2) 순서가 있는 액션 실행하기

id totalAction = [CCSequenece actions:액션1, 액션2, nil];

(3) 액션을 동시 실행하기

id totalAction = [CCSpawn actions: 액션1, 액션2, nil];

CCSequence와 CCSpawn은 마지막에 nil을 넣어야 하는 것을 잊지 말자.

(4) 콜백 함수

액션을 실행한 후에 무엇인가를 하려고 할 때 사용한다.

① 콜백 함수를 호출하는 CCCallFunc 클래스

콜백 함수 클래스에는 CCCallFunc와 N이 붙은 CCCallFuncN이 있는데, 차이점은 노드의 전달 유무이다. 액션 직후에 노드를 다른 함수로 넘겨서 복잡한 무엇인가를 처리하기 위해서는 CCCallFunC을 사용해야 한다. 노드를 넘길 필요가 없는 단순한 동작은 CCCallFunc로도 충분하다.

② 콜백 함수 사용 예제 코드
-(void)sampleFunction
{
// 코드...

// CCCallFuncN으로 selector를 이용하여 afterAction을 호출
id callback1 = [CCCallFuncN actionWithTarget:self selector:@selector(afterAction:)];
}

// 노드를 전달하여 무엇인가(NSLog)를 한다!
-(void)afterAction:(CCNode *)node {
	NSLog("전달된 노드: %@", node);	
}

3. 액션 사용 예제

-(void)buttonPushed {
 
    // 기본 스프라이트 설정 - 생성, 위치 설정, 자식으로 추가
    CCSprite *sprite = [CCSprite spriteWithFile:@"ball.png"];
    sprite.position = ccp(50,50);
    [self addChild:sprite];
 
    // ********** move 액션
    // 시간(duration)은 초 단위, position은 움직일 위치
    CCMoveTo *action = [CCMoveTo actionWithDuration:3 position:ccp(440,50)];
    
    // 액션을 실행한다.
    [sprite runAction:action];    
 
 
    // ********** 여러 가지 액션 **********
 
    // CCMoveTo는 position 좌표로 바로 이동한다.
    CCMoveTo *action = [CCMoveTo actionWithDuration:3 position:ccp(440,50)];
 
    // CCMoveBy는 현재의 위치를 기준으로 x+440,y+50으로 이동시킨다.
    CCMoveBy *action = [CCMoveBy actionWithDuration:3 position:ccp(440,50)];
 
    // CCRotateBy
    // 회전 액션, angle은 각도를 뜻하며 360은 시계 방향으로 한 바퀴
    // 720도는 시계 방향으로 두 바퀴를 회전한다.
    CCRotateBy *action = [CCRotateBy actionWithDuration:3 angle:360];
    CCRotateBy *action = [CCRotateBy actionWithDuration:3 angle:720];
 
    // CCRotateTo
    // 자동으로 자신이 판단해서 빠른 쪽으로 회전한다.
    // 회전할 필요가 없으면 회전하지 않는다.
    // 360도는 액션 후의 결과가 제자리이므로, 회전을 하지 않는다.
    // angle:90은 시계 방향으로 90도 회전하게 된다.
    CCRotateTo *action = [CCRotateTo actionWithDuration:3 angle:360];
    CCRotateTo *action = [CCRotateTo actionWithDuration:3 angle:90];
    
    // CCScaleTo
    // 크기를 2배로 확대한다.
    // 위의 액션들과 다르게 여기서는 액션의 결과를
    // id 타입의 action 변수로 받았다.
    // CCScaleTo *action = [CCScaleTo actionWithDuration:2 scale:2.0];
    id action = [CCScaleTo actionWithDuration:2 scale:2.0];
    
    [sprite runAction:action];
 
 
    // ********** 2가지 이상의 액션 처리 **********
    // move, rotate, scale을 CCSpawn으로 받아 total에 넣어 액션을 실행한다.
    // CCSpawn은 여러 가지 액션을 동시에 실행한다. nil 주의!
    id move     = [CCMoveBy actionWithDuration:3 position:ccp(400,0)];
    id rotate   = [CCRotateBy actionWithDuration:3 angle:360*4];
    id scale    = [CCScaleBy actionWithDuration:3 scale:3.0];
    id total    = [CCSpawn actions:move, rotate, scale, nil];
    [sprite runAction:total];
 
    // move, rotate, scale을 CCSequence로 받아 total에 넣어 액션을 실행한다.
    // CCSequence는 액션을 차례대로 하나씩 실행한다. nil 주의!
    id move     = [CCMoveBy actionWithDuration:3 position:ccp(400,0)];
    id rotate   = [CCRotateBy actionWithDuration:3 angle:360*4];
    id scale    = [CCScaleBy actionWithDuration:3 scale:3.0];
    id total    = [CCSequence actions:move, rotate, scale, nil];
    [sprite runAction:total];
 
 
    // ********** 콜백 함수 이용하기 **********
    // 함수를 이용하여 액션 후에 무엇인가를 명령할 수 있다.
    // callback에 after1Action 메소드를 연결해 total에 넣었다.
    // 콜백 함수 after1Action의 역할은, move가 끝나면 NSLog를 실행한다.
    // CCCallFuncN은 노드를 함께 전달하는 클래스이며,
    // afterAction2 뒤에 콜론을 넣어야 한다. (주의)
    id move         = [CCMoveBy actionWithDuration:3 position:ccp(400,0)];
    id callback1    = [CCCallFunc actionWithTarget:self selector:@selector(after1Action)];
    id callback2    = [CCCallFuncN actionWithTargetself selector:@selector(after2Action:)];
    id total        = [CCSequence actions:move, callback1, nil];
    [sprite runAction:total];
}
 
// callback1이 호출하는 콜백 함수
-(void)after1Action {    
    NSLog("move 액션이 종료됨");
}
 
// node를 전달받는 콜백 함수, callback2가 이것을 호출한다.
-(void)after2Action:(CCNode *)_node {
    NSLog("전달된 노드: %@", _node); // 노드를 LSLog로 출력
}



PS

이제 스프라이트를 확실하게 움직이게 되었다.

By와 To의 개념이 처음에는 어려웠지만, 현재 스프라이트 자신의 위치를 기준으로 생각하면 쉽다. (By는 자신 기준, To는 절대 좌표)

그 외에 여러 가지 액션이 많지만, 종류만 여러 가지일 뿐이므로 외울 필요까지는 없고 필요할 때마다 찾아서 사용하면 된다.

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #11  (0) 2012.10.26
cocos2d study #10  (0) 2012.10.26
cocos2d study #08  (0) 2012.10.25
cocos2d study #07  (0) 2012.10.25
cocos2d study #06  (0) 2012.10.23

cocos2d study #08

레이블 만들기


Label

화면에 문자를 표시하는 단순한 기능이다.

너무 뻔해서(?) 특별히 설명할 부분조차 없기 때문에 기억할만한 부분은 간단히 주석으로만 표시해 두었다.


-(id) init
{
    if ( (self=[super init]) )
    {
        //0.99.5 이전에는 CCLabel이었음
        CCLabelTTF *label = [CCLabelTTF labelWithString:@"테스트"
                                        fontName:@"Marker felt"
                                        fontSize:20];
        label.position=ccp(240,160);
        label.color=ccc3(255,0,0);  //rgb 컬러
        label.opacity=100.0;        //투명도. 숫자가 작을수록 투명해진다.
        [self addChild:label];
 
        // 2줄 이상 쓰고 싶다면 아래처럼 사용한다.
        CCLabelTTF *label2 = [CCLabelTTF labelWithString:@"테스트\n테스트"
                                         dimensions:CGSize(300,300) //글자가 들어갈 영역
                                         alignment:UITextAlignmentLeft //왼쪽 정렬
                                         fontName:@"Marker felt"
                                         fontSize:20];
        label2.position=ccp(240,160);
        [self addChild:label2];
    }
    return self;
}


PS

레이블은 단순하지만 활용 범위는 꽤 많을 수 있다. (게임 스코어, 생명력 표시 등)

사용법 역시 스프라이트처럼 단순해서 좋다. :)

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #10  (0) 2012.10.26
cocos2d study #09  (0) 2012.10.26
cocos2d study #07  (0) 2012.10.25
cocos2d study #06  (0) 2012.10.23
cocos2d study #05  (0) 2012.10.23

cocos2d study #07

스프라이트 연구


1. 부모와 자식 관계

스프라이트는 부모와 자식 관계를 가질 수 있다.

addChild를 이용하여 현재의 스프라이트를 자식으로 만든다.

CCSprite *parent = [CCSprite spriteWithFile:@”parent.png”
parent.position = ccp(240,160);
[self addChild:parent];
 
CCSprite *child = [CCSprite spriteWithFile:@”child.png”
CGSize parentSize; // 부모 사이즈
parentSize = parent.contentSize; // 부모 스프라이트의 너비와 높이를 얻는다
child.position = ccp(parent.width/2.0, parent.height/2.0); // 자식의 위치는 부모와 겹치게 된다.
[parent addChild:child]; //여기서는 addChild를 하는 것이 parent이므로 self를 적으면 안 됨.


2. 자식 노드

(1) 자식 노드를 얻는 방법

태그를 이용하여 얻는 방법이 쉽고 간단하다.

[부모노드 getChildByTag:자식노드의 태그번호];

(2) 자식을 삭제하는 방법

① removeChild를 이용하여 삭제하는 방법
노드포인터 = [부모노드 getChildByTag:자식노드의 태그번호];
[부모노드 removeChild:자식노드 cleanup:YES];

② removeChildByTag를 이용하여 바로 삭제하는 방법
[부모노드 removeChildByTag:자식태그번호];

3. 메뉴와 자식을 이용한 예제

3개의 버튼을 만들어 각각 동작하게 하는 코드이다.

-(id)init
{
    if ((self=[super init]))
    {
        CCMenuItem *item1=[CCMenuItemImage itemFromNormalImage:@"menu1.png" 
                                           selectedImage:@"menu1.png"
                                           target:self
                                           selector:@selector(buttonPushed:)];
        CCMenuItem *item2=[CCMenuItemImage itemFromNormalImage:@"item2.png"
                                           selectedImage:@"item2.png"
                                           target:self
                                           selector:@selector(buttonPushed:)];
        CCMenuItem *item3=[CCMenuItemImage itemFromNormalImage:@"menu3.png"
                                           selectedImage:@"menu3.png"
                                           target:self
                                           selector:@selector(buttonPushed:)];
        
        item1.tag=1;
        item2.tag=2;
        item3.tag=3;
 
        CCMenu *menu=[CCMenu menuWithItems:item1,item2,item3,nil];
        menu.position=CGPointZero;    
        [self addChild:menu];
 
        CCSprite *sprite=[CCSprite spriteWithFile:@"parent.png"]; // 부모
        sprite.position=ccp(80,80); // 위치는 (80,80)
        sprite.tag=10;              // 부모 태그 10
        [self addChild:parent];
    }
    return self;
}
 
// 메뉴 버튼을 누르면 동작하는 buttonPushed 메소드
-(void)buttonPushed:(id)sender
{
    CCMenuItem *item=(CCMenuItem *)sender;    // sender를 캐스팅하여 받는다.
    CGSize parentSize;
 
    // 태그로 parent 스프라이트를 얻는 방법이다.
    // 여기서의 parent는 buttonPushed: 메소드의 로컬 변수 parent이다.
    // (init의 parent와 이름만 같은 로컬 변수이기 때문에 =를 써서 대입한 것)
    CCSprite *parent=(CCSprite *) [self getChildByTag:10];
    
    parentSize=parent.contentSize;
 
    // 메뉴1을 누르면 부모의 위치를 위로 이동시킨다.
    if (item.tag==1) {
        parent.position=ccp(80,280);
    }
    // 메뉴2를 누르면 부모 위에 자식 스프라이트를 만든다.
    if (item.tag==2) {
        CCSprite *child=[CCSprite spriteWithFile:@"child.png"];
        child.position=ccp(parentSize.width/2.0, parentSize.height/2.0);
        child.tag=11;
        [parent addChild:child];
    }
    // 메뉴3을 누르면 만들었던 자식을 제거한다.
    // 태그로 차일드를 얻고, 삭제한다.
    if (item.tag==3) {
        CCSprite *child=(CCSprite *)[parent getChildByTag:11];
        [parent removeChild:child cleanup:YES];
    }
}


PS

부모와 자식, 메뉴를 조합했을 뿐인데 이렇게 복잡한 코드가 되어 버렸다.

나중에는 얼마나 더 복잡해질지… :(

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #09  (0) 2012.10.26
cocos2d study #08  (0) 2012.10.25
cocos2d study #06  (0) 2012.10.23
cocos2d study #05  (0) 2012.10.23
cocos2d study #04  (0) 2012.10.23

cocos2d study #06

메뉴 만들기


CCMenuItem, CCMenu를 이용해 메뉴를 쉽게 만들 수 있다.

메뉴 추가 방법

1. CCMenuItem 객체들을 만든다.

2. CCMenu 객체를 만들면서 CCMenuItem 객체를 추가시킨다.

3. 메뉴를 삽입시키려는 노드 위에 CCMenu를 차일드로 추가시킨다.


기본 코드

-(void)sampleMenu
{
    CCMenuItem *item1 = [CCMenuItemImage itemFromNormalImage:@"평소그림"
                                         selectedImage:@"눌린그림"
                                         target:메소드를실행할객체
                                         selector:selector];
    // 마지막 nil 주의 (반드시 넣어야 함)
    CCMenu *menu = [CCMenu menuWithItems:item1, nil];
    [부모노드 addChild:menu];
}

CCNode

CCNode는 cocos2d에서 모든 객체의 슈퍼클래스이다.

CCNode 안에 tag 변수가 들어있다. (int 타입)

tag는 각 객체를 구별하기 위해 달아놓은 숫자 꼬리표이다.

(중간중간 또는 나중에 수정하기 쉽게 #define으로 번호를 지정해 사용하면 좋다)

CCMenuItem은 CCNode를 상속받았다.

그러므로, CCMenuItem 객체 item1에 tag를 쓸 수 있다.

메뉴 만들기 예제 코드

-(id)init
{
    if ((self=[super init])) {
        CCMenuItem *item1=[CCMenuItemImage itemFromNormalImage:@"menu1.png" 
                                           selectedImage:@"menu1.png"
                                           target:self
                                           selector:@selector(buttonPushed:)];
        CCMenuItem *item2=[CCMenuItemImage itemFromNormalImage:@"item2.png"
                                           selectedImage:@"item2.png"
                                           target:self
                                           selector:@selector(buttonPushed:)];
        CCMenuItem *item3=[CCMenuItemImage itemFromNormalImage:@"menu3.png"
                                           selectedImage:@"menu3.png"
                                           target:self
                                           selector:@selector(buttonPushed:)];
        // sender를 보낼 때는 콜론(:)을 붙인다
 
        item1.tag=1;
        item2.tag=2;
        item3.tag=3;
 
        // 마지막 nil 주의 (반드시 넣어야 함)
        CCMenu *menu=[CCMenu menuWithItems:item1,item2,item3, nil];
 
        // [menu alignItemsVertically]; // 메뉴 수직 정렬할 때 사용
        // 메뉴는 기본 위치가 (240,160)이기 때문에 자동정렬 안 한다면 위치를 잡아줘야 함!!
        menu.position=CGPointZero;
        [self addChild:menu];
 
        CCSprite *sprite=[CCSprite spriteWithFile:@"parent.png"]; // 부모 스프라이트
        sprite.position=ccp(80,80);   // 위치는 임의로 80,80
        sprite.tag=10;                // 부모의 태그 10
        [self addChild:parent];
 
        // ...
        // 자식 스프라이트를 추가하면서 태그를 붙여보자.
        // ...
    }
    return self;
}




'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #08  (0) 2012.10.25
cocos2d study #07  (0) 2012.10.25
cocos2d study #05  (0) 2012.10.23
cocos2d study #04  (0) 2012.10.23
cocos2d study #03  (0) 2012.10.22

cocos2d study #05

스프라이트


 

스프라이트는 화면 내에서 이미지로 이루어진 (일반적으로 작은) 물체를 뜻한다.

게임에서 우리가 흔히 부르는 아군 캐릭터라든지, 적의 무기, 바위, 나무, 집 등의 물체를 화면에 표시하기 위해서는 스프라이트를 불러와야 한다. 스프라이트에 여러 가지 움직임(액션)을 적용하여 애니메이션을 만들 수도 있고, 유저 입력에 따라 반응하는 코드를 넣으면 캐릭터의 조종이 가능하게 된다.

 

1. 스프라이트를 만드는 순서

 

(1) 스프라이트 생성
CCSprite *sprite = [CCSprite spriteWithFile:@”그림파일”];

(2) 초기 위치 설정
sprite.position = ccp(240,160);

(3) 스프라이트 배치 (원하는 노드 위에)
[노드객체 addChild:sprite];

 

이렇게 3단계로 스프라이트를 만들 수 있다.

 

2. 스프라이트 생성 예제 코드

// HelloWorldScene.m 또는 HelloWorldLayer.m 파일의 init
 
-(id) init 
{
    if( (self = [super init] ))
    {
        CCSprite *myBox = [CCSprite spriteWithFile:@"mybox.png"];
        myBox.position = ccp(240, 160);    // 스프라이트 위치 설정
        myBox.anchorPoint = ccp(1, 1);     // 앵커포인트 설정
 
        // self는 [HelloWorld Layer] 자신이다.
        // z:를 이용해서 레이어의 깊이를 설정할 수 있다.
        // [self addChild:myBox z:2]; 
        [self addChild:myBox];        
    }
    return self;
}

1. ccp()

ccp는 cocos2d에서 제공하는 짧은 매크로이다.

간단하게 좌표를 지정할 수 있다.

ccp(x, y) 형식으로 사용하면 된다.

2. self

노드 객체 self는 HelloWorld 자신이다.

3. 앵커포인트 (기준점)

스프라이트는 앵커 포인트라는 기준점이 있다.

앵커포인트는 기본적으로 스프라이트의 정중앙이다.

앵커포인트는 변경 가능하다.

사각형 스프라이트에서 각 앵커 포인트 좌표

4. addChild

addChild까지 작업을 해줘야 스프라이트가 비로소 화면에 출력된다.

addChild는 여러 종류가 있는데, z: 를 써줄 경우 스프라이트의 깊이를 정해줄 수 있다.

z는 한 마디로 층이다. 2층이 1층보다 높은 것처럼, z: 2로 된 스프라이트가 위에 보이고, z: 1인 스프라이트는 아래에 묻히게 된다. (두 개의 스프라이트가 겹친 상황)

스프라이트의 깊이 



PS

아직은 화면에 네모만 띄우는 수준이긴 하지만 이 네모가 게임의 가장 기초가 될 것임은 틀림이 없다. 수많은 네모가 모여서 엄청난 명작(?) 캐릭터가 될 수도 있을 것이다.

지금은 일단 스프라이트 생성 과정을 처음 접해서 생소하므로, 몸에 익숙하게 만들어야겠다. :)

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #07  (0) 2012.10.25
cocos2d study #06  (0) 2012.10.23
cocos2d study #04  (0) 2012.10.23
cocos2d study #03  (0) 2012.10.22
cocos2d study #02  (0) 2012.10.22

cocos2d study #04

cocos2d 프로젝트 시작하기


1. 프로젝트를 시작하기 전 알아야 할 것


cocos2d로 프로젝트를 생성하면 여러 개의 파일을 Xcode의 Class 폴더에서 볼 수 있다.

RootViewController는 일반적으로 잘 사용하지는 않는다. (주의: 화면 모드를 세로 모드 또는, 가로 모드로 바꿀 때 수정하는 부분이 있으므로 기억은 해 놓아야 한다)

주로 사용하는 것은 프로젝트명Layer.m 또는 프로젝트명Scene.m이다. (cocos2d의 버전에 따라 파일명의 layer, scene 같은 접미사 부분이 다를 수 있다)

프로젝트명AppDelegate.m 파일은 필요에 따라 약간의 수정을 할 수 있다.

2. 프로젝트의 각 파일에 대하여

(1) ProjectNameAppDelegate.m 파일


예제로 만든 HelloWorld 프로젝트의 HelloWorldAppDelegate.m 파일


AppDelegate.m 파일은 거의 고칠 부분이 없다.

수정을 하더라도 아래의 두 줄 정도가 보통이다.

[director setAnimationInterval:1.0/60]; // FPS를 결정한다.
[director setDisplayFPS:YES]; // FPS를 표시한다.


fps는 초당 프레임으로 1초에 몇 프레임의 장면을 표시할 것인지를 뜻한다. 인간의 눈은 최소 30 프레임 이상이 되어야 끊기지 않는다고 느낀다. 그리고 60 프레임 이상이 되면 움직임이 부드럽다고 느끼게 된다. 기본적으로 60으로 설정되어 있고, setAnimationInterval 수치를 변경하면 원하는 fps로 맞출 수 있지만 일반적으로 60이상의 프레임이 권장 사항이므로 수정할 일은 거의 없다.


가장 중요한 부분은 아래의 코드이다.

[[CCDirector sharedDirector] runWithScene: [HelloWorldLayer scene]];


CCDirector는 싱글톤 객체이다.

runWithScene 메시지를 보내 어디서든 어떤 장면(Scene)이든 호출할 수 있다.

여기서는 HelloWorld Scene을 호출한다.

(2) HelloWorld Scene


예제로 생성한 HelloWorldLayer.h


HelloWorldLayer.h 파일에서 기억할 것은 다음의 내용이다.

HelloWorldLayer는 CCLayer를 상속받았다. 그리고 HelloWorld 자체가 레이어(CCLayer)이다.



예제로 생성한 HelloWorldLayer.m


HelloWorldLayer.m 파일에서 기억해야 할 것은 크게 2가지인데, 바로 scene과 init 메소드이다.

scene에서는 아래 내용을 알아두면 좋다. (하지만 cocos2d가 미리 만들어 놓았기 때문에 실제로 수정할 일은 거의 없음) 

1. 먼저, CCScene으로 장면(scene)을 생성한다.

2. 다음으로는 HelloWorld로 레이어(layer)를 생성한다.

3. 그 후 scene에 layer를 추가(addChild)한다.

4. 마지막으로 scene을 return하게 되는데, 이것을 받는 것이 바로 AppDelegate의 [HelloWorldLayer scene]이다.

즉, CCDirector가 runWithScene으로 HelloWorld라는 scene을 호출한 것이다.


init에서는 HelloWorld의 주요 작업을 하게 된다. (필요하다면 스케줄링이라든가, 애니메이션 같은 작업을 메소드로 만들어 쓰면 된다.)

예제로 만든 HelloWorld에는 cocos2d가 자동으로 만들어 넣은 label이 들어가 있는데, init에서 이 작업을 하고 있다.



PS

이 전의 튜토리얼에서도 참고할 내용은 있었지만, 더 이상의 진행을 할 수 없어 스터디를 새롭게 시작한다.

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #06  (0) 2012.10.23
cocos2d study #05  (0) 2012.10.23
cocos2d study #03  (0) 2012.10.22
cocos2d study #02  (0) 2012.10.22
cocos2d study #01  (0) 2012.10.22

cocos2d study #03




오늘은 본격적인 cocos2d 튜토리얼 코딩 따라하기다.

처음부터 알 수 없는 복잡한 소스코드가 흘러 넘쳤다. 첫 술에 배가 부를 수는 없으니 일단은 무작정 따라하기부터 해봤다.
코드의 내용은 물체를 움직이는 것이다.

-(void)addTarget {
    CCSprite *target = [CCSprite spriteWithFile:@"target.png" rect:CGRectMake(0, 0, 70, 70)]; 
    
    // 타겟(맘모스)의 Y축 위치 결정.
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    int minY = target.contentSize.height/2;
    int maxY = winSize.height - target.contentSize.height/2;
    int rangeY = maxY - minY;
    int actualY = (arc4random() % rangeY) + minY;
    
    // 오른쪽 끝 화면 밖에 X축 위치와 위에서 결정한 Y축으로 타켓의 포지션 결정.
    target.position = ccp(winSize.width + (target.contentSize.width/2), actualY);
    [self addChild:target];
    
    // 타겟의 속도 결정.
    int minDuration = 2.0;
    int maxDuration = 4.0;
    int rangeDuration = maxDuration - minDuration;
    int actualDuration = (arc4random() % rangeDuration) + minDuration;
    
    // 액션 생성.
    id actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-target.contentSize.width/2, actualY)];
    id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)];
    [target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}


이런 코드를 처음 볼 때의 막막함이란!

그러나 빌드 후의 결과는 대 실망이었다.

화면에 움직이는 물체가 나타날 것이리라 생각했지만, 아무런 변화도 없었고 모든 것이 멈춰 있었다.

코딩에 오타가 났거나, 무엇인가 빠진 것이 있을 것 같았다.

원인 파악에 많은 시간을 쏟았지만 어째서인지 전혀 이유를 알 수 없었다.

일단 튜토리얼 연습은 중단했다.



PS

코드가 제대로 실행되지 않아 스터디는 계속 진행할 수 없었다.

나중에 다른 블로그에서 같은 내용의 코드를 발견하고 (원본은 외국 사이트에 있다) 실행했을 때는 제대로 실행이 되었다. 아무래도 처음 발견했던 블로그의 내용에 잘못된 부분이 있었던 것인지, 의문이다.

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #06  (0) 2012.10.23
cocos2d study #05  (0) 2012.10.23
cocos2d study #04  (0) 2012.10.23
cocos2d study #02  (0) 2012.10.22
cocos2d study #01  (0) 2012.10.22

cocos2d study #02

무작정 따라하기


오늘의 목표는 튜토리얼 따라하기이다.


Hello World까지는 만들었으니, 이제 조금이나마 게임 냄새가 나는 프로그램을 만들어보자는 결심을 했다.

일단 작은 png 그림 파일을 화면에 띄우는 것까지는 성공했다.

그림 파일은 블로그에서 그대로 긁어와서 Xcode의 Resources 폴더에 넣어주었다.

그리고 아직은 의미를 알 수 없는 몇 줄의 소스 코드를 넣었다.

init 함수이니 무언가 초기화의 의미일 것이다.


대부분은 뭔 소리인지 알 수 없었고, 중간의 png 파일명과 Rect가 있는 부분은 파일명과 그림 사이즈일 것 같다.

어쨌든 연습 겸 익숙해질 겸 직접 코딩 후 Build and Run!

화면에 선글라스를 쓴 고릴라가 하나 보였다.

후후 성공이다.



스크린샷은 귀찮아서 그냥 퍼왔다. – 어차피 똑같다. 내 시뮬레이터가 아이폰 4라는 것만 빼면.




약간 뜬금없지만 좌표계에 대해 기록.

OpenGL 좌표계는 화면의 좌하단의 x, y 좌표가 (0, 0)이다.

아이폰에서는 이와 다르게 좌상단이 (0, 0)이다.


이외에도 강좌에 더 내용이 있지만 이해가 안 되니 우선은 패스.

init에서 아래와 같이 수정하라고 되어 있어 그대로 실행.

if ((self=[super initWithColor:ccc4(255,255,255,255)])) {



보통 RGB 색상 코드에서 255,255,255이면 흰색을 뜻하므로, 아무래도 흰색으로 도배가 될 것이다. 255가 4번 나오는 이유는 색상을 뜻하는 R, G, B 외에 Alpha 값이 포함되어 있어서일 것이다.

튜토리얼이 끝났으므로 오늘의 기록은 여기까지.



PS

튜토리얼에 뜬금없이 많은 용어가 갑자기 쏟아져 나와 혼란스럽다.

스프라이트는 알겠는데 (아마 옛날 8비트 컴퓨터에서 2d 게임을 만들 때의 그것일 듯) 다른 건 제대로 된 설명이 없었다.

아래에 그것들을 적어두었다.


레이어, 앵커포인트(anchor point), 프레임(frame), 바운드(bound), 위치(position), 모서리 반경(corner radius)


아직은 정확한 개념을 알 수 없으니 나중에 이 녀석들을 정확히 파악해야겠다.

'개발 > Cocos2d' 카테고리의 다른 글

cocos2d study #06  (0) 2012.10.23
cocos2d study #05  (0) 2012.10.23
cocos2d study #04  (0) 2012.10.23
cocos2d study #03  (0) 2012.10.22
cocos2d study #01  (0) 2012.10.22

+ Recent posts