프로그래밍/Cocos2D2010. 7. 2. 17:53
Cocos2D-iPhone 엔진은 원래 Python으로 작성된 2D 기반의 게임 라이브러리 인데 이 것을 아이폰 용으로 포팅한 것이 바로 Cocos2D-iPhone이다. 아이폰 게임 개발에 관심을 갖게 된다면 가장 먼저 접합게 되는 게임 엔진일 것이다. Cocos2D는 모바일 환경에서 그래픽 출력을 위한 OpenGL ES 및 사운드 출력을 위한 OpenAL 라이브러리를 손쉽게 게임 개발에 사용할 수 있도록 래핑한 것이다. 물론 다양한 기능을 지원한다. 이에 대한 내용은 사이트에서 확인 바란다.

단 0.8.X  버전에서 0.99.0(cocos2d for iPhone v0.99.0 Release Notes) 버전으로 업그레이드 되면서 CC라는 네임스페이스를 사용하기 시작했다는 점에 주의해야 한다. 0.99.0 이전의 인터넷 자료를 참고한다면 샘플 소스에서 차이가 날 것이다.

이와 관련된 내용과 기본적인 사용법(Hello World, Hello Actions, Hello Events 등등) 등을 공부하고 나면 바로 다음 단계가 궁굼해 진다. "그럼, 어떻게 게임을 만들지?", 물론 사이트에 샘플 게임 소스가 공개되어 있긴 하지만 이제 막 게임 개발에 입문한 개발자에게는 그리 녹녹치 않다.

부분적으로 API를 훓어 본다고 해결될 문제도 아니다. 이에 대한 가장 좋은 해결책은 최대한 단순한 게임 형태를 살펴보는 것이 전체적인 사용법과 이해도를 높이는데 훨씬 많은 도움이 될 것이다. 

본 포스트는 "How To Make A Simple iPhone Game with Cocos2D Tutorial"의 내용을 한글로 재구성 한 것이며, 좋은 글을 공개해준 저자에게 감사 드린다. 이외에도 게임 개발과 관련된 유용한 정보가 상당히 많다. 기회가 된다면 다른 내용도 이와 유사한 형태로 포스팅해 볼 계획이다.

* 부분적으로 설명이 생략된 부분은 마지막 포스트 하단에 첨부한 샘플 프로젝트로 설명을 갈음한다.

우선 사전 준비부터 시작하자.
1. Cocos2D 다운로드 및 설치(현재 안정 버전: 0.99.1)

프로젝트 생성
MammothHunting이라는 이름으로 신규 프로젝트 생성. 물론 Cocos2D 템플릿을 이용한다.


이 상태에서 빌드앤런 하면 다음 화면을 볼 수 있을 것이다. 이미 알고 있는 것처럼 Hello World 예제이다.


이제 게임 개발에 관심을 갖는 단계라면 Xcode의 사용법은 익숙할 것이다. 자세한 설명은 생략한다.

Sprite 추가
* Director, Scene, Layer, Sprite 네 개의 클래스는 Cocos2D에서 게임 화면의 구성을 위한 가장 중요한 것 들이다. 이와 관련된 기본 내용은 숙지하자. 다행히도 미리 고생해 준 분이 계시다.

스프라이트를 추가하기 전에 다음 세 단계를 먼저 진행한다. 물론 기존 템플릿 코드로 진행해도 되지만 생애 최초의 게임을 만드는 마당에 네이밍도 중요하지 않은가? 

첫째, 다음 세개의 그림을 Resources에 추가한다.



둘째, MammothHuntingAppDelegate.m 파일을 열어 applicationDidFinishLaunching: 메소드에서 템플릿이 생성해준 맨 아래의 [[CCDirector sharedDirector] runWithScene: [HelloWorld scene]]; 코드를 다음과 같이 수정한다.

CCScene *scene = [CCScene node];

CCLayer *layer = [MammothHuntingScene node];

[scene addChild:layer];

[[CCDirector sharedDirectorrunWithScene: scene];


세째, HelloScene.h와 HelloScene.m 클래스 파일을 삭제한다. 그리고 NSObject의 서브 클래스로 MammothHuntingScene.h와 MammothHuntingScene.m 클래스를 생성한다. 다음은 MammothHuntingScene.h 클래스에서 "cocos2d.h"를 임포트 하고 CCLayer를 상속하도록 수정한다. MammothHuntingScene.m에 다음 init 메소드를 추가하고, 다시 빌드앤런!

-(id) init {

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

CGSize winSize = [[CCDirector sharedDirectorwinSize];

CCSprite *player = [CCSprite spriteWithFile:@"player.png" rect:CGRectMake(005055)];

player.position = ccp(player.contentSize.width/2, winSize.height/2);

[self addChild:player];

}

return self;

}


아마도 문제가 없다면, 다음 화면을 접할 수 있을 것이다.


잘 보이지 않겠지만, 고릴라이다. 인터넷에서 무료로 구할 수 있는 아이콘을 활용했다. 원하는 그림으로 변경해도 튜토리얼을 진행하는 데는 전혀 지장이 없다. 단 그림 사이즈와 rect 사이즈는 동일해야 한다.

여기서 잠깐, 좌표계에 대해서 공부하고 다음 단계로 넘어가자. 화면의 위치를 이동하거나 지정할 때 Cocos2D에서는 좌표계에 주의해야 한다. UIView를 사용하는 일반적인 아이폰 앱은 UIView 좌표계를 사용하며 UIView에서는 좌측 상단(0, 0)이 원점이다. 즉, 오른쪽으로 가면서 x 값이 증가하고 아래로 갈 수록 y 값이 증가한다. 이와는 달리 Cocos2D는 OpenGL을 사용하므로 좌표계의 원첨이 좌측 하단 위로 갈수록 y 값이 증가한다.

위 내용을 그림으로 표현하면 다음과 같다. 나중에 좌표계를 변환해야 하므로 기억해 두어야 한다.


좌표계를 기준으로 플레이어(고릴라)의 위치는 init 메소드에 다음과 같이 설정했다.

player.position = ccp(player.contentSize.width/2, winSize.height/2);


여기서 플레이어(고릴라)의 스프라이트의 앵커포인트(anchorPoint: 고정점)의 x, y 좌표를 위와 같이 설정했다. 앵커 포인트는 모든 변환 및 위치 조작의 중심점인데, 상위 레이어에 부착한 레이어 상의 핀으로 생각하면 된다. 

레이어 관련하여 프레임(frame), 바운드(bounds), 위치(position), 고정점(anchorPoint), 모서리 반경(cornerRadius), 레이어 높낮이(zPosition) 등의 기하 관련 속성에 대한 이해가 전제되어야 하는데, 이는 Core Animation의  Layer Geometry and Transforms 부분을 참고하라.

다음 작업은 배경화면 변경이다. 검정색 배경을 흰색으로 변경할 것이다.
프로젝트에서 MammothHuntingScene.h 클래스 파일을 열어 다음과 같이 CCColorLayer를 상속 받도록 수정한다.

#import "cocos2d.h"



@interface MammothHuntingScene : CCColorLayer {


}


@end


그리고 MammothHuntingScene.m 클래스의 init 메소드의 if 조건을 다음과 같이 수정한다.

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


이제 다시 빌드앤런 하면 다음 그림과 같이 흰색 배경화면을 볼 수 있을 것이다.


"Cocos2D를 사용한 아이폰 게임 개발 튜토리얼 1"은 이것으로 마무리 하고 "Cocos2D를 사용한 아이폰 게임 개발 튜토리얼 2"에서는 타켓과 총알 발사에 관해서 살표 보겠다. 하나의 포스트로 진행하기에는 내용이 너무 많은 것 같아 4 단계 정도로 나누어서 포스팅할 계획이다.

---

Posted by windship
프로그래밍/Objective-C2010. 6. 25. 00:37
이전에 포스팅한 "NSXMLParser로 RSS 읽어오기"와 유사한 방법으로 구글 날씨 RSS를 가져오는 것을 만들어 보았습니다. 그런데 한글이 깨져나와 확인해 보니 문자셋이 euc-kr이었습니다. 문자셋을 확인하는 방법은 URLConnection의 델리게이트 메소드에서 확인할 수 있습니다.
  1. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
  2.     NSLog(@"Encoding: %@"[response textEncodingName]);
  3. }

전송이 끝난 후에 아래와 같이 NSData를 euc-kr을 utf-8로 변환하여 사용할 수 있습니다. 변경된 data를 NSXMLParser의 initWithData의 인자로 사용하면 됩니다.
  1. - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
  2.     NSString *str = [[NSString alloc] initWithData:receiveData encoding:0x80000000 + kCFStringEncodingDOSKorean];
  3.     NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
  4.    
  5.     NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
  6. .
  7. .
  8. .
  9. }

한가지 이상한 점은 웹브라우저에서 확인하면 같은 URL이지만 utf-8로 넘어 옵니다. 아마 서버에서 헤더를 검사에서 각각 다른 인코딩으로 넘겨주는 것이 아닌가 하는 생각이 듭니다. 헤더의 항목들을 변경해서 보았는데 User-Agent를 설정해서 보내보니 euc-kr이 아닌 utf-8로 넘어 왔습니다.
  1.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURLURLWithString:@"http://www.google.com/ig/api?weather=seoul"]];
  2.      
  3.     [request addValue:@"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ko; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2" forHTTPHeaderField:@"User-Agent"];
  4.  
  5.     xmlConnection = [[NSURLConnection alloc]
  6.                      initWithRequest:request
  7.                      delegate:self];


구글의 날씨 API에서는 이와 같이 User-Agent를 보내면 utf-8로 보내기때문에 위와같이 인코딩의 변환이 필요하지 않습니다. 아마 예측가능한 User-Agent는 utf-8로 보내고 그외에는 euc-kr로 보내는 것 같습니다. 이는 영문도 마찬가지이며 http://www.google.com/ig/api?weather=seoul와 같이 co.kr에서 com으로 변경하면 문자셋이 iso-8859-1로 넘어 옵니다. User-Agent를 추가하면 역시 utf-8로 넘어 옵니다.



이전부터 그냥 복사해서 올렸는데 오늘 보니 아래와 같이 나오는 건 너무 보기가 힘든 것 같아서, 예제코드를  Quick Highlighter를 사용해서 정리해 보았습니다.
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com/ig/api?weather=seoul"]];
     
    [request addValue:@"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ko; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2" forHTTPHeaderField:@"User-Agent"];

    xmlConnection = [[NSURLConnection alloc] 
                     initWithRequest:request 
                     delegate:self];

보기도 조금 나아지지만 해당 클래스에 대한 애플의 문서로 바로 링크가 되는 것도 좋은 것 같습니다.

Posted by windship
프로그래밍/Objective-C2010. 6. 25. 00:32
아이폰 3.0 SDK 부터는 accelerometer를 사용하지 않고도 UIResponder에 추가된 motion 이벤트 처리 메소드를 구현함으로써 간단하게 사용자의 흔들기 동작을 체크할 수 있습니다. 저도 처음 사용해 보면서 간단한 내용들을 정리해 보았습니다.

1. First responder 되기
사용자의 흔들기 이벤트를 처리할 ViewController는 그 자신이 First responder가 되어야 합니다. becomFirstResponder 메소드를 호출하고 canBecomeFirstResponder 메소드에서 YES를 반환합니다.

  1. - (void)viewDidAppear:(BOOL)animated {
  2.     [super viewDidAppear:animated];
  3.     [self becomeFirstResponder];
  4. }
  5.  
  6. - (BOOL)canBecomeFirstResponder {
  7.     return YES;
  8. }

viewDidAppear는 코드에서 서브뷰로 추가될 때만 호출됩니다. IB에서 바로 Window에 View를 추가하였으면 awakeFromNib등의 메소드에서 becomFirstResponder를 호출하셔야 합니다.

2. motion 메소드 구현
이후로는 간단합니다. 사용자의 흔들기가 시작되면 해당 motionBegan이 호출되고 종료될 때 motionEnded가 호출됩니다. 지나치게 많이 흔들거나 하여 유효하지 않은 흔들기로 판단될 때는 motionCancelled가 호출됩니다.

  1. - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
  2.     NSLog(@"Shaking start");
  3. }
  4.  
  5. - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
  6.     NSLog(@"Shaking end");
  7. }
  8.  
  9. - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
  10.     NSLog(@"Shaking cancel");  
  11. }
  12.  

motionEnded 메소드에 사용자의 흔들기가 끝난 후 실행할 코드를 추가하면, 간단하게 흔들기를 지원할 수 있습니다.

Posted by windship
프로그래밍/Objective-C2010. 6. 25. 00:29
1. 빌드시 시뮬레이터 판별

#if !TARGET_IPHONE_SIMULATOR
pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
#endif
TARGET_IPHONE_SIMULATOR로 실제 아이폰에서만 실행되는 코드를 따로 관리할 수 있습니다. 

2. 하위 View 검색

NSArray *subViewList = [searchBar subviews];
for (UIView *view in subViewList) {
    if ([view isKindOfClass:[UITextField class]]) {
        [(UITextField *)view setReturnKeyType:UIReturnKeyDone];
    }    
}
UIView의 subviews와 isKindOfClass를 사용하여 하위의 특정 뷰를 찾아내어 설정을 변경할 수 있습니다. UISearchBar에서 UITextField를 찾아내어 키보드의 Search 버튼의 텍스트를 Done으로 변경하는 예입니다.

- (void) setSubViewsClearColor: (UIView*)theView {
   NSArray *subViewList = theView.subviews;
   for (UIView *view in subViewList) {
       [view setBackgroundColor:[UIColor clearColor]];
       [self setSubViewsClearColor:view];
   }
}
하위 View를 모두 찾아 배경을 투명한 속성으로 변경하는 예입니다. 
초기화 하는 곳에서 [self setSubViewsClearColor:self]; 와 같이 호출하여 사용합니다.
  
 
3. 사용자 데이터 저장

userLevel = [[NSUserDefaults standardUserDefaults] integerForKey:@"user_level"]; 
[[NSUserDefaults standardUserDefaults] setInteger:g_userLevel forKey:@"user_level"];
옵션등의 간단한 설정은 데이터베이스나 파일을 이용하는대신 NSUserDeraults를 사용하면 간단하게 저장하고 불러올 수 있습니다.

4. Rect와 Point
좌표로 많이 사용되는 Rectd와 Point에서 자주 사용되는 함수와 상수입니다.

CGRect  CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);
x, y, width, height로 설정된 CGRect를 반환합니다.

CGRectZero
0, 0 좌표와 0, 0 크기를 가진 CGRect 상수입니다.

CGPointMake(CGFloat x, CGFloat y);
x, y로 설정된 CGPoint를 반환합니다.

CGPointZero
0, 0 좌표를 가진 CGPoint 상수입니다.

bool CGRectContainsPoint(CGRect rect, CGPoint point);
rect 사각형에 point가 속해있는지 여부를 반환합니다.

bool CGRectContainsRect(CGRect rect1, CGRect rect2);
rect1 사각형에 rect2 사각형이 속해있는지 여부를 반환합니다.

bool CGRectIntersectsRect (CGRect rect1,  CGRect rect2);
rect1과 rect2가 교차하는지 여부를 반환합니다.


5. Path

NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
어플리케이션 번들 디렉토리를 반환합니다.

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
번들에 포함된 파일들은 읽기만 가능하고 쓰기가 불가능합니다. 디비와 같이 변경이 필요한 경우에는 위와같이 어플리케이션의 도큐먼트 폴더를 구해와 도큐먼트 폴더로 복사 생성해 놓고 작업합니다.


6. URL

NSURL *url = [NSURL URLWithString:@"http://www.cocoadev.co.kr"];
[[UIApplication sharedApplication] openURL:url];
지정된 웹주소를 사파리에서 오픈합니다.

NSURL *url = [NSURL URLWithString:@"mailto:abc@def.com"];
[[UIApplication sharedApplication] openURL:url];          
받는사람이 설정되어 메일 프로그램의 새로운 메시지가 실행됩니다.

NSURL *url = [NSURL URLWithString:@"tel:02-111-2222"];
[[UIApplication sharedApplication] openURL:url];
지정된 번호로 전화를 겁니다.

Posted by windship
프로그래밍/Cocos2D2010. 1. 20. 22:46
개발Q&A / 2010.01.19 21:55 / drkhero79 / http://cafe.naver.com/mcbugi/27576  

코코스2D엔진에서 스프라이트 애니메이션 할때 스프라이트에 애니메이션 등록해놓고 사용하잖아요
근데 CCRepeatForever actionWithAction을 이용하면 모든 프레임을 전부다 처음부터 끝까지 반복재생해주잖아요..

[sprite runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO] ]];
 
그렇게 하지않고 특정 한 프레임 만 계속 띄워놓는 다든지 첫번째 프레임만 선택해서 계속 보이게 한다던지 혹은 2~5번째 만 선택적으로 재생한다던지 하는 선택 재생 방법은 없는 건가요?
 
또다른 질문은 aniframe으로 프레임을 만들고 aniframe2를 만들어서..
처음엔 aniframe으로 애니를 재생하다가 특정 이벤트가 발생되면 aniframe2로 교체해서 애니메이션을 재생해주는
그런 방법은 없는것 인가요?

제가 테스트 해볼라고 간단히 작성해본것 입니다.



CGSize size = [[CCDirector sharedDirector] winSize];

    //애니메이션에 필요한 이미지 파일로딩    
    CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:@"walk.png"];
    CCTexture2D *texture1 = [[CCTextureCache sharedTextureCache] addImage:@"dive.png"];
    
    // manually add frames to the frame cache
   //걷는 그림 프레임 세팅
    CCSpriteFrame *frame0 = [CCSpriteFrame frameWithTexture:texture rect:CGRectMake( 25*0, 0, 25, 66 ) offset:CGPointZero];
    CCSpriteFrame *frame1 = [CCSpriteFrame frameWithTexture:texture rect:CGRectMake( 25*1, 0, 25, 66 ) offset:CGPointZero];
    CCSpriteFrame *frame2 = [CCSpriteFrame frameWithTexture:texture rect:CGRectMake( 25*2, 0, 25, 66 ) offset:CGPointZero];
    
  //다이빙하는 그림 프레임 세팅
    CCSpriteFrame *frame_0 = [CCSpriteFrame frameWithTexture:texture1 rect:CGRectMake( 0, 0, 25, 40 ) offset:CGPointZero];
    CCSpriteFrame *frame_1 = [CCSpriteFrame frameWithTexture:texture1 rect:CGRectMake( 45, 0, 25, 40 ) offset:CGPointZero];
    CCSpriteFrame *frame_2 = [CCSpriteFrame frameWithTexture:texture1 rect:CGRectMake( 80, 0, 25, 40 ) offset:CGPointZero];
    CCSpriteFrame *frame_3 = [CCSpriteFrame frameWithTexture:texture1 rect:CGRectMake( 118, 0, 25, 40 ) offset:CGPointZero];
    
   //기본으로 걷는 첫번째 프레임이미지으로 스프라이트 세팅한다.
    CCSprite *sprite = [CCSprite spriteWithSpriteFrame:frame0];
    sprite.position = ccp( size.width/2-80, size.height/2);
    [self addChild:sprite];
    
   //걷는 프레임으로 세팅한 이미지를 에니메이션으로 할당한다.
    NSMutableArray *animFrames = [NSMutableArray array];
    [animFrames addObject:frame0];
    [animFrames addObject:frame1];
    [animFrames addObject:frame2];
 
     //다이빙하는 프레임으로 세팅한 이미지를 애니메이션으로 할당한다.   
     NSMutableArray *animFrames1 = [NSMutableArray array];
    [animFrames1 addObject:frame_0];
    [animFrames1 addObject:frame_1];
    [animFrames1 addObject:frame_2];
    [animFrames1 addObject:frame_3];
    
   //애니메이션 변수 할당
    CCAnimation *animation;

    switch([(CCMenuItemFont*)sender tag])    // callBack에 들어온 sender를 위에 아이템과 같은 형으로 변환을 한다.
    {
        case 0:    //걷는 프레임 재생
            animation = [CCAnimation animationWithName:@"run" delay:0.2f frames:animFrames];
            [sprite runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO] ]];
            break;
            
        case 2:   //다이빙하는 프레임 재생
            animation = [CCAnimation animationWithName:@"dive" delay:0.2f frames:animFrames1];
            [sprite runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO] ]];
            break;

    }
 
작동 방식좀 알아볼겸 해서 이렇게 간단히 작성해봤네요..
당연히 구조 변경할거구요..어떻게 동작하는지 보려고 대충 작성해본거니까 머라고 욕은 마세요^^;;;

암튼 위의 소스를 보면 저의 질문이 파악될지 모르겠네요.

이렇게 하니까 0일경우 걷는 프레임을 재생하고 2일경우는 다이빙을 재생하지만..
메모리에서 헤제를 안하고 계속 이전 애니메이션이 재생됩니다. 걷는것도 계속나오고 다이빙하는것도 계속나옵니다.

걷기를 하다가 중간에 다이빙동작으로 바꾼다는지 하는 방법이 무엇이며..

혹은 걷거나 다이빙 하는 프레임중 1~2프레임만 반복한다든지 1번프레임만 정지상태로 계속 보이게 하고도 싶습니다.

어떻게 하면될까요? 화면상에서 지워지지 않는 문제도 있네요..어떻게 하면되는지요^^

고수님들의 좋은 답변 부탁드려요~
 
에어조단(ckw0507) / 2010.01.19 23:43

애니 메이션 등록을 
CCAnimation *aniWaitRight = [[CCAnimation alloc] initWithName:@"waitRight" delay:0.1];
[aniWaitRight addFrameWithFilename:@"0r.png"];
[aniWaitRight addFrameWithFilename:@"9r.png"];
[self addAnimation:aniWaitRight];
[aniWaitRight release];
이런식으로 하시고 사용하실때는 아래처럼..하시면 될꺼에요.
[self stopAllActions];
[self setDisplayFrame:@"waitRight" index:waitFrame%2];
waitFrame++;
if(waitFrame > 1) waitFrame = 0; 

schedule 을 등록하여 위에방법대로 count 를 이용하여 사용하는 방법이 있을것 같네요.

---
GTekna Corp(gtekna) / 2010.01.20 08:42

Animation 변수를 하나만 사용하지 마시고, 걷는 것과 다이빙에 쓰일 것으로 두 개를 만드세요.   Animation은 미리 만들어 놓고 재 사용하는 것이 좋습니다. 안 그러면, performance에 조금 지장이 있지요.

Posted by windship
프로그래밍/Cocos2D2009. 11. 7. 14:44
cocos2d Texture2d 에 대한 질문입니다. ^^; | i개발Q&A
0 / 2009.10.19 21:02
조금 밑에 어플개발시 메모리에 관한 질문을 보시면 제가

1024 * 1024 * 32비트  PNG 가 엑티비티 모니터링 시 리얼메모리 12메가를 잡아먹는다고 적어놨었습니다.

이에대해 채원아빠님께서 1024 * 1024 * 32비트면 약 4메가 정도 먹지않겠냐 라고 답변 다셨는데

저도 어제 약 4메가정도 먹어야 정상일텐데 왜 12메가 인지 한참 고민해었습니다.  결국 어차피 컴퓨터가 맞겠지 하고 -_- 

넘어가려고 하기도했었구요.. (이유를 못찾았었습니다.)

그러다 오늘 채원아빠님께서 말씀하신거 보고 제가 계산을 잘못한게 아니라고 생각해서  테스트를 실시했습니다.

지금 사용중인 어플은 OpenGL로 만들고있지만 실제로는 cocos2d의  Texture2d.h를 가져와서 활용하고있습니다.

그래서 일단 cocos2d  프로젝트를 열고  AtlasSpriteManager로 똑같은 이미지(1024 * 1024 * 32) 를 얹어보았더니 약 4메가가

리얼메모리에 추가된걸 확인할수있었습니다.

같은 파일을 가지고 Texture2d의 initwithImage를 사용해 불러오니 리얼메모리에 12메가가 추가되는 것도 확인할수있었습니다.

혹시 이런 문제로 고민하셨던 적이 있으신 분이 있으신가 해서 글 남깁니다. -ㅁ-... 또  저같이 texture2d.h를 활용하고계신분이라면

더더욱이.. .........................................................

이제 AtlasSprite와 Texture2d의 차이점을 확인하러가야겠습니다. ㅜ_ㅜ

작성자의 카페글 더보기

.....없어그런거..
덧글 4개 | | 조회수 108 | | 추천 0 나도추천
 담기 | 인쇄 | 신고
  • 2009/10/19 21:09

    답글|신고

    아하... 그랬었군요... ^^;................... (도움은 못드려서 ㅈㅅ.... 쩌비... )
    상황파악이 되셨으니, 어렵지않게 해결하시리라 생각되네요...

    하루에 한시간씩 시간투자를 하는데... gl study 할시간은.. ㅡ,ㅡ;;;;;;;;;;;..........

    힘 내세요...
    ^^;...................................

  • 2009/10/19 21:30

    답글|신고

    저도 굉장히 궁금한 부분이네요.
    역시 cocos2d를 사용하고 있고..게임의 규모가 커지다보니 슬슬 메모리의 압박이 시작되는 것 같아서요..
    혹시 알게 되시면 소중한 정보 공유해주시면 정말 감사하겠습니다. (_ _);;

  • 2009/10/19 22:39

    답글|신고

    해결했습니다. 대충 답이 맞는지 어쩐지는 확신은 없으나 일단 용량문제나 실행상의 문제는 전혀없게됐습니다.
    대충 문제의 원인에 대해 말씀드리자면.. 해당 이미지를 불러올때..
    _texture[0] = [[Texture2D alloc] initWithImage:[UIImage imageNamed:@"A.png"]];
    이런식으로 불러옵니다. [Texture2D alloc] <- 이부분에서 한번 메모리를 추가하죠..
    [UIImage imageNamed:파일이름] 이녀석의 정의를 보면 + (UIImage *)imageNamed:(NSString *)name; 입니다.
    안을 열어볼순없지만 alloc를 한다는 거죠; initWithImage안을 보면 UIImage ImageNamed:""로 불러온 녀석의 메모리를
    해제하는 코드가 없더군요.. 해결방법은 맨 마지막줄 reutrn self; 전에 [uiImage release]; 한줄 추가해주시면 됩니다.
    cocos2d라이브러리 템플릿 사용하시는 분은 처음 라이브러리 만드시는 단계에서 수정하셔서 시뮬레이션 - cocos2d
    디바이스 - cocos2d 를 해주신후에 나온 라이브러리 파일과 함께 Texture2D.h파일을 복사해서 덮어쓰시면 됩니다.

  • 2009/10/19 22:58

    신고

    ^^;.................... 그렇군요... ㄳㄳ...

Posted by windship
프로그래밍/Cocos2D2009. 11. 6. 21:00
Posted by windship
프로그래밍/Cocos2D2009. 11. 6. 20:46
게임 제작의 중심은 주로 그림을 어떻게 표현하느냐,

뭐가 화면에 보여야 내가 제대로 만들고 있는건지 알 수 있는거 아닐까?

iPhone 게임 개발로 많이 사용되는게 cocos2D 라는 라이브러리이다.

현재 0.8.1 버전까지 나온 상태다.

http://appsnet.co.kr/bbs/cocos2d


여기 개발자 포럼에 상세하게 cocos2D의 개발환경 설정부터 

애니메이션 구현까지의 강좌가 설명되어있다.

어제까지 아이폰 시뮬레이터에 메뉴를 만들어서 띄우는 것까지 해보았다.

다음은 메인 소스이다.
//
//  Cocos2DAppDelegate.m
//  Cocos2D
//
//  Created by MOAi on 09. 10. 8..
//  Copyright 전북대학교 2009. All rights reserved.
//

#import "Cocos2DAppDelegate.h"
#import "cocos2d.h"

@implementation Cocos2DAppDelegate

@synthesize window;


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

    // UIWidow 개체를 생성
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    // Director에서 사용할 View등록
    [[Director sharedDirector] attachInView:window];
    
    // HelloScene 생성
    Scene *helloScene = [Scene node];
    
    // hello world 라벨 만들기
    Label *helloLabel = [Label labelWithString:@"Hello World of Cocos2d."
                                      fontName:@"Helvetica" fontSize:20.0f];
    helloLabel.position = ccp(150,200);    // 위치 지정(가운데를 글자의 가운데 부분을 위치시켜야함)
    //[helloScene addChild:helloLabel];
    //초록색 코드는 맨처음 헬로우 월드 찍어보는 코드이고 라벨 사용법을 알기 위해서 코드를 남겨 놓았음


    // 이 부분을 강좌 잘 따라해가면서 만들어봤음 전체 소스가 없어서 고민해서 만드느라 시간이 상당히 오래걸렸다.
    // 기본 메뉴 아이템 설정
    [MenuItemFont setFontSize:30];
    [MenuItemFont setFontName: @"Courier New"];
    
    // 메뉴 아이템
    MenuItem *item1 = [MenuItemFont itemFromString: @"시작" target:self selector:@selector(menuStartCallback:)];
    MenuItem *item2 = [MenuItemFont itemFromString: @"환경설정" target:self selector:@selector(menuConfigCallback:)];
       
    
    // 메뉴를 담는 레이어(메뉴는 배열 형식)
    Menu *menu = [Menu menuWithItems: item1,item2, nil];
    
    //[menu alignItemsInRows:(NSNumber *)2];
    [menu alignItemsInRows:[NSNumber numberWithInt:2],nil];
    
    // 메뉴의 위치설정
    //menu.position = ccp(100,300);
    
    // 메뉴들의 위아래 간격 조절
    //[menu alignItemsVerticallyWithPadding:100.0f];
    


    // 씬에 메뉴를 추가(메뉴가 레이어를 상속받기때문에 다른 레이어 추가없이 추가 가능)
    [helloScene addChild:menu];

    // HelloScene을 실행
    [[Director sharedDirector] runWithScene:helloScene];
    
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}
                        
-(void) menuStartCallback: (id) sender
{
    NSLog(@"called start menu");
}                        

-(void) menuConfigCallback: (id) sender
{
    NSLog(@"called config menu");
}

- (void)dealloc {
    [window release];
    [super dealloc];
}


@end



빌드하고 실행하면 다음과 같이 시뮬레이터에 코드에 작성한 것처럼 

시작과 환경설정이란 메뉴가 나타난다.

왼쪽화면은 메뉴를 클릭했을때 콜백메소드를 제대로 호출하는지 확인하기 위해 띄운 콘솔창

위 스샷과 같이 메뉴를 누를때마다 콜백메소드가 잘 호출되고 있는게 보인다.

일단 인트로 화면이 이렇게 구성이 되어야 하는데. 메뉴 글자부터 짤라서 이미지나 만들어 놓을까


 
Posted by windship
프로그래밍/Cocos2D2009. 11. 6. 16:45
2009.08.11 22:24:12(*.76.17.162)
조회수:1509

 이번 강좌는 Ease Actions와 Misc Actions 라는 Action들을 배울 것이다. 그런데 생각보다 어렵다. 잘 이해가 되지 않는 것은 예제도 실행해보면서 다시한번 살펴봐라. 그리고 그래도 이해가 되지 않는다면 댓글을 달아주시길...


그럼 강좌를 시작하겠다. 


Cocos2d로 애니메이션 구현하기 3


3. Ease Actions


Ease Action은 애니메이션을 구현하는 속도에 관련된 Action들이다. 이제까지 알아본 것은 모두 기본 속도 1로 작동하는 것들인데 Ease Action을 통해서 애니메이션을 점점빠르게 갑자기 빠르게 등을 구현해 볼 수 있다. 

3.1 EaseIn / EaseOut


EaseIn은 이동이나 변환등의 액션을 처음에는 천천히 시작했다가 점점 빨라지는 애니메이션을 구현한다. 그러니까. 점점 빨라지는 Action 이다. Move Action을 사용하면 쉽게 이해할 수 있는데 특정 지점으로 이동하는 Action을 EaseIn에 등록하고 실행시키면 해당 지점으로 빨려들어가듯이 점점 빨리 움직이는 것을 볼 수 있다. EaseOut은 EaseIn과 반대로 처음에는 빨리 시작되었다가 점점 느려지는 애니매이션을 구현한다. Move Action에서 다시 생각해 보자면 특정 위치에서 빨리 빠져나와서 점점 지정된 위치로 이동하는 것으로 이해하면 쉽게 이해할 수 있을 것이다. 

다음 그림을 보면서 이해를 하도록 노력해 보자. x축은 시간이고 y축은 전체를 1로 봤을 때 처리한 프레임 수의 비율이다. 만약 Move라면 이동한 거리라 볼 수 있고, Rotate라면 회전한 각도 비율이라 볼 수 있다.

EaseInOut.png 

파란색은 EaseIn을 빨간색은 EaseOut의 Rate계산식을 나타낸 것이다. 그리고 가운데 검은 선은 기본 애니메이션 구현속도이고, 양 옆의 희미한 색의 그래프는 rate값을 좀더 크게했을 때의 속도그래프이다. 이 그래프를 보면 알 수 있듯이 EaseIn은 처음에는 느린 속도로 애니메이션하다가 점점 빠르게 애니메이션을 구현한다. EaseOut은 이와 반대로 처음에는 매우 빠른 속도로 애니메이션을 구현하다가 점점 느린 속도로 구현되도록 계산하는 것을 확인할 수 있다. 
 

사 용방법은 다음과 같이 Action을 하나 만들고 그 Action을 [EaseIn actionWithAction:rate:]에 입력되는 Action을  rate만큼의 로그 비율로 점점 빨라진다. rate의 값이 크면 클 수록 처음에는 더 느리고 중간 이동하는 속도가 더 빨라진다.

    id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
    id move_ease_in = [EaseIn actionWithAction:[[move copy] autorelease] rate:3.0f];
    [someSprite runAction:move_ease_in];

EaseOut도 동일한 방법으로 구현할 수 있다. 단, rate값이 크면 클 수 록 처음에 실행되는 애니메이션의 속도가 빨라지고 중간에 이동하는 속도는 급격히 떨어진다.


다음은 EaseIn/EaseOut이 실행되는 화면이다.

맨 위는 EaseIn을 두번째는 EaseOut을 세번째는 비교를 위해 기본 속도의 애니메이션을 출력한 것이다. 

(용량상 캡춰를 짧게 해서 잘 모를지도 모른다. 그럴 경우에는 밑에 소스를 첨부했으니 실행해 보자.)


3.2 EaseInOut


EaseInOut은 EaseIn과 EaseOut을 연속해서 실행하는 것과 동일한 결과를 얻을 수 있다. 처음에는 느리게 실행되었다가 점점 속도가 빨라졌다가 다시 점점 느려지는 애니메이션이 구현된다. 


다음은 실행되는 화면이다.

처음은 비율을 3.0f로 했을 경우이고 두번째는 5.0f로 했을 경우이다. 어떻게 차이가 있는지 비교해 볼 수 있다. 


3.3 EaseSineIn / EaseSineOut


EaseSineIn과 EaseSineOut은 EaseIn과 EaseOut의 rate를 Sine값으로 대체한 것이다. 그래서 Sine그래프처럼 처음에는 느리게 실행되다고 점점 빨라지다가 다시 느려지고, 말로 설명을 하려니까. 좀 힘이 든다. ㅜㅜ. 

다음의 이미지는 실제로 SineIn과 SineOut을 할 때 식의 그래프이다.

EaseSine.png 

빨간색이 SineIn의 애니메이션의 속도 변화값이고, 파란색이 SineOut의 애니메이션의 속도 변화값이다. 그리고 검은색은 Rate가 1일 때 일반적인 속도를 나타낸 것이다. 
이 그림을 보면 대충 짐작하겠지만 SineIn은 기본 애니메이션보다 느리게 출발하지만 점점 빨라지고, SineOut은 처음에는 빨리 출발하지만 점점 느려진다.

다음에 실행되는 화면을 추가할 테니 보시면서 잘 이해하길 바란다. ^^;;;


구현하는 방법은 다음과 같이 단순히 속도 조절을 원하는 Action을 입력받는다.

    id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
    id move_ease_in = [EaseSineIn actionWithAction:[[move copy] autorelease]];
    [someSprite runAction:move_ease_in];


다음은 실행되는 화면이다.

위의 것이 EaseSineIn이고 중간의 것이 EaseSineOut이고 마지막의 것이 기본 속도로 움직이는 것이다. 


3.4 EaseSineInOut


EaseSineInOut은 EaseSineIn과 EaseSineOut을 합쳐놓은 것과 같은 속도로 애니메이션을 구현하고 이를 계산하는 식의 그래프는 다음과 같다. 

EaseSineInOut.png 

구현하는 방법은 EaseSineIn이나 EaseSineOut과 동일하다.


다음은 실행되는 화면이다. 

 


3.5 EaseExponential


EaseExponential은 영어를 해석하자면 지수적인이란 접미어가 붙었는데 말그대로 지수로 애니메이션의 속도가 변한다. 그러므로 급격히 빨라지거나 급격히 느려지는 것을 구현할 때 사용하면 된다. 
다음은 EaseExponentialIn과 EaseExponentialOut의 속도 계산식을 그래프로 그린 것이다. 


EaseExponetial.png

빨간색이 EaseExponentialOut을 파란색이 EaseExponentialIn의 속도 변화를 그린 것이다. 그래프를 봐서 쉽게 이해되지 않는다면 다음 애니메이션을 참고해보자.

구현하는 방법은 EaseSine과 동일하게 속도를 변화하려는 Action만을 다음과 같이 입력하면 된다. 

    id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
    id move_ease_in = [EaseExponentialIn actionWithAction:[[move copy] autorelease]];
    [someSprite runAction:move_ease_in];


다음은 실행하는 화면이다.

 맨위가 EaseExponentialIn이고 두번째가 EaseExponentialOut이고 세번째에 비교를 위해서 기본 속도의 애니를 추가했다.



3.6 EaseExponentialInOut


EaseExponentialInOut 은 EaseExponentialIn과 EaseExponentialOut을 연속해서 실행시킨 것과 동일한 기능을 한다. 먼저 처음에는 느리게 시작되다가 갑자기 빨라지다가 목적지에 거의 도달해서 갑자기 느려진다. 초기위치에 도달위치를 알려주고 순간이동과 같은 경우를 구현하고자 할 때 사용하면 좋을 것 같다. 

실행하는 방법은 EaseExponentialIn이나 EaseExponentialOut과 같다. 

3.7 Speed


Speed는 Action의 속도를 중간 중간에 변경할 때 유용하게 사용할 수 있다. 초기에 생성시에 [Speed actionWithAction:speed:]로 해당 Action을 speed파라미터로 입력된 속도로 일정하게 애니메이션을 동작시키다가 [speedAction setSpeed:]로 해당 애니메이션 동작 속도를 변경할 수 있다. API에 보면 슬로모션이나 빠른 건너뛰기를 할 때 유용하게 사용할 수 있다고 합니다. 

다음은 점프하면서 회전하는 이미지를 1초마다 Scheduler를 통해서 속도를 변경시키는 예제이다. 매 초마다 변경할 속도는 랜덤한 값으로 설정하도록 설정한 예제이다.

- (void)onEnter
{
    [super onEnter];

    // rotate and jump
    IntervalAction *jump1 = [JumpBy actionWithDuration:4 position:ccp(-400,0) height:100 jumps:4];
    IntervalAction *jump2 = [jump1 reverse];
    IntervalAction *rot1 = [RotateBy actionWithDuration:4 angle:360*2];
    IntervalAction *rot2 = [rot1 reverse];

    id seq3_1 = [Sequence actions:jump2, jump1, nil];
    id seq3_2 = [Sequence actions: rot1, rot2, nil];
    id spawn = [Spawn actions:seq3_1, seq3_2, nil];
    id action = [Speed actionWithAction: [RepeatForever actionWithAction:spawn] speed:1.0f];
    [action setTag: kTagAction1];

    [someSprite runAction:action];

    [self schedule:@selector(altertime:) interval:1.0f];    // schedule을 등록한다.
}

- (void)altertime:(ccTime)dt
{
    id action = [someSprite getActionByTag:kTagAction1];

    [action setSpeed: CCRANDOM_0_1() * 2];
}

4. Mics Actions


4.1 CallFunc


CallFunc는 callback 메소드를 호출해서 실행시킨다. Sequence로 애니메이션을 다 구현한 후에 메소드를 실행시키려도 할 때 유용하게 사용할 수 있다. 
CallFunc는 [CallFunc actionWithTarget:selector:]를 사용해서 callback메소드를 입력하는 Action을 만들 수 있다. 

다음은 가로로 200이동한 후에 Callback을 호출하는 예제이다. 

-(void) onEnter
{
    [super onEnter];
    
    id action = [Sequence actions:
                 [MoveBy actionWithDuration:2 position:ccp(200,0)],
                 [CallFunc actionWithTarget:self selector:@selector(callback)],
                nil];
    [someSprite runAction:action];
}

-(void) callback
{
    [tamara setVisible:YES];
}

4.2 Orbit(궤도)


Orbit는 화면의 가운데를 중심으로 하는 구형의 좌표계에서 해당 Sprite를 궤도를 따라 움직이게 하는 Action이다. Orbit의 구현은 다음의 메소드를 사용한다. 
    [OrbitCamera actionWithDuration:        // 애니메이션 구현 시간
                        radius:deltaRadius:        // 시작지 및 목적지의 거리(반경) - 원근을 표시할 때 사용하면 좋음
                        angleZ:deltaAngleZ:        // Z축의 시작지 및 목적지 각도
                        angleX:deltaAngleX:        // X축의 시작지 및 목적지 각도

Orbit 구현은 구형 좌표계가 익숙하지 않으니까 이해하기가 쉽지가 않다. 다음의 예제를 가지고 값을 바꿔가면서 실행해보면 어느 정도는 이해가 될 것이다. 

    id orbit = [OrbitCamera actionWithDuration: 2 radius:0.5f deltaRadius:1 angleZ:0 deltaAngleZ:180 angleX:0 deltaAngleX:0];
    id action = [Sequence actions:orbit, [orbit reverse], nil];
    [someSprite runAction:action];



이제 Cocos2d로 구현할 수 있는 대부분 애니메이션의 Action을 알아봤다. 어떤 것이든 지금까지 배운 것을 다 조합하면 다 구현할 수 있을 것이다. 마지막으로 3번째 애니메이션 구현의 예제를 추가하겠다. SpriteTest3.zip 이것은 Cocos2d Test의 sample예제를 강좌를 위해서 편집한 것이다. 그럼 열심히 공부하시길... 


다음에는 터치이벤트를 받아서 처리하는 법을 배우겠다. 머 다들 알겠지만 간단히 훌른다는 기분으로 준비하려고 한다. 

그럼 다음 강좌를 기대하시라... ^^

'프로그래밍 > Cocos2D' 카테고리의 다른 글

Cocos2D - 각종 레퍼런스  (0) 2009.11.06
cocos2D로 시작해보자  (0) 2009.11.06
Cocos2d 애니메이션 구현하기 2  (0) 2009.11.06
Cocos2d 애니메이션 구현하기 1  (0) 2009.11.06
메뉴 만들기  (0) 2009.11.06
Posted by windship
프로그래밍/Cocos2D2009. 11. 6. 16:44
2009.08.11 21:43:39(*.112.98.77)
조회수:1309

 역시 글을 쓴다는 것은 어려운 것 같다. 이번에도 시간이 자료를 준비하는데 꽤 많은 시간이 소요됬다. 그래도 재미있는 기능들이 많이 있으니까. 기대하시라. 그런데 강좌를 쓰다보니까. 상당히 길어서 2,3으로 끊어서 여기에 연재하기로 결정했다. 그래서 이번에는 유래없이 연이어 두개의 강좌글이 올라갈 것이다. ㅋㅋ


이번에는 그리 어렵지않게 이해할 수 있을지 모르겠지만 다음 장은 좀 어려우니까. 잘 보고 이해하길 바란다. 그럼 강좌를 시작하겠다. 


Cocos2d로 애니메이션 구현하기 2


2. Composable Actions


Composable Actions는 전 시간에 배웠던 Transformation Actions를 여러개를 순차적으로 또는 동시에 같이 애니메이션을 실행시키는 것을 말한다. 예를 들자면 빙빙 돌면서 특정 위치로 이동을 한다던가.. 점점 커지면서 사라진다던가 또는 커지고나서 다른 위치로 이동한다음 다시 원래의 상태로 돌아가는 순차적인 애니메이션 등을 구현할 수 있다. 
실행시키는 방법은 Transformation Action을 만든 방식과 동일하다. 단 만들 때 여러 Action들을 조합하므로 Array를 생성하는 방식으로 만들어야 한다. 다음과 같이 말이다.

    id action = [Sequence actions:
                 [MoveBy actionWithDuration: 2 position:ccp(240,0)],
                 [RotateBy actionWithDuration: 2 angle: 540],
                 nil];
                
이제 Composable Actions의 종류별로 하나씩 알아보도록 하자.


2.1 Sequence

이는 순차적으로 등록된 Action들을 실행시키게 하는 것이다. Action인 A, B, C를 차레로 등록했다면 A Action이 끝난 뒤에 B Action이 실행되고, B Action이 끝난 뒤에 C Action이 실행되는 식이다. 그리고 눈치가 빠르신 분은 알겠지만 A, B등 입력되는 Action이 역시 Composable Actions이어도 된다. 그래서 다음과 같은 것도 가능하다. (다음은 설명을 위해서 로직을 간단히 한거다.)

    id seq = [A, B, C, nil] : A -> B -> C 실행

    id subSeq = [B, D, E, nil];
    id seq = [A, subSeq, C, nil]; // 이는 A를 실행한 후에 subSeq에 등록된 B -> D -> E를 실행하고 나서 다시 E를 실행시킨다.

이제 실제로 코딩된 예제를 보자. 다음은 현재 위치에서 가로로 240만큼 이동한 후에 제자리에서 540를 돌는 예제이다.

    id action = [Sequence actions:
                 [MoveBy actionWithDuration: 2 position:ccp(240,0)],
                 [RotateBy actionWithDuration: 2 angle: 540],
                 nil];

    [someSprite runAction:action];

그리고, 주의 해야할 것이 NSArray를 사용해 봤으면 알겠지만 Composable Actions는 내부에서 NSArray로 관리되기 때문에 배열의 끝을 nil로 꼭 알려줘야 한다. 그렇지 않으면 실행 시에 에러난다.

2.2 Spawn


Spawn 은 등록된 모든 Action들을 동시에 실행시키는 Action이다. 즉, 점점 커지는 액션과 이동 액션을 등록했을 경우, 점점 커지면서 해당 위치로 이동을 한다. 그런데 여기서 주의해야할 것은 시작 시간이 같은 것이지 애니메이션이 끝나는 시간은 각각의 Action에서 지정한 시간에 따라 천차 만별이 될 수 있다. 개발을 할 때 동시에 애니의 끝까지 완료되게 하고 싶다면 각각의 Action들의 애니메이션 시간을 동일하게 해줘야 한다. 만약, 끝나는 시간이 다른 Spawn Action을 Sequence Action의 element로 등록을 했다면 가장 애니메이션이 긴 액션을 완료한 후에 다음에 등록된 Action이 실행된다.

다음은 Spawn을 사용한 예제이다. Sequence와 동일한 방식으로 사용할 수 있다.

    id action = [Spawn actions:
                 [JumpBy actionWithDuration:2 position:ccp(300,0) height:50 jumps:4],
                 [RotateBy actionWithDuration: 2 angle: 720],
                 nil];

    [someSprite runAction:action];

2.3 Reverse


처 음엔 이 Action은 왜 있을까라는 생각도 했지만, 아주 유용하게 쓸모있는 Action이다. Action을 반대로 실행하게 한다. 그러니까. 만약, A에서 B로 이동하는 Action을 다음과 같이 reverse를 호출하면 B에서 A로 이동하게 된다. 

    id action = [MoveTo actionWithDuration:1 position:ccp(250, 250)];
    id reverseAction = [action reverse];

만약, Sequence와 다음에 배우게 될 Repeat이나 RepeatForever를 사용한다면 스타크래프트의 순찰지정과 같이 무한반복도 가능한다.

다음은 Sequece를 활용해서 가로로 250 이동하고 나서 세로로 50 이동한다음 다시 처음위치로 원위치되는 애니메이션을 구현한 예제이다. 간단하게  [seq reverse]로 원래 위치로 이동시킬 수 있다.

    id move1 = [MoveBy actionWithDuration:1 position:ccp(250,0)];
    id move2 = [MoveBy actionWithDuration:1 position:ccp(0,50)];
    id seq = [Sequence actions: move1, move2, [move1 reverse], nil];
    id action = [Sequence actions: seq, [seq reverse], nil];

    [someSprite runAction:action];

2.4 DelayTime


DelayTime은 지정된 시간동안 대기시키는 Action이다. Sequence로 각 Action들을 등록할 때 일정시간 동안 지연효과를 줄 때 아주 유용하게 사용할 수 있다. 다음과 같이 초단위 시간으로 지연시킬 수 있다.

    [DelayTime actionWithDuration:초단위 시간]; 

다음은 DelayTime을 사용해서 가로로 150이동했다가 2초동안 지연후 다시 가로로 150이동하는 애니메이션을 구현한 예제이다.

    id move = [MoveBy actionWithDuration:1 position:ccp(150,0)];
    id action = [Sequence actions: move, [DelayTime actionWithDuration:2], move, nil];

    [someSprite runAction:action];

2.5 Repeat, RepeatForever


Repeat과 RepeatForever는 단어에서도 볼 수 있듯이 Repeat은 지정한 횟수만큼 반복하는 것이다. RepeatForever는 영원히 등록된 Action들을 반복시키는 Action이다.
Repeat는 횟수를 지정하기 위해서 다음과 같이 times 파라미터가 추가되지만 RepaetForever는 반복할 Ation들을 등록하는 파라미터만 입력하면 된다.

    [Repeat actionWithAction:times:]
    [RepeatForever actionWithAction:]

다음은 Reverse시에 사용한 것을 Repeat을 사용해서 3번 반복 시키는 예제이다.

    id move1 = [MoveBy actionWithDuration:1 position:ccp(250,0)];
    id move2 = [MoveBy actionWithDuration:1 position:ccp(0,50)];
    id seq = [Sequence actions: move1, move2, [move1 reverse], nil];
    id action = [Repeat actionWithAction:[Sequence actions: seq, [seq reverse], nil]
                                   times:3];

이를 무한 반복 시키려면 다음 같이 사용하면 된다.

    id action = [RepeatForever actionWithAction:[Sequence actions: seq, [seq reverse], nil]];



여기까지 간단하게 Cocos2d의 Composable Actions에 대해서 알아봤다. 예제를 SpriteTest2.zip  보면서 실행해보면 쉽게 이해할 수 있을 것이다. 

'프로그래밍 > Cocos2D' 카테고리의 다른 글

cocos2D로 시작해보자  (0) 2009.11.06
Cocos2d 애니메이션 구현하기 3  (0) 2009.11.06
Cocos2d 애니메이션 구현하기 1  (0) 2009.11.06
메뉴 만들기  (0) 2009.11.06
Cocos2d의 구성  (1) 2009.11.06
Posted by windship