( 들어 가면서 )

1. 한글화 목적 : jbox2d 를 위한 기초작업
                     작성자 : 나
                     번역 태클 : 언제든지 해주세요 !!!!!

2. 출처 http://box2d.org/manual.pdf



Box2D의 배포버전에는 Hello World project이 포함 되어 있습니다. 
프로그램은  커다란 ground박스와 하나의 작은 박스를 생성합니다. 
이코드 에는 그래픽적 요소가 없습니다. 
당신이 볼수 있는것은 모든 시간에 대해서 box의 위치를 콘솔로 텍스트로 볼 수 있을 겁니다.

이것은 box2d의 실행과 어떻게 시작해야 할지에 대한 좋은 예를 제공 할수 있습니다.

 
2.1 Creating a world 
모든 box2d 프로그램은  b2World object를 생성하는 것으로 시작한다. 
b2World는 물리공간과 프로그래머의 연결점입니다. b2World는 메모리, 객체, 시뮬레이션
을 관리합니다. 물리공간을 stack과 heap 과 section에 위치 시킬수 잇습니다.

Box2D world 생성하는 것은 매우 쉽습니다. 
첫번째로  중력 벡터를 정의 해야 합니다. (중력의 방향과 중력의 값)
또한 바디들 비활성상태 상태 인지 아닌지를 결정하는 것을 world가 알게 해주어야 한다. 
비활성 상태를 sleep이라고 하는데  sleep 상태이 바디들은 시뮬레이션요청을 받지 않는다.

b2Vec2 gravity(0.0f, -10.0f);
bool doSleep = true;

월드 오브젝트를 생성한다. 아래에 나오는 것은 stack에 world를 생성하는 것이다,
이때 월드는 범위(무슨 범위?) 안에 있어야 한다.
 b2World world(gravity, doSleep);

정리 코드

b2Vec2 gravity(0.0f, -10.0f);
bool doSleep = true;
b2World world(gravity, doSleep); 



이제 물리월드(물리 공간)이 생성되었고 이제 다른요소들을 추가 해보자.

 
2.2 creating a ground Box (바닥 상자 만들기)
바디를 생성하기 위한 단계는 아래와 같다. 

step1. 바디의 위치와 제동(damping)을 정의한다. 
step2. world object를 이용해서 body를 생성하라.
step3. shape와 friction 과 densitiy 와 함께 fixtures 을 정의하라. 
step4. body위에 fixtures을 생성하라




첫번째 단계을 위해서 그라운드 바디를 생성한다. 
이때 생성되는 바디의 정의가 필요하다. 이 정의를 가지고 
그라운드 바다의 초기위치를 정한다.

b2BodyDef groundBodyDef;

groundBodyDef.position.Set(0.0f, -10.0f);



두번째 단계에서는 바디의 정의가 바다의 생성을 위해서 월드 오브젝트로 전달된다. 
월드 오브젝트는 바디정의 에 대한 레퍼런스를 유지하지 않는다 . 바디들은 초기화에 대해
고정적이다. 이 고정적인 바디 (static bodies)들은 다른 static body와 충돌하지 않고
움직이지 안는다. 

b2Body* groundBody = world.CreateBody(&groundBodyDef);



세번재 단계로 그라운드 폴리곤을 생성한다. SetAsBox를 이용해서 그라운드 폴리곤을
box shape 으로 만들어라, 이 박스는 부모의 바디원형에 센터에 자리 잡는다.

b2PolygonShape groundBox;

groundBox.SetAsBox(50.0f, 10.0f);


SetAsBox 함수는 인자값으로 높이와 길이의 1/2값을 받는다  (센터에 맞추니까)
그래서 이 경우에 그라운드 바디는 x축 100단위이고  y축 20 단위이다. 
Box2D의 단위는 KMS 단위로 조정된다.  그래서 위에 넣은 값은 미터단위로  생각해볼수 있다
Box2D 는 오브켁트가 실세계의 사이즈를 기초로 했을때 잘 동작한다.
예를 들어 베럴(오크통)은 높이가 1미터 정도이다. 부동소숫점 연산의 제한때문에 
glaciers(빙하?)나 먼지 입자의 움직임 모델링은 좋은  생각이 아니다. 



마지막 4번째로 shape fixture을 만들어야 한다. 이번 단계에서 간단한 방법이 있다. 
기본 fixture의 요소의 속성을 변화 시킬필요 없다. 픽스쳐의 정의없이 그냥 shape를 바로 body에 전달한다. 이후에 커스터마이징을 위한 fixture을 알아 보겟다. 두번째 파라미터는 shape의 입방미터당 킬로그램 즉 밀도이다.  static body는 디폴트로 0 이다. 그래서 이번 경우에는 사용하지 않는다 

groundBody->CreateFixture(&groundBox, 0.0f);



Box2d 는 shape의 레퍼런스를 유지하지않는다 그 데이터는(레퍼런스) b2Shape 오브젝트에 복사된다. 


주의: 모든 fixture는 부모 body를 가져야한다. (단연한 말이다) 심지어 static(전역?) 이라도 말이다. 그러나  모든 static fixture를 하나의 static body에 붙일수는 있다. 



2.3 Creating a Dynamic Body

지금까지 그라운드 바디를 생성한는 방법을 알았다. 이 방법(테크닉)을 이용해서 다이나믹 바디를 
만들어 보겟다. 그라운드 바디와 다이나믹 바디의 차이점이 있는데 가장 큰 차이점은
다이나믹 바디의 mass 속성을 지정해주어야 한다. 

첫번째로 CreateBody 를 이용해서 body 를 만든다. 디폴트 바디는 static 이기 때문에 
b2BodyType를  다이나믹 바디 오브젝트를 만들때 준비해야 한다. 

b2BodyDef bodyDef;

bodyDef.type = b2_dynamicBody;

bodyDef.position.Set(0.0f, 4.0f);

b2Body* body = world.CreateBody(&bodyDef);

주의 :   body type 을 b2_dynamicBody 으로 설정해한다. 사용자의 입력에 따른 반을을 할려면 말이다. 



다음으로 fixture 정의 를 이용해서 폴리곤 shape를 생성하고 할당한다. 
첫번재로 boxshape를 생성하고 

b2PolygonShape dynamicBox;

dynamicBox.SetAsBox(1.0f, 1.0f);


다은으로 box를 이용해서 fixture정의를 생성한다. 밀도 density는 1로 정해준다.
디폴트 밀도는 0 이다 shape의 마찰(friction)은 0.3으로 하자. 

b2FixtureDef fixtureDef;

fixtureDef.shape = &dynamicBox;

fixtureDef.density = 1.0f;

fixtureDef.friction = 0.3f;



픽스쳐의 정의를 이용하면  fixture를 생성할수 있다. 이것은 body의 mass를 자동으로 업데이트 해준다.  이것으로 많은 fixture를 원하는 body에 추가 할수 있다. 
각각의 요소는 전체 mass를 구성하는 역활은 한다. 



2.4 simulating the world (of Box2D)
지금까지 그라운드 박스를 만들고 다이나믹 박스도 만들어 보았다.
이제 거의 모든 준비는 다되었습니다. 
이제 몇가지만 고려하면 됩니다. 

Box2D 적분기(integrator)라는 컴퓨팅 알고리즘을 이용합니다. 
인터그래이터(알고리즘)는 물리공식을 이산시간에 대해서 시뮬레이션합니다. 
이산시간이란 ( 시간을 연속적으로 보지않고 일정한 간격으로 잘라 사용하는것을
의미합니다.) 전통적인 게임루프(플립북에서 대상이 움직이는 하나의 scene)와 같이 
진행이 된다. 그래서 Box2d를 위한 시간이 필요하다.  일반적으로 게임에서 물리엔진은 
60프레임정도이다. 이 프레임 보다 더 크게 시간을 분할할 필요는 없다. 그러나 생성한
world 오브젝트에 대한 정의를 주의깊게 준비해야 한다. 
다양한 time step은 다양한 결과를 야기 시킨다. 이것은 디버깅 하기도 어렵다 .
그러므로 진행하는 프레임에 time step을 엮지 말라. (진정으로 정말 원한다 하더라도
말이다. )
별다른 고생할 필요없이 여기 간단하게 time step을 설정할수 있다. 

float32 timeStep = 1.0f / 60.0f;


게다가 적분기에 , Box2d는 constraint solver 라고 불리는 코드의 더 많은 비트를
이용할수 있다. constraint solver은 시뮬레이션 제약에 대해서 해결책을 제공해준다. 
하나의 제한은 완전하게 해결할수 있다. 그러나 하나의 제한을 해결할때 또다른 
제한을 약간 방해 한다. 좋은  해결책은 모든 제한에 대해서 여러번 반복할 필요있습니다.

constraint solver 에 2개의 단계가 있다. : 속도 단계 위치 단계
속도 단계에서 solver 바디를 정확하게 움직이기 위해서는 필수적으로 impulses를 연산
할 필요가 있다. 위치 단계에서는 solver는 overlap 과 조인트 분리를 오차를 줄이기 위해서 
바디의 포지션을 조정한다. 각각의 단계는 자기자신의 iteration count 를 가지고 있다 
만약 에러가 작다면 위치 단계는 반복을 일찍 벗어난다.

box2d에서 추천하는 iteration은 속도 8이고 위치3 이다. 이 숫자는 임의로 조정할수 있다.
명심할것은 속도와 정확도는 trade-off 이다. 적은 숫자의 iteration은 속도를 증가 시키지만.
정호가도는 개판이다. 반대로  많은 iteration은 속도를 줄이지만 시뮬레이션의 정확도는 좋다
간단한 예제에서 많은 iteration은 필요없다. 
여기에 우리가 선택한 iteration counts가 있다. 

int32 velocityIterations = 6;

int32 positionIterations = 2;


time step 과 iteration counts은 아무 상관이 없다. iteration은 sub-step 이 아니다. 
하나의 solver iteration 은 time step내의 모든 constraints(제약조건)을 한번씩은 통과해야 한다
(확인해야 한다.)최소한 한번이다. 이말은 여러번 반복할수 있다라는 말이다. 

우리는 시뮬레이션 루프시작을 준비한다. 당신의 게임에서 시뮬레이션루프는 게임루프에 
통합된다.당신의 게임루프전체의 각각의 단계에서 당신은 b2World::step를 호출할수 있다.
일반적으로 당신의 프레임과 물리 time step 에 따라  다릅니다.

Hello World 프로그램은 심플하게 디자인(구성)되어 있다. 그래서 
그래픽적 아웃풋은 없다. 코드는 다이나믹바디의 위치와 회전값을 출력한다. 
여기에 시뮬레이션 루프가 있다. 이는 시뮬레이션 타임의 1초에서 60번의 time step을 
시뮬레이션한다.

for (int32 i = 0; i < 60; ++i)

{

    world.Step(timeStep, velocityIterations, positionIterations);

    b2Vec2 position = body->GetPosition();

    float32 angle = body->GetAngle();

    printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);

}


출력되는 데이터는 박스의 떨어짐과 그라운드 박스에 안착하는 것을 보여준다.
아마도 당신이 볼수 있는 데이터는 

0.00 4.00 0.00

0.00 3.99 0.00

0.00 3.98 0.00

...

0.00 1.25 0.00

0.00 1.13 0.00

0.00 1.01 0.00


이럴것이다.


2.5 Cleanup
world 가 범위를 벗어나거나 pointer에 삭제가 호출될때 bodies,fixtures,joints에 남겨놓은
모든 메모리는 해제된다. 이것은 퍼포먼스를 향상시키고 당신의 삶을 좀더 쉽게 해주기위해서
이다.

그러나 당신이 가지고 있는 bodies,fixtures,joints의 포인터를 해제할 필요가 있을것이다.
그것들은 필요가 없어 질것이기 때문이다. 


2.6 The Testbed 
HelloWorld 예제를 정복하기 위해서는 Box2d의 testbed를 보아야 할것이다. 
testbed는 프레임워크와 메모환경을 unit 단위로 테스트 할수 있다. 
여기에 몇가지 특징이 있다. 

• Camera with pan and zoom.

• Mouse picking of shapes attached to dynamic bodies.

• Extensible set of tests.

• GUI for selecting tests, parameter tuning, and debug drawing options.

• Pause and single step simulation.

• Text rendering.



testbed 는 box2d 사용에 대한 많은 예제를 가지고 있다. 많이 고치고 찾아보아라.

testbed는 freeglut와 GLUI를 사용해서 작성되었다. testbed는 box2d 라이브러리의 일부분이
아니다. box2d 라이브러리는 렌더링에 대해서 문외한이다.? 예제에 보여지는 것은 box2d를
사용하여 렌더링할수 없다 ?

 



























Posted by 수다쟁이증후군 :


타일 기반 게임의 장점
* 메모리를 절약할 수 있다. 
* 게임 세계의 효과적인 공간 분할에 따른 이점이 있다. 타일에 속성을 부여함으로써 충돌검사나 랜더링을 쉽게 할 수 있다. 캐릭터와 배경과의 상호작용을 처리하기가 쉽다.  
* 그래픽 디자이너가 아닌 누구라도, 디자이너가 만들어둔 타일셋으로 맵 디자인을 할 수 있다.

타일 기반 게임의 단점 
* 그래픽이 다소 지루하고 경직되어 보인다. 반복되는 타일 이미지가 많이 나타나며 유연성이 부족하다. 
* 타일 이미지 제작, 관리가 힘들고 불편하다.  
* 통짜맵에 비해 랜더링 알고리즘이 복잡하고 느리다.

<출처 : http://meat.tistory.com/9 >
 




TileMap 관련 내용
http://mamedev.org/devwiki/index.php/Tilemaps#The_problem




TileMap cocos2d-iphone 레퍼런스
http://www.cocos2d-iphone.org/wiki/doku.php/ko:prog_guide:tiled_maps






타일맵 관련 정말깔끔한 최종 정리
출처: 
http://cafe.daum.net/iLogic/915W/39?docid=1KHkj915W3920110612155237 

타일 맵

Cocos 2D 에서는 타일 맵을 생성하는 방법이 2 가지다.

  • TMX 타일 맵 형식 사용 (새로 나와서 다루기 쉬움, 추천)
  • PGU 타일 맵 형식 사용 (예전 것, 비추)                                                   

TMX 타일 맵 형식

Cocos 2D 는 타일로 생성된 맵을 제공한다.

Tiled 의 2 가지 버전:

  • Mac OS X, 윈도우, 리눅스에서 실행되는 자바 어플은 안정화된 버전이다.
  • 자바 버전의 모든 특징을 제공하는 QT 어플. 이 강좌를 작성하는 시점의 최근 버전은 0.4.0 이며 육각형 맵만 제외하고 모든 기능을 제공한다.

다음 링크된 페이지에서는 Tiled 를 사용하여 맵을 만드는 방법을 설명한다.

Cocos 2D 는 다음과 같은 TMX 맵을 제공한다.

  • 위치:
    • 지각 맵
    • 등각 맵
    • 육각 맵
  • 타일:
    • 연결된 타일은 제공되지 않는다. (즉, 연결된 이미지를 갖는 tileset).
    • embedded tileset 만 제공된다. (즉, tileset 은 연결되었지만 이미지는 아닌 것).
    • 레이어 별로 최대 1 개의 tileset 만 제공된다.
  • 레이어:
    • 레이어는 원하는 만큼 만들 수 있다.
    • 각 레이어는 내부적으로 CCSpriteSheet 의 자식 클래스인 CCTMXLayer 으로 표현된다.
    • 각 타일은 CCTMXLayer 의 자식 클래스인 CCSprite 으로 표현된다.
  • 객체 그룹:
    • 타일의 객체 그룹이 제공된다.

외부 이미지에서 연결된 tileset 생성하는 방법

Cocos 2D 는 tileset 에 연결된 이미지를 제공하지 않는다. 그러나, tileset 자체는 맵 파밀에서 연결된 그림이 되어야 한다. 대신, 자체적으로 sprite sheet 이미지(AKA: Texture Atlas)를 생성해야 한다.


Tiled 정보 설정

연결된 이미지를 갖는 tileset 으로 저장되지 않도록 tiled 에 설정한다.

$ cd bin/tiled-0.7.2/
$ java -jar tiled

tiled 에서 해야할 작업:

  • Edit → Preferences → Saving
  • Layer 옵션:
    • Use binary encoding: ON (“텍스트” 엔코딩은 Cocos 2D 에서 제공되지 않는다)
    • Compress layer data: ON (압축되지 않은 데이터도 또한 제공된다)
  • Tileset 옵션:
    • Embed images (PNG): OFF (연결 이미지는 제공되지 않는다)

새로운 맵을 생성할 때 맵의 크기는 맵의 픽셀 단위의 크기가 아닌 가로 세로의 tile 의 개수를 넣어야 한다. iPhone 에서 제공할 수 있는 맵의 크기는 제한된다. 작동할 때 44 픽셀 x 44 픽셀은 100 x 100 으로 보여진다. 400 x 200 의 타일은 모두 검정색으로 그려진다.


tileset 연결된 것 확인하기

맵용 tileset 은 맵 파일 내에 포함되어야 한다. tiled 에서는 Tileset → Tileset Manager 로 접근할 수 있는 "Tileset Manager"로 조절된다. tileset 목록에서 tileset 이름의 오른쪽 행에 Embedded 를 볼 수 있다. 대신에 경로가 보인다면, 목록에서 열을 선택하고 embedded tileset 으로 변환하는 오른쪽의 Embed 아이콘을 선택해야 한다.

다른 도구를 사용하거나 확인해보려면 텍스트나 XML 편집기에서 *.tmx 파일을 열고 <tileset> 노드를 확인해볼 수 있다. 파일 명을 갖는 source 속성을 포함하면 Cocos 2D iPhone 에서 동작하지 않는 외부 tileset 을 보고 있는 것이다.


sprite sheet 생성

유용한 이미지를 묶어주는 도구들이 있다.

  • zwoptex 비주얼 텍스처 아트라스 생성기 (flash)
  • mkatlas.pl 도스 실행형 텍스처 아트라스 생성기 (perl)
  • Packer 비주얼 텍스처 아트라스 생성기 (java)
  • TexturePacker 강력한 명령행 도구, XCode-통합용

이 도구들은 개별 이미지로부터 sprite sheets 를 생성하도록 도와준다.

sprite sheet 의 제한:

  • 최대 크기: iPhone 3GS 에서는 2048×2048 이고 이전 iPhone 에서는 1024×1024
  • 타일은 모두 같은 크기여야 한다.

옵션:

  • 여백: 픽셀 단위의 공백
  • 간격: 타일 간의 공백

여백과 간격은 2 를 사용하는 것이 추천된다.


spritesheet artifact fixer

맵을 이동할 때 타일의 경계 사이의 선이 깜빡이는 경험이 있다면, 이 도구는 고쳐야 한다. 이들 선은 시뮬레이터에서는 나타나지 않고 장치에서 실행할 때만 나타난다.

spritesheet-artifact-fixer 는 spritesheet 를 고치는 Cocos 2D 에 있는 작은 도구이다.

실제로 해야할 일은 타일의 경계선을 여백 안으로 복사하는 것이다. 이론적으로는 여백은 렌더링되지 않아야 하지만, 때때로 렌더링된다. 특히, 안티-앨리어싱 텍스처나 3D 투영을 사용한 것이라면 더 그렇다.

도구를 사용하는 방법:

$ cd cocos2d/tools
$ python spritesheet-artifact-fixer.py -f spritesheet.png -x 32 -y 32 -m 2 -s 2

다른 도구는 –extrude 옵션으로 TexturePacker 을 사용하는 것이다.

$ TexturePacker *.png --extrude 1 --plist test.plist --sheet test.png

좌표와 GID

좌표

64×32 맵에서 tiled 에서 사용되는 좌표 시스템은 다음과 같다.

  • (0,0): 왼쪽 상단 모서리
  • (63,31): 오른쪽 하단 모서리


GID

타이틀의 GID 는 타이틀의 전역적으로 구별하는 식별 기호이다. 이 값은 unsigned int 형이며 1 부터 타일의 개수까지 차례대로 번호가 부여된다.

5 개의 다른 타일이 있다면

  • Tile 0 은 GID 1
  • Tile 1 은 GID 2
  • Tile 2 은 GID 3
  • 등등.

GID 0 은 빈 타일을 표현하는 데 사용된다.


TMX 노드 생성

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"hexa-test.tmx"];
[self addChild:map];

디폴트로 모든 타일은 앨리아싱된다. 안티-앨리어싱 타일을 원하면 다음과 같이 작업해야 한다.

// TMX 맵 생성
CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal-test2.tmx"];
[self addChild:map];
 
// 모든 레이어를 반복하면서 'antialias' 로 설정한다
for( CCTMXLayer* child in [map children] ) {
    [[child texture] setAntiAliasTexParameters];
}

완전한 소스:

타일 얻기/추가/삭제/수정

특정 좌표에서 타일(CCSprite) 얻기

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal-test2.tmx"];		
CCTMXLayer *layer = [map layerNamed:@"Layer 0"];
 
CCSprite *tile = [layer tileAt:ccp(0,63)];
tile.anchorPoint = ccp(0.5f, 0.5f);

특정 좌표에서 타일의 GID 얻기

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal-test2.tmx"];		
CCTMXLayer *layer = [map layerNamed:@"Layer 0"];
 
unsigned int gid = [layer tileGIDAt:ccp(0,63)];

특정 좌표에 새로운 타일의 GID 설정하기

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal-test2.tmx"];		
CCTMXLayer *layer = [map layerNamed:@"Layer 0"];
 
[layer setTileGID:gid2 at:ccp(3,y)];

특정 좌표에 타일 제거하기

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal-test2.tmx"];		
CCTMXLayer *layer = [map layerNamed:@"Layer 0"];
 
[layer removeTileAt:ccp(15,15)];

레이어 반복

CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal-test2.tmx"];		
CCTMXLayer *layer = [map layerNamed:@"Layer 0"];
 
CGSize s = [layer layerSize];
for( int x=0; x

z 오더와 깊이 버퍼

이 정보는 v0.99.1 이후 버전부터 유효하며, Isometric 과 orthogonal 맵 에서는 가능하며 hexagonal 맵에서는 불가능하다.

만들고자 하는 게임이 sprite 의 Y 위치를 따라서 어떤 타일의 앞쪽이나 뒤로 sprite 를 위치시켜야할 때, 2 가지 옵션을 사용할 수 있다.

  • OpenGL ES 깊이 버퍼 사용
  • 멀티 TMX 레이어와 z-오더 사용

깊이 버퍼 사용

이 옵션은 OpenGL ES 깊이 버퍼를 사용한다. 그래서, 우선 적으로 해야할 작업은 z-버퍼와 2D 프로젝션을 생성하는 것이다.

// 직접적으로 윈도우 뷰에 붙기 전에 AppDelegate 에서 작성한다.
// kDepthBuffer24 로 24 비트 버퍼를 사용할 수도 있다.
[[CCDirector sharedDirector] setDepthBufferFormat:kDepthBuffer16];
 
 
// 이 코드는 아무 곳이나 원하는 위치에 넣을 수 있다. 실행 중에 프로젝션 방법을 바꿀 수 있다.
[[CCDirector sharedDirector] setProjection:CCDirectorProjection2D];

2 TMX 레이어로 맵을 생성하는 것이 중요하다.

  • 배경 레이어. 예: grass
  • 전경 레이어. 예: trees

grass 레이어는 뒤쪽의 스프라이트가 되어, vertexZ 값이 가능한 가장 작은 값이 될 것이다. 예: -1000. trees 레이어는 타일들마다 다른 vertexZ 값들을 갖는다. 아래 쪽에 있는 타일은 위에 있는 타일보다 더 큰 vertexZ 값을 갖는다.

그래서, 해당 작업은 다음과 같다:

  1. Tiled 열기
  2. 배경 레이어 선택 (예: grass)
  3. Tiled → Layer → Layer Properties
  4. 추가: cc_vertex = -1000
  5. 전경 레이어 선택 (예: trees)
  6. Tiled → Layer → Layer Properties
  7. 추가: cc_vertexz = automatic

가장 중요한 작업은 스프라이트를 GL_ALPHA_TEST가 가능한 상태로 드로잉하는 것이다. 예제:

// MySprite 는 CCSprite 를 상속받은 클래스이다.
// CCSpriteSheet 를 사용하여 스프라이트를 드로잉한다면, CCSprite 가 아니라 CCSpriteSheet 를 상속받아야 한다.
// 전역적으로 GL_ALPHA_TEST 를 설정할 수 있다. 설정하면, CCTMXLayer#draw 함수를 주석처리해야 한다.
// 다른 방법은 아래 예제와 같다.
@implementation MySprite
-(void) draw
{
   glEnable(GL_ALPHA_TEST);
   glAlphaFunc( GL_GREATER, 0 );
   [super draw];
   glDisable(GL_ALPHA_TEST);
}
@end


 

Q: cc_vertexz 의 작업 방식은 ?

A: cc_vertexz 는 자동으로 word 형식이나 정수를 받게 된다.

  • 값이 음수나 양수인 정수라면, 숫자는 레이어의 모든 타일의 vertexZ 로 사용될 것이다.
  • 값이 자동이라면, 타일의 첫 번째 열은 vertexZ 는 -1 이 되고, 두 번째 열은 vertexZ 가 -2 등을 자동으로 할당된다.

남은 작업은 Y 위치에 따라서 스프라이트의 vertexZ 값을 변경하는 것이다. 예제:

-(void) repositionSprite:(ccTime)dt
{
  // 타일 높이는 101x81
  CGPoint p = [sprite position];
  [sprite setVertexZ: -( (p.y+81) /81) ];
}

샘플의 작동은 TileMapTest.m 를 참고해라.


Q: cc_alpha_func 는 언제 사용해야 하나?

Acc_alpha_func 는 cc_vertexz=automatic 일 때 사용된다. 디폴트 값은 0 이다. 이 값은 GL_GREATER 함수를 사용하여 타일을 그릴 때 사용된다. 다음은 CCTMXLayer 로 타일을 그리는 방법이다. 

// CCTMXLayer 드로잉 함수
-(void) draw
{
  if (useAutomaticVertexZ_) {
    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, alphaFuncValue_);
  }
 
  [super draw];
 
  if (useAutomaticVertexZ_) glDisable(GL_ALPHA_TEST);
}

 

예제:

등거리 vertex Z 예제. "trees" 와 "grass" 로 2 개의 레이어를 갖는다. "trees" 레이어에 대해서 cc_vertex = automatic 를 사용한다. "grass" 레이어에는 cc_vertexz = -1000 를 사용한다.
직각 vertex 예제. “trees” 와 “grass” 로 2 개의 레이어를 갖는다. "trees" 레이어에 대해서 cc_vertexz = automatic 와 cc_alpha_func = 0.5 를 사용한다. "grass" 레이어는 cc_vertexz = -1000 을 사용한다.


다중 TMX 레이어와 z-오더 사용법

이 정보는 아직 가능하지 않다. 그러나 예제는 TileMapTest.m 에서 볼 수 있다.


스크린 샷

3D 프로젝션과 안티 앨리어싱 타일을 갖는 직각 맵.  타일들은 spritesheet-fixer 도구를 사용하여 고정된다. 3D 프로젝션과 안티 앨리어싱 타일로 표현되는 구조는 나타나지 않았다.
직각 맵. 맵의 타일 크기는 타일들 보다 더 적다.
2D 프로젝션과 앨리어싱 타일을 갖는 등거리 맵.
2D 프로젝션과 앨리어싱 타일을 갖는 육각맵. 가장자리는 좌우에 위치하며, 상하 가장자리는 아직 제공되지 않는다.


PGU 타일 맵 형식

PGU 타일 맵 형식도 사용할 수 있다.

이 형식은 크기 제한을 가지므로 유연하지 않고, 편집기 자체에도 약간의 버그를 갖기 때문에, 이 형식은 잘 다뤄지지 않는다. 예전 게임에 이 형식을 사용했다면 계속적으로 사용할 수 있지만, 추천되지 않는 형식이다. 대신 TMX 타일 맵이 추천된다.

이 형식에 대한 정보는 다음과 같다.


 

Posted by 수다쟁이증후군 :


0.SceneTest에 나오는 내용들

1.scene 전환 방법
2.scene 전환 액션  


 
1. 예제 분석 목적
==> scene 전환방법의 기본을 알고 scene action의 원리를 알아본다.



2.전체적 개요

전체 3개의 scene을 구성하면 각 scene당 Layer1 ,Layer2, Layer3 이 할당된다.
Layer1_Scene에서 Layer2_Scene로 전환될때는 push를 사용하고 이때 화면전환은
단순장면 전환 및 scene_action전환을 이용한다. 
Layer2_Scene에서 Layer1_Scene로 전환은 push의 반대 개념은 pop를 이용한다.


Layer2_Scene에서 Layer3_Scene로 전환 될때는 replace를 사용하고 이때 화면전환은
단순장면 전환 및 scene_action전환을 이용한다.
Layer3_Scene에서 pop를 이용하면 Layer1_Scene로 이동한다. 

 

3-1. Layer1 클래스  분석

public Layer1() {

            CCMenuItemFont item1 = CCMenuItemFont.item("Test pushScene", this,                                                                                                          "onPushScene");

            CCMenuItemFont item2 = CCMenuItemFont.item("Test pushScene w/transition",                                                                                    this, "onPushSceneTran");

            CCMenuItemFont item3 = CCMenuItemFont.item("Quit", this, "onQuit");


            CCMenu menu = CCMenu.menu(item1, item2, item3);

            menu.alignItemsVertically();


            addChild(menu);

        }

        public void onPushScene(Object sender) {

            CCScene scene = CCScene.node();

            scene.addChild(new Layer2(), 0);

            CCDirector.sharedDirector().pushScene(scene);

        }

        public void onPushSceneTran(Object sender) {

            CCScene scene = CCScene.node();

            scene.addChild(new Layer2(), 0);

            CCDirector.sharedDirector().pushScene(
                                                 CCSlideInTTransition.transition(1, scene));

        }

        public void onQuit(Object sender) {

            CCDirector.sharedDirector().popScene();

        }


==>MenuItem으로 3가지 메뉴를 만들고 클릭 되었을때 실행될 콜백을 각각 지정한다.
     push에서 봤다 시피 Scene을 담는 통의 구조는 스택으로 구성되어 있다.

     CCDirector.sharedDirector().runWithScene(scene);
     코드를 사용하여 디렉터에서 기본적으로 화면에 보여줄 scene을 전달한후에는
     
     CCDirector.sharedDirector().pushScene(scene);
     CCDirector.sharedDirector().popScene();
     CCDirector.sharedDirector().replaceScene(scene);
     이용해서 장면전화을 한다. 
     
     replaceScene 는 별거 없는것이 . pop 한 후에 push 한것  뿐이다.  보다 쓰기 쉽게만들어
     놓은 api 뿐이니 별 고민 할 필요 없다. 몰라도 된다 걍 남들이 쓰면 이런게 있다 정도로만 
     알아 두자 .
     Scene 라고 별거 없다 그냥 layer 라고 생각하면 된다. 다만 디렉터에서 관리하는
     Layer일 뿐이다.

     디렉터에서 관리하는 Layer는 Scene이다.  

==>Scene_Action 장면전환 효과가 있는 Scene 라고 하나의 패키지로 나와있는데 
     이것은 어이없는게도 CCNode+Action 일뿐이다. 
     이전 까지는 CCNode와 CCAction을 따로 선언하여 하나로 합쳐서 액션을
     사용했지만. 장면전환효과가 있는 Scene라고 거창한 이름을 붙여놓은것은
    CCScene에 기본 액션을 디폴트로 집어 놓았을뿐이다. 별거없다. 내부 함수들을
    살펴보면 알겟지만 더이상 없다. 이런 기본적인 것들을 알아 보았으니
    우리도 이와 비슷한것을 수십가지를 만들어 낼수 있다. 
    action에 action을 추가해서 CCSecne를 상속한 클래스에 박아 넣기만 하면
    되니까 말이다.  



나머지 Layer2와 Layer3도 별다른 차이점이 없다 여기서 설명한 내용이 전부 일뿐이다.
그런데 어떻게 글을쓰다 보니까 반말이 되었네요^^;;
글 수정하기도 ~~ 좀 그러니 ㅎㅎㅎ 이번만 양해 해주세요 

추가로 이상하다거나 헷갈리는 부분이 있으면  댓글로 ^^


Posted by 수다쟁이증후군 :
(들어가면서 :

1. 한글화 목적 : jbox2d 를 위한 기초작업
                     작성자 : 나
                     번역 태클 : 원추!!!!!!  강추!!!!!!

2. 출처 http://box2d.org/manual.pdf


제 1장 개요

1.1 box2d란 
box2d 란 게임을 위한 강체 시뮬레이션 라이브러리 이다. 
프로그래머는 게임을 이용하는 사람들이 어떠한 물체를 이동시킬수 있게 하고 좀 더 반응성이
좋은 게임을 만들기 위해 이 엔진을 사용한다.
게임 엔진의 관점에서 물리엔진은 단지 에니메이션을 처리하는 시스템일 뿐이다. 

Box2d 는 포터블C++로 작성 되었다 . 이 엔진에서 대부분의 타입은 b2라는 접두어가 붙어 있다 
이건 게임엔진을 사용하면서 네이밍하는데 있어서 중복을 피할수 있게 도움을 줄것이다. 

1.2 Box2D 를 사용하기에 앞서 
이 메뉴뉴얼은 당신이 기본 물리개념(mass, force, torque impulses...)을 좀더 친숙하게 해줄
수 있지만. 이게 전부 가 아니다. 구글링이나 위키를 이용하기 바란다. 

Box2d는 게임 개발자 컨퍼런스에서 물리강좌의 한부분으로 만들어졌다.  box2로 만든 이강좌는 
홈페이지에서 다운받을수 있다. 

Box2D가 C++로 작성되었기때문에 c++ 프로그래밍 경험은 당연히 있어야 한다. 
Box2D가 C++ 입문으로써는 적합하지 않다. 최소한 컴파일과 링크와 디버깅은 능숙하게 
다루어야 한다. 

1.3 이 메뉴얼에 관해서 
이 메뉴얼은  배부분의 Box2d API를 다루고 있다 글그러나 그게 전부는 아니다.
좀더 공부하고자 한다면 Box2D를 포함하는 Testbed를 충분히 보기 바란다 . 또한.
Box2D 코드는 Doxygen 으로 되어있다 그래서 api문서를 만들기는 좋을 것이다.

이문서는 새로운 버전에 맞추어져 있을며 최신 버전이다.

1.4 피드백과 버그리포팅
Box2D관련 질문이 있다면  포럼에 글을 남기세요. 매우 많은 사람들이 사용하니까
토론장소로 최고다.
Box2D관련 이슈는 구글코드프로젝트를 이용된다.  이건 이슈를 추적하기 좋고 포럼속에
묻히는걸 방지해준다 . ㅋ
여기에 있다 : http://code.google.com/p/box2d/

 
1.5 중요컨셉

Box2D 는 몇가지 몇 가지 중요 objects 가 있다. 여기에서는 간단히 정리하고 
자세한 내용은 관련 챕터에서 알아 본다. 

shape
.원이나 폴리곤 같은 2차원 기하객체이다. 

rigid body

물체(body)를 구성하는 두 입자의 거리가 절대로 바뀌지 않을 때 그러한 물체를 강체라고 한다.

다이아몬드처럼 단단한 물체이다.

물리현상에서 실제로 존재하지 않지만 단순화된 물리 법칙을 구현하기 위해 가정하는 형태이다.

일반적으로 생각할 때 단단한 고체 정도로 생각하면 될 것 같다.
(해석이 잘안되서 차용함 : 출처 : http://cafe.naver.com/uiaa.cafe)

fixture
fixture(고정장치) 는 body에 shape를 연결한다. 밀도 마찰 반발력과 같은 물체속성을 추가한다. 

constraint
constraint는 물체의 자유도를 없는 물리적연결이다. 
2차원에서 body는 자유도 3을 가진다.(2개의 이동축과 1개위 회전축)만약 body를
벽에 고정한다면 이것 벽에 body를 constraint한것이다.  그 고정점을 기분으로  body는
회전할수 있다. 그래서 constraint는 자유도 2를 제거한다.

constact constraint 
special constraint 는 강체의 침투(강체가 부딧쳤을때 움푹파이는 정도)를 막기 위해 만들어졌다 
또한 마찰 과 반발력을 시뮬레이션 할수 있게한다. 직접 만들수 없고. Box2D가 자동으로
생성한다.


joint
2가지 이상의 body를 하나로 만들어주는 constraint 이다. Box2d는  revolute, prismatic, distance... 과 같은 joint 타입을 제공한다. 몇가지 joint는 제약을 가진다. 


joint limit
joint limit 는 조인트의 움직이는 범위를 제한한다. 에를 들러 사람의 팔꿈치는 일정한 번위만큼만 
회전한다. 


joint motor
조인트 모터는 조인트의 허용되는 각도에 따라 연결된 바디의 움직임을 유발한다.
예를 들면 모터를 팔굼치를 회전 시키기 위해 사용할수 있다.

world
프로그래밍상의 물리공간이다.Box2D는  복수의 물리공간을 만들수 있으나 
별로 추천하지는 않는다 . 

solver
물리공간은 solver를 가진다. 이놈은 좀더 나은 타이머를 사용할수 있게 해주며
접촉과 joint제약을 해결해준다. Box2d에서 이놈은 성능이 좋다 

continuous collision
solver는 물체는 점진적으로 이동시킨다. 별도의 상호작용없이 turnneling
을 이끌어준다. 
Box2D는 turnneling을 위해 특별한 알고리즘을 사용한다. 
첫번째로 충돌 알고리즘 은 첫번째 impace를 찾기위해 2개의 바디의 움직임을 보간한다.
(아  힘드네 이거 생각보다 )

일단 요까이 ~~ ㄷㄷㄷ
2011/09/29

1.6 모듈
Box2d 는 3가지 모듈(Common, Collision,Dynamics)로 구성된다. 
Common 모듈은 allocation,math,settings과 관련된 코드를 가진다. 
Collision 모듈은 shapes,broad-phase, collision function/queries 를 정의한다. 
마지막으로 
Dynamics 모듈은 simulation world,bodies,fixture,joints 를 제공한다. 




1.7 단위(Units)
Box2d는 부동소수전연산을 하고 허용오차는 Box2d가 좀 더 동작을 잘하도록 도와준다. 
이러한 허용오차는 미터, 킬로그램,초 단위와도 잘 작동하도록 조정되었다.
특별히 Box2d는 0.1미터와 10미터 사이에서 잘동작되도록 조정 되어있습니다.
즉 이말은  0.1과 10 사이에서  soup cans와 buese 사이의 물체는 작동이 잘됩니다.(이말이
먼말인지 모르겟네) 정적 물체는 50미터 까지는 큰 문제 없을 겁니다.

2D 물리 엔진 이기 때문에 사용자가 이용하는 화면의 픽셀단위로 변경 하고 싶어 질겁니다.
불행히도 이것은 시뮬레이션 결과가 부정확해질겁니다.  200픽셀 길이의 물체가 Box2D 에서는 
45층 건물정도의 크기 입니다. (단위를 조심할것.)
**주의 **
**Box2d는 MKS 단위입니다.물체는 대략적으로 0.1에서 10미터 를 움직이는 것으로 유지해라.
**화면에 무언가를 렌더링 할 때 아마도 단위변환 시스템이 필요할것입니다.  Box2d testbed는
**opengl viewport 변형을 이용한다. 픽셀 단위를 사용하지 마세요. 

이미지를 붙이는 하나의 판처럼  box2d 바디를 생각하는 가장 좋습니다. 미터단위로 그 판을 움직
일수 있습니다. 그 반면에 간단한 요소를 이용하여 픽셀 좌표로도 변형 할수 있다. 
이는 스프라이트 같은 요소를 움직이기 위해 픽셀좌표를 이용할수 있습니다. 

box2d는 각도를 위해 라디안을 이용합니다. 바디의 회전은 라디안으로 값을 저장하고 증가 또는 
축소 할 수 있습니다. 각도의 크기가 너무 크다면 바디의 회전을 정규화 해야 합니다. 


1.8 Factories 와 Definetions
메모리 관리는 box2d api 에 있어서 중요한 역활은 합니다.  그래서 
b2body 나 b2joint 의 객체를 만든다면 b2world 의 팩토리 함수를 호출할 필요가 있습니다. 
다른방법으로 이런것들을(바디 조인트....)을 할당할 필요없습니다.

생성함수는 와 같습니다. 
b2Body* b2World::CreateBody(const b2BodyDef* def)
b2Joint* b2World::CreateJoint(const b2JointDef* def)
 
그리고 이와 반대의 메모리 해제는 아래와 같습니다.
void b2World::DestroyBody(b2Body* body)
void b2World::DestroyJoint(b2Joint* joint)

바디와 조인트를 만들때 definution을 필요로 한다.  그 definitions에는 바디와 조인트를 만드는데
필요한 정보들이 포함되어 있어야 한다.
이러한 접근법은
객체생성에서 에러를 줄일수 있고,
파라미터의 수를 줄일수 있고,
알맞은 정의를 제공할수 있고,
접근자의 수도 줄일수 있다.

fixtures 는 바디를 부모로 해야 하기때문에 b2Body의 팩토리 메소드를 이용해서 생성하도 해제 한다. 
b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
void b2Body::DestroyFixture(b2Fixture* fixture)

shape와 density로 부터 바로 fixture를 생성하는 방법이 있습니다. 
b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)

팩토리는 정의에 대한 참조를 유지하지 않는다. 그렇기 때문에 stack에 대한 정의를 만들어야 한고 임시 resources에 유지 해야 한다. 



1.9 유저 데이터 
b2Fixture 와 b2Body 그리고 b2Joint 클래스들은 void 포인트로서 user data에 접근해야 한다.
이것은
Box2D 자료 구조를 검토(?)할 때
게임엔진에서 엔티티에  어떻게 관계 지어야 할지를 결정할때 
유용합니다

예를 들면 강체에 actor 포인터를 붙이것이 일반적이다 . 이것은 연산 레퍼런스를 준비해야 한다.
만약 actor를 가지고 있다면 body획득할수 있다. 반대로 바디를 가지고 있다면 actor를 얻을수 있다. 
GameActor* actor = GameCreateActor();
b2BodyDef bodyDef;
bodyDef.userData = actor;
actor->body = box2Dworld->CreateBody(&bodyDef);

유저 데이터가 필요한 case가  몇가지 있다.
*충돌 결과를 이용하는 actor에 데미지(?)를 적용 할 때.
*플레이어가 축-정렬(axis-aligned) 박스안에 있다면 scripted event를 동작 시킬때
*조인트가 파괴 될것을 Box2d가 우리에게 알려줄때 겜임 구조에 접근.

유저 데이터는 하나의 옵션이고 어디에든지 위치 시킬수 있다라는 것을  명심해야 한다. 
그럼에도 불구하고 개발자는 항상 일관되어야 합니다(?) 예를 들어 
actor 포인트를 바디에 저장한다면  actor 포인트를 전체바디에 유지 해야한다.
하나의 바디에 actor 포인터나 첫번째 포인터를 다른 bosy에 저장하지 말것. 
첫번째 포인터를 actor 포인터로 캐스팅하는 것은 충돌을 일을킬수 있다. 

유저 데이터는 기본적으로 NULL 이다. 




Box2d를 이해하고 메뉴얼을 해석하는 것이 아니기 때문에 
번역상의 이상한점이아 오류들이 많을수 있습니다. 지적 해주시면 감사 하겟습니다.



 




































 
Posted by 수다쟁이증후군 :
1.JBox2d 란
==> Box2d를 자바환경에 변형한것이다. 

2.관련 문서들

box2d 매뉴얼
http://www.box2d.org/manual.pdf

한글화 작업 및 관련 강좌는 아래의 싸이트에 정리 잘되어있습니다. 
http://cafe.naver.com/uiaa.cafe

jbox2d 공식사이트
http://www.jbox2d.org

구글 코드 싸이트
http://code.google.com/p/jbox2d/

 
Posted by 수다쟁이증후군 :
0. EaseActionsTest 에 들어가며
==> 기본클래스 심화에 EaseAction에서 상세히 다루어서 그 관련 글들만 잘 보신다면.
    분석 하는데 별무리 없을듯 보입니다. 그래서 EaseAction클래스 심화내용중
    중요부분만 발췌하여 이번 분석예제를 대체하고 자 합니다. 
 
1.EaseAction의 기본 적인 내용


1. 클래스 설명

Base class for Easing actions


==> 액션을 쉽게 하게위한 기본 클래스 입니다. 
==> 말그대로 쉬운 액션 입니다. 액션을 보다 쉽고 재밌게 쓰기 위한 기본클래스입니다. 

==> 이렇게 클래스 소스에서 뽑아 낼수 있는 자료는 별로 없네요 그래서 홈페이지 있는
    자료를 참고 해봅니다.     

Ease 액션은 내부의 액션의 기간을 수정하는 특별한 composition액션입니다. 

Flash에서는 이러한 액션을 Tweening 또는 Easing 액션이라고 합니다.


이 액션을 내부 액션의 속도를 수정하지만 전체 동작 시간을 수정하지는 않습니다. 

내부 액션이 5초 동안 수행된다면 전체 시간은 5초 동안 진행될겁니다.


Ease 액션은 동작 시간을 선형적으로 수정합니다.
 

예를 들면 내부 액션을 가속화하거나 저속화합니다.

이 액션을 3가지 타입으로 구분할 수 있습니다. :


In actions: 액션의 처음부분을 가속화

Out actions: 액션의 끝 부분을 가속화

InOut actions: 처음/끝과 끝에서 가속화

easing 또는 tweening 액션은 다음 페이지를 참조하세요. :


http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html

http://www.robertpenner.com/easing/easing_demo.html 

위에 2페이지를 찾아 보시면 정말 깔끔하게 잘 정리 되어있습니다.  

 



2. 추가된 멤버 변수 

public static final float M_PI_X_2 = (float) (Math.PI * 2.0f);
protected CCIntervalAction other;


==>첫번째 멤버변수 M_PI_X_2  가 있는 것을 보니 액션을 사용할때 수학적인 요소를 사용하려
    나 봅니다.
==>
두번째 멤버변수  other  CCIntervalAction을 멤버변수로 하나더 가지고 있습니다. 이걸 왜 
    가지고 있을까요? 위에서 설명한바와 같이 액션의 기간을 수정하기위함입니다. 
    이는 기본액션의 인스턴스를 생성자의 파라미터로 가지기 때문입니다.
    그럼 기본액션들은 어떨까요?. 다른 기본액션들은 속성에 대한 데이터를 액션 생성자의  
    파라미터로 넘깁니다. 여기에 중요한 포인트입니다. 
    한마디로 EaseAction은  다른 기본액션을 담는 통이라는것입니다. 이와 유사한것을로
    시퀀스, 리핏, 무한리핏 또한 이런류의 액션을 담는 통입니다.  

    
3. 클래스 상속 관계도


(출처 :http://www.cocos2d-iphone.org/api-ref/0.99.0/interface_c_c_ease_action.html)
 
==>중간 중간 헷갈리수도 있으니 일단 참고하세요 

4. CCEaseAction을 상속하는 클래스들 (업데이트되는 분석글을 보려면 초록색글자 클릭)

CCEaseBackIn.java (2011/9/15 추가)

CCEaseBackInOut.java (2011/9/15 추가)

CCEaseBackOut.java (2011/9/15 추가)
 

CCEaseBounce.java (2011/9/15 추가)
* CCEaseBounceIn / CCEaseBounceInOut / CCEaseBounceOut  포함


CCEaseElastic.java (2011/9/15 추가)
CCEaseElasticIn /  CCEaseElasticInOut / CCEaseElasticOut 포함


CCEaseExponentialIn.java (2011/9/15 추가)

CCEaseExponentialInOut.java (2011/9/15)

CCEaseExponentialOut.java (2011/9/15)


CCEaseRateAction.java (2011/9/15)
CCEaseIn / CCEaseInOut / CCEaseOut  포함


CCEaseSineIn.java (2011/9/15)

CCEaseSineInOut.java (2011/9/15)

CCEaseSineOut.java (2011/9/15)


==> 위를 6개묶음으로 분류한것은 내부액션의 기간 수정 방법에 대한것입니다. 
     (결과값을 만들어내는 수식의 종류에 따라)


5. 쓰이는 곳 

==> 실제적으로 코드에서 사용할일은 없을듯합니다. CCEaseAction 클래스를 기반으로 
      확장된 클래스(4번참고)를 사용하세요 
==> cocos2d는 아직 확장중인 엔진으므로 혹시 사용자가 나만의 EaseAction을 구현할때나 
     쓰일 것 입니다.

6. 최종정리
 
  어떻게 하다보니 org.cocos2d.actions.ease 관련 클래스를 모두 정리하였습니다. 
막상정리하고 보니 별것도 없고 그냥 그렇네요 그런데 어떤 EaseAction을 쓸것인가
에 대한 고민을 안할수가 없네요 . 어떻게 해야 할까요? 하나하나 정리 테스트 해보면
좋겟지만. 먼가 감도 안오고 흠... 그래서 준비 했습니다. 

휘어지는 정도가 한눈에 보이네요 ㅎㅎㅎ 그럼 
잘 골라서 쓰세요 ㅎㅎ
 
 
Posted by 수다쟁이증후군 :
0.DrawPrimitivesTest 에 나오는 내용들

1.  Node를 이용하여 그리는것이 아닌 opengl의 기본 api를 1차 작업하여 
   좀더 쉽게 기본 선,원, 사각형 및 부드러운 곡선을 그리는 방법을 알수 있습니다. 



1. 예제 분석 목적. 
   기존의 화면 구성 방식에서 기본도형을 화면에 그리기 위한 api를 확인

2. 확인 속성. 

Primitives.drawLine    == > 선그리기
Primitives.drawPoint   == > 원그리기
Primitives.drawPoints == > 점을 여러개 
Primitives.drawCircle  == > 원그리기
Primitives.drawPoly    == > 점연결하여 선그리기
Primitives.drawQuadBezier 4점 Bezier 

Primitives.drawCubicBezier 3점 Bezier 





3. 기본도형 그리기 소스

public void draw(GL10 gl) {

   CCSize s = Director.sharedDirector().winSize();



   // draw a simple line

   // The default state is:

   // Line Width: 1

   // color: 255,255,255,255 (white, non-transparent)

   // Anti-Aliased

   gl.glEnable(GL10.GL_LINE_SMOOTH);

   

   Primitives.drawLine(gl, CCPoint.ccp(0, 0), CCPoint.ccp(s.width, s.height));


   // line: color, width, aliased

   // glLineWidth > 1 and GL_LINE_SMOOTH are not compatible

   // GL_SMOOTH_LINE_WIDTH_RANGE = (1,1) on iPhone

   gl.glDisable(GL10.GL_LINE_SMOOTH);

   gl.glLineWidth(5.0f);

   gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);

   Primitives.drawLine(gl, CCPoint.ccp(0, s.height), CCPoint.ccp(s.width, 0));


   // TIP:

   // If you are going to use always the same color or width, you don't

   // need to call it before every draw

   //

   // Remember: OpenGL is a state-machine.


   // draw big point in the center

   gl.glPointSize(64);

   gl.glColor4f(0.0f, 0.0f, 1.0f, 0.5f);

   Primitives.drawPoint(gl, s.width / 2, s.height / 2);


   // draw 4 small points

   CCPoint points[] = {CCPoint.ccp(60, 60), CCPoint.ccp(70, 70), CCPoint.ccp(60, 70), CCPoint.ccp(70, 60)};

   gl.glPointSize(4);

   gl.glColor4f(0.0f, 1.0f, 1.0f, 1.0f);

   Primitives.drawPoints(gl, points, 4);


   // draw a green circle with 10 segments

   gl.glLineWidth(16);

   gl.glColor4f(0.0f, 1.0f, 0.0f, 1.0f);

   Primitives.drawCircle(gl, s.width / 2, s.height / 2, 100, 0, 10, false);


   // draw a green circle with 50 segments with line to center

   gl.glLineWidth(2);

   gl.glColor4f(0.0f, 1.0f, 1.0f, 1.0f);

   Primitives.drawCircle(gl, s.width / 2, s.height / 2, 50, CCMacros.CC_DEGREES_TO_RADIANS(90), 50, true);


   // open yellow poly

   gl.glColor4f(1.0f, 1.0f, 0.0f, 1.0f);

   gl.glLineWidth(10);

   CCPoint vertices[] = {CCPoint.ccp(0, 0), CCPoint.ccp(50, 50), CCPoint.ccp(100, 50), CCPoint.ccp(100, 100), CCPoint.ccp(50, 100)};

   Primitives.drawPoly(gl, vertices, 5, false);


   // closed purple poly

   gl.glColor4f(1.0f, 0.0f, 1.0f, 1.0f);

   gl.glLineWidth(2);

   CCPoint vertices2[] = {CCPoint.ccp(30, 130), CCPoint.ccp(30, 230), CCPoint.ccp(50, 200)};

   Primitives.drawPoly(gl, vertices2, 3, true);


   // draw quad bezier path

   Primitives.drawQuadBezier(gl, 0,s.height, s.width/2,s.height/2, s.width, s.height, 50);


   // draw cubic bezier path

   Primitives.drawCubicBezier(gl, s.width/2, s.height/2, s.width/2+30, s.height/2+50,

  s.width/2+60, s.height/2-50, s.width, s.height/2,100);



   // restore original values

   gl.glLineWidth(1);

   gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

   gl.glPointSize(1);

        }




기존에는 텍스쳐를 이용한 렌더링을 하였습니다. 이제 모든 그리기 라이브러리의 기초인 
기본도형 그리기를 cocos2d가 어떻게 구현하는지에 대해서 나와 잇습니다. 
크게 어려운 부분이 없을뿐더러 소스에는 친절한 주석이 나와있으므로 이를 간단하게 해석하는 
것으로 이번 강좌는 정리하겟습니다.

 // TIP:

   // If you are going to use always the same color or width, you don't

   // need to call it before every draw

   //

   // Remember: OpenGL is a state-machine.
같은 색깔이나 동일한 두께를 표현하기 위해서 매번 따로 설정할필요 없습니다.
한번 바뀐 속성은 계속 지속됩니다.
이는 opengl이 정적이기 때문입니다. 이를 잘기억하세요  







// TIP:

Every CocosNode has a "draw" method.

모든 cocosNode는 "draw" 함수를 가지고 있다
 

In the "draw" method you put all the code that actually draws your node.

이함수 안에서 node에 실제그려지므로 여기에 코드를 놓을수 있다. 
 

And Test1 is a subclass of TestDemo, which is a subclass of Layer, which is a subclass of CocosNode.

TestDeomo는 Layer의 서브 클래스 이고 Layer는 CoccosNode의 서브 클래스이다. 
 

As you can see the drawing primitives aren't CocosNode objects. They are just helper

여기에서는 cocosNode의 object를 그리지 않고 기본도형을 그리기볼수 있는데 이것들은
 

functions that let's you draw basic things like: points, line, polygons and circles.

 기본적인 도형을 그리는것을 도와주는 함수 들이다.

        //
 

TIP:

Don't draw your stuff outside the "draw" method. Otherwise it won't get transformed.

"draw"메서드 밖에서 그리지 마세요 . 그러면 재대로 적용이 되지 않는다.

        //

TIP:

If you want to rotate/translate/scale a circle or any other "primtive", you can do it by rotating

the node. eg:

   this.rotation = 90;

만약 도형의 회전/이동/크기의 변화를 주고 싶다면. Node의 속성을 이용하세요 

 






















Posted by 수다쟁이증후군 :
0. CocosNodeTest에 나오는 내용들

1. 앵커의 정의화 position과의 관계
2. 부노노드의 앵커의 변화에 따른 자식노드에 끼치는 영향 과 부노노드에 액션이 작용할때
      자식노드가 어떤 영향을 받는가?
3. Z-order에 대한 설명 간략히
4. Tag의 유일성과 중첩성(분류)
5. removechild()의 영향과 자식 노드의 재사용에 대해서 
6. 부모노드가 할매노드에서 제거 될때 자식노드의 상태 
   액션 콜백과 콜백. 
 





1.예제 분석 목적: 
=>CCNode 주요속성의 변경방법과 속성이 변경될때 화면에 어떻게 나타 나는가를 확인



2.확인속성

Test1.class==>Transform Anchor
Test2.class==>Transform Anchor and Children
Test3.class==>Z Order
Test4.class==>Tags
Test5.class==>Remove
Test6.class==>Remove with Children
Test7.class==>Stress Test #1







* 코드 설명중 속성의 변화에 따른 액션 부분은 제외 하였습니다.
3-1 Test1 ( Transform Anchor  )

Sprite sp0 = Sprite.sprite("grossini.png");

Sprite sp1 = Sprite.sprite("grossinis_sister1.png");

Sprite sp2 = Sprite.sprite("grossinis_sister2.png");

Sprite point0 = Sprite.sprite("r1.png");

Sprite point1 = Sprite.sprite("r1.png");

Sprite point2 = Sprite.sprite("r1.png");


point0.scale(0.25f);

point1.scale(0.25f);

point2.scale(0.25f);


sp0.setPosition(s.width/2, s.height / 2);

point0.setPosition(sp0.getPositionX(), sp0.getPositionY());

sp0.setAnchorPoint(0.5f, 0.5f);


sp1.setPosition(s.width/2 - 100, s.height / 2);

point1.setPosition(sp1.getPositionX(), sp1.getPositionY());

sp1.setAnchorPoint(0, 0);


sp2.setPosition(s.width/2 + 100, s.height / 2);

point2.setPosition(sp2.getPositionX(), sp2.getPositionY());

sp2.setAnchorPoint(1, 1);


addChild(sp0);

addChild(sp1);

addChild(sp2);


addChild(point0, 1);

addChild(point1, 1);

addChild(point2, 1);



사전 필요 지식
1. sprite는 기본적으로 앵커점을 0.5f 0.5f 로 잡고 시작합니다.(이미지의 센터점)
2. cocos2d의 좌표계는 Top-Left 가 아니라 Bottom-Left 입니다. 
   이에 반해 안드로이드의 화면 좌표계는 Top-Left 라서 처음 cocos2d를 접하시는 분들이 
   좀헷갈려합니다. 

코드 설명
sp0, sp1,sp2 를 화면센터에 수평정렬입니다.
point0,point1,point2 는 sp0, sp1, sp2의 앵커 포인트를 가리키고 있습니다. 
그리고 나서 sp0 sp1 sp2 의 앵커 포인트를 변형합니다. 그리고 나타난 화면은 
처음 앵커 포인트를 알게된사람들은 언듯 이해가 가지 않습니다.

이에 대해서 자세한 설명은 앵커포인트와 비슷한 이름을 지닌 position 과 비교하면 좀 더 
이해가 잘 될듯합니다. 
position은 부모Node 의 0,0 좌표에서 얼마나 떨어져 있는 지를  x와 y로 나타 낸것입니다.
Node가 (100,200)이면  부모노드에서 x 100만큼 y 200만큼 떨어진 곳에 이란것입니다.
이때 자신의 기준은 무엇일까요? 머 앵커를 설명하는 자리니까 당연히 앵커가 되겟죠.

다시말해 사이즈 가로50 세로50인 이미지를 부모노드에서 (100,200)만큼 움직이라고 하는데 
어디를 기준으로 잡아야 할까요? 이미지의 왼쪽아래? 오른쪽아래? 정가운데?
이게 바로 앵커입니다. Node의 크기가 사용자마다 다르니 특정 크기값으로 하지 말고 
이미지=Node의 원래 사이즈를 가로 세로 1 로 잡고 그 비율로 나타낸것입니다.내부적으로 화면
에 표시 될때는 이미지크기에 맞추어 특정 좌표로 표현되지만 우리가 그것까지 볼필요는
업습니다. 
(추후 강좌를 전체적인 업데이트 할 때 이미지도 포함하여 반영하겟습니다.)




3-2 Test2 (  Transform Anchor and Children  )

Sprite sp1 = Sprite.sprite("grossinis_sister1.png");

Sprite sp2 = Sprite.sprite("grossinis_sister2.png");

Sprite sp3 = Sprite.sprite("grossinis_sister1.png");

Sprite sp4 = Sprite.sprite("grossinis_sister2.png");


sp1.setPosition(100, s.height / 2);

sp2.setPosition(s.width - 100, s.height / 2);

addChild(sp1);

addChild(sp2);


sp3.scale(0.25f);

sp4.scale(0.25f);


sp1.addChild(sp3);

sp2.addChild(sp4);


IntervalAction a1 = RotateBy.action(2, 360);

IntervalAction a2 = ScaleBy.action(2, 2);


Action action1 = RepeatForever.action(Sequence.actions(a1, a2, a2.reverse()));

Action action2 = RepeatForever.action(Sequence.actions(a1.copy(), a2.copy(), a2.reverse()));


sp2.setAnchorPoint(0, 0);


sp1.runAction(action1);

sp2.runAction(action2);


이미 3-1에서 설명을 잘 이해 하셨다면 이번 내용은 어렵지 않겟 받아 들일것이라 생각합니다.
자식Node의  위치=position은 부모의 0.0 점을 기준으로 해서 결정된다 라고 위에서 이야기 드렸습니다. 그럼 그 부모노드가 속해있는 부모노드 그러니까 할배노드라 합시다. 
부모노드의 position은 할배노드의 0,0을 기준하겟죠, 결국 자식노드의 위치는 부모노드뿐만 아니라 할배노드에게도 영향을 받습니다.

이것을 액션의 rotate(회전변화)을 이용하여 상당히 적절하게 표현되고 있습니다. 실제 코드를 
돌려보기 전에 머리속으로 한번 그려보세요
할배노드 = Test2
부모노드 = sp1, sp2
자식노드 = sp3, sp4
입니다. 그와 더불어 부모노드에 대한 액션은 자식 노드에도 영향을 끼칩니다.
(강좌 업데이트때 이미지추가)





3-3 Test3 (Z Order)

Sprite sp1 = Sprite.sprite("grossinis_sister1.png");

Sprite sp2 = Sprite.sprite("grossinis_sister2.png");

Sprite sp3 = Sprite.sprite("grossini.png");


sp1.setPosition(20, 80);

sp2.setPosition(70, 50);

sp3.setPosition(s.width / 2, s.height / 2);
 

sp3.addChild(sp1, -1, kTagSprite1);
sp3.addChild(sp2, 1, kTagSprite2);


xy 축에 더불어 한가지 축 z축 입니다. z값이 양수면 화면앞 그러니까 사용자의 눈쪽 
가까이 위치하고 음수면 ,화면 너머에 위치합니다. 그러니까 이미지가 겹쳐질때 맨위로 오느냐 
맨뒤로 가서 가려지느냐의 차이를 설명한것입니다.
(참고이미지는 강좌 업데이트 하면서추가 하겟습니다.)








3-4 Test4 (Tags )

{
Sprite sp1 = Sprite.sprite("grossinis_sister1.png");

Sprite sp2 = Sprite.sprite("grossinis_sister2.png");


sp1.setPosition(100, s.height / 2);

sp2.setPosition(s.width - 100, s.height / 2);


addChild(sp1, 0, 2);

addChild(sp2, 0, 3);


schedule("delay2", 2.0f);

schedule("delay4", 4.0f);

}


public void delay2(float dt) {

     CocosNode node = getChild(2);

     IntervalAction action1 = RotateBy.action(1, 360);

node.runAction(action1);

}


public void delay4(float dt) {

     unschedule("delay4");

     removeChild(3, false);

}



태그는 말그대로 꼬리표입니다. 
안드로이드에서는 View클래스에 id 를 할당합니다. 
그 아이디를 기반으로 R.java 클래스 변수로 등록되고 액티비티 
어디에서든 접근 가능합니다.

그럼 cocos2d에 대한 구분자는 어떻게 할까요 ?
바로 TAG입니다  

안드로이드 id는  유일한 값입니다 이는 어플리케이션 package에서 관리
하기때문입니다. 
그럼 cocos2d에서는 tag는 어디서 관리할까요?
바로 자기 자신이 관리 합니다. 
그럼 으로서 활용방법은 2가지 입니다. 
Node의 독립성을 확보하기 위해 각기 고유 코드값으로 줄수도 있고
분류를 위한  비슷한 역활을 하는 Node들에서 공통의 값을 줄수도 있습니다.






3-5 remove and cleanup

public Test5() {

super();


CCSprite sp1 = CCSprite.sprite("grossinis_sister1.png");

CCSprite sp2 = CCSprite.sprite("grossinis_sister2.png");


sp1.setPosition(CGPoint.make(100, 160));

sp2.setPosition(CGPoint.make(380, 160));


CCIntervalAction rot = CCRotateBy.action(2, 360);

CCIntervalAction rot_back = rot.reverse();

//CCRepeatForever은 CCAction으로 받을것

CCAction forever = CCRepeatForever.action(

CCSequence.actions(rot, rot_back));

CCAction forever2 = forever.copy();


// forever.setTag(101);

// forever2.setTag(102);


addChild(sp1, 0, kTagSprite1);

addChild(sp2, 0, kTagSprite2);


sp1.runAction(forever);

sp2.runAction(forever2);


schedule("addAndRemove", 2.0f);

}


public void addAndRemove(float dt) {

CCNode sp1 = getChildByTag(kTagSprite1);

CCNode sp2 = getChildByTag(kTagSprite2);


removeChild(sp1, false);

removeChild(sp2, true);


addChild(sp2, 0, kTagSprite2);

addChild(sp1, 0, kTagSprite1);

}


부모노드에서 제거될때 자식노드의 상태에 대해서 
기술됩니다. 이는 단지 화면에서만 사라지는 것이 아니라 
자식노드가 가지고 있는 액션과 콜백/selector 는 어떻게 되는 것인가에 대한 예
보여 주고 있습니다

removeChild(sp1, false);
removeChild(sp2, true);
에서 보는 바와 같이 두번째 파라미터를 true로 하면  부모노드에서 자식노드를 삭제함과
동시에 자식노드의 액션과 콜백을 전부 초기화 하여 버립니다.
false로 한다면 액션과 콜백을 남겨두고 단지 소속만을 없애 버릴뿐입니다.
 


액션은 어디에 저장 되어 있을까?
removeChild(sp1, false);
removeChild(sp2, true);
분명 Layer의 child를 제거 했는데도 불구하고 
액션이 남이 있다면 .child의 action은 최소한 부모에게로 등록되지 않는다. 
그럼 ActionManager에 등록될때 child의 정보가 넘어간다는 소리인것 같은데 ㅎㅎ. ㅎ
소스 찾아 들어 가보니 역시 거기에 남아 있었다 . 
ActionManager 의 ConcurrentArrayHashMap 에 저장 되어 있어다 .
private final ConcurrentArrayHashMap<CCNode, HashElement> targets;
그러니까 다시 활성화 되게 layer에 등록시키면 AcManager가 알아서 찾아서 쓴다 
멀보고 할까?
addchild 안에 들어 가보면 뒤에 true와 false로 나뉜다 
ActionManager는 이것을 보고 액션은 실행시킬지 말지를 결정한다. 
무한 리핏액션이 아니면 액션이 종료되는 순간 이값은 false가 된다.









3-6 Test6 ( Remove with Children )

public Test6() {

            CCSize s = Director.sharedDirector().winSize();


            Sprite sp1 = Sprite.sprite("grossinis_sister1.png");

            Sprite sp11 = Sprite.sprite("grossinis_sister1.png");


            Sprite sp2 = Sprite.sprite("grossinis_sister2.png");

            Sprite sp21 = Sprite.sprite("grossinis_sister2.png");


            sp1.setPosition(100, s.height / 2);

            sp2.setPosition(s.width - 100, s.height / 2);



            IntervalAction rot = RotateBy.action(2, 360);

            IntervalAction rot_back = rot.reverse();

            Action forever1 = RepeatForever.action(Sequence.actions(rot, rot_back));

            Action forever11 = forever1.copy();


            Action forever2 = forever1.copy();

            Action forever21 = forever1.copy();


            addChild(sp1, 0, kTagSprite1);

            sp1.addChild(sp11);

            addChild(sp2, 0, kTagSprite2);

            sp2.addChild(sp21);


            sp1.runAction(forever1);

            sp11.runAction(forever11);

            sp2.runAction(forever2);

            sp21.runAction(forever21);


            schedule("addAndRemove", 2.0f);

        }


        public void addAndRemove(float dt) {

            CocosNode sp1 = getChild(kTagSprite1);

            CocosNode sp2 = getChild(kTagSprite2);


            removeChild(sp1, false);

            removeChild(sp2, true);


            addChild(sp1, 0, kTagSprite1);

            addChild(sp2, 0, kTagSprite2);

        }



이번번 예제는 할배노드에서 부모노드를 삭제할때 자식노드의 액션과 콜백은 어떻게 되느
냐를 묻는 건데요.결론만 먼저 말하자면 모두 삭제 됩니다.
자세한 내용은 cocos2d 내부 소스를 보시면 이해가 빠를겁니다.^^  결론은 간단한데 
그 내부를 설명하려면 몇단계를 거쳐야 하기때문에 일단 여기서는 제외합니다.



3-7 번 보류 StressTest
Posted by 수다쟁이증후군 :
1. 목적 
==> Action 과 밀접한 관련을 가지 scheduler 를 정확하게 인지 함으로 써 
     보다 나은 시스템을 구현하고자 합니다. 

2. 소스 분석. 
  2-1 안로로이드 activity 생명주기와  관련된 cocos2d 기본 셋팅.

==>이것은 기본 셋팅부분입니다. 이전 MenuTest 첫번째 강좌에서도 분석이 했기에 생략합니다. 


2.2. 기본 셋팅을 제외한 나머지 분석. 

2.2-1 멤버변수 

public static final int kTagAnimationDance = 1;
 

/*레이어 인덱스 번호*/
static
int sceneIdx=-1;

/* 구현될 클래스 */
static
Class<?> transitions[] = {

  SchedulerAutoremove.class,

  SchedulerPauseResume.class,

  SchedulerUnscheduleAll.class,

  SchedulerUnscheduleAllHard.class,

  SchedulerSchedulesAndRemove.class,

  SchedulerUpdate.class,

  SchedulerUpdateAndCustom.class,

  SchedulerUpdateFromCustom.class,

};



2.2-2  static classSchedulerTestLayer extendsCCLayer 

static class SchedulerTestLayer extends CCLayer {

    publicSchedulerTestLayer() {

      super();

 

      CGSize s = CCDirector.sharedDirector().winSize();

 

      CCLabel label = CCLabel.makeLabel(title(),"DroidSans", 24);

      addChild(label);

      label.setPosition(CGPoint.make(s.width / 2, s.height / 2 - 50));

 

      String subtitle = subtitle();

      if (subtitle!= null) {

        CCLabel l = CCLabel.makeLabel(subtitle(),"DroidSans", 16);

        addChild(l, 1);

        l.setPosition(s.width/2, s.height-80);

      }

 

      CCMenuItemImage item1 = CCMenuItemImage.item("b1.png", "b2.png", this, "backCallback");

      CCMenuItemImage item2 = CCMenuItemImage.item("r1.png", "r2.png", this, "restartCallback");

      CCMenuItemImage item3 = CCMenuItemImage.item("f1.png", "f2.png", this, "nextCallback");

 

      CCMenu menu = CCMenu.menu(item1,item2, item3);

      menu.setPosition(0, 0);

      item1.setPosition(s.width / 2 - 100, 30);

      item2.setPosition(s.width / 2, 30);

      item3.setPosition(s.width / 2 + 100, 30);

      addChild(menu, 1);

}

==> 레이어 공통을 따로 뽑아 구현 


2.2-3 
SchedulerTestLayer상속해서 구현해야 할 클래스들 

static class SchedulerAutoremove extendsSchedulerTestLayer
static classSchedulerPauseResume extendsSchedulerTestLayer
static classSchedulerUnscheduleAll extends chedulerTestLayer
static class chedulerUnscheduleAllHarextend SchedulerTestLayer 
static classchedulerSchedulesAndRemovextends chedulerTestLayer
static classTestNode extendsCCNode implements                                                        UpdateCallback

static classSchedulerUpdateAndCustom extends                          SchedulerTestLayer implementsUpdateCallback 

static classSchedulerUpdateFromCustom extends                        SchedulerTestLayer implementsUpdateCallback  
 
 



3. 주요 클래스 분석
3.1 static class SchedulerAutoremove extendsSchedulerTestLayer 

static class SchedulerAutoremove extends SchedulerTestLayer {

    float accum;

    publicSchedulerAutoremove() {

      super();

      schedule("autoremove", 0.5f);

      schedule("tick", 0.5f);

      accum = 0;

    }

    public void tick(float dt) {

      ccMacros.CCLOG(LOG_TAG, "Thisscheduler should not be removed");

    }

    public void autoremove(float dt) {

      accum += dt;

      String s = String.format("Time: %f", accum);

      ccMacros.CCLOG(LOG_TAG, s);

      if( accum > 3 ) {

        unschedule("autoremove");

        unschedule("tick");

        ccMacros.CCLOG(LOG_TAG, "schedulerremoved");

      }

    }

    public Stringtitle() {

      return "Self-remove an scheduler";

    }

    public Stringsubtitle() {

      return "1 scheduler will be autoremoved in 3seconds. See console";

}

}

==>schedule("tick", 0.5f);

   public void tick(float dt) {

      ccMacros.CCLOG(LOG_TAG, "Thisscheduler should not be removed");

   }
   에서 볼수 있듯이 기본본적으로 로그를 확인해야 알수 있다 .
==>Log 사용법은 tick(float dt)에 나와 있듯이 사용하면됩니다. 
==>schedule 함수 에서 알수 있듯이  첫번째 파라미터는 콜백함수 두번째 파라미터는 
   반복적으로 호출되어질 주기를 설정한다.
==>콜랙함수를 String 타임으로 넘기는것을 selector 라고 한다  당장은 이걸 왜 
   빨간색으로 했는지는 모르겟지만 뒤에 이것에 대한 것이 나온다 . 일단 알고갑시다.
==>
unschedule("autoremove"); 에서 볼수 있듯이 스케쥴의 해제는           unschedule(String selector)을 쓴다. 
==>특별히 어려운건 없습니다.  

3.2 static classSchedulerPauseResume extends chedulerTestLayer 

  static class SchedulerPauseResume extends SchedulerTestLayer {

    publicSchedulerPauseResume() {

      super();

      schedule(newUpdateCallback() {

        @Override

        public void update(float d) {

          tick1(d);

        }

      } , 0.5f);

      schedule(newUpdateCallback() {

        @Override

        public void update(float d) {

          tick2(d);

        }

      } , 1);

      schedule(newUpdateCallback() {

       

        @Override

        public void update(float d) {

          pause(d);

        }

      } , 3);

    }

    public void tick1(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick1");

    }

    public void tick2(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick2");

    }

    public void pause(float dt) {

      CCScheduler.sharedScheduler().pause(this);

    }

    public Stringtitle() {

      return "Pause / Resume";

    }

    public Stringsubtitle() {

      return "Scheduler should be paused after 3seconds. See console";

    }                 

  }

==>schedule(new UpdateCallback() {

        @Override

        public void update(float d) {

          tick1(d);

        }

      } , 0.5f);
    에서 볼수 있듯이 좀전과는 다르게 selector를 사용하지 않고  
UpdateCallback()
    인터페이스를 구현 해서 스케쥴하였습니다. 뒤에 0.5f 는 당연히 주기겟죠
    좀전에 selector를 기어억하라고 했던것은 이 때문입니다. 
==>
schedule을 구현하는데 있어서 2가지 방법이 바로 selector                                          와 UpdateCallback()구현입니다. 잘기억해두세요 

3.3 static classSchedulerUnscheduleAll extends                                                   SchedulerTestLayer 

static class SchedulerUnscheduleAll extends SchedulerTestLayer {

    publicSchedulerUnscheduleAll() {

      super();

      schedule("tick1", 0.5f);

      schedule("tick2", 1);

      schedule("tick3", 1.5f);

      schedule("tick4", 1.5f);

      schedule("unscheduleAll", 4);

    }

    public Stringtitle() {

      return "Unschedule All selectors";

    }

    public Stringsubtitle() {

      return "All scheduled selectors will beunscheduled in 4 seconds. See console";

    }

    public void tick1(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick1");

    }

    public void tick2(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick2");

    }

    public void tick3(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick3");

    }

    public void tick4(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick4");

    }

    public void unscheduleAll(float dt) {

      unscheduleAllSelectors();

    }

}

==> 이번에 하는것은 첫번째 것을 잘 보셨다면 무리 없이 진행 하실수 있을것입니다. 
     selector를 이용한 스케쥴링입니다. 
==> 다만 새롭게 나온것은  unscheduleAllSelectors(); 별거 없습니다. 
   selector로 등록했으니까 AllSelectors란 접미사가 붙는건 당연합니다. 
   selector로 등록한 모든 콜백을 삭제하라입니다. 


3.4 static class SchedulerUnscheduleAllHard extends                                                    SchedulerTestLayer 

static class SchedulerUnscheduleAllHard extends SchedulerTestLayer {

    publicSchedulerUnscheduleAllHard() {

      super();

      schedule("tick1", 0.5f);

      schedule("tick2", 1);

      schedule("tick3", 1.5f);

      schedule("tick4", 1.5f);

      schedule("unscheduleAll", 4);

    }

    public Stringtitle() {

      return "Unschedule All selectors #2";

    }

    public Stringsubtitle() {

      return "Unschedules all selectors after 4s.Uses CCScheduler. See console";

    }

    public void tick1(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick1");

    }

    public void tick2(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick2");

    }

    public void tick3(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick3");

    }

    public void tick4(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick4");

    }

    public void unscheduleAll(float dt) {

      CCScheduler.sharedScheduler().unscheduleAllSelectors();

    }

  }

==> 3.3의 살짝 변형인데요 모두 동일하고  
    3.3은 CCNode의 unscheduleAllSelectors() 함수를 이용했고
   3.4는 
sharedScheduler를 직접 이용했습니다. 
==> 바로 여기서 결정적인 차이가 나는데요 . CCNode의 schedule()함수를사용
   하면 해당 CCNode의 스케쥴만 헤제되는데 비해서 3.4처럼 해줘버리면
   cocos2d 전체의 스케쥴 걸어놓은것이 다 멈추어 버립니다. 그래서 제목에
   Hard가 붙은것이죠  

3.5 static classSchedulerSchedulesAndRemove extends                                                       SchedulerTestLayer 

static class SchedulerSchedulesAndRemove extends                                                     SchedulerTestLayer {

    publicSchedulerSchedulesAndRemove() {

      super();

      schedule("tick1", 0.5f);

      schedule("tick2", 1);

      schedule("scheduleAndUnschedule", 4);

    }

    public Stringtitle() {

      return "Schedule from Schedule";

    }

    public Stringsubtitle() {

      return "Will unschedule and scheduleselectors in 4s. See console";

    }

    public void tick1(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick1");

    }

    public void tick2(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick2");

    }

    public void tick3(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick3");

    }

    public void tick4(float dt) {

      ccMacros.CCLOG(LOG_TAG, "tick4");

    }

    public void scheduleAndUnschedule(float dt) {

      unschedule("scheduleAndUnschedule");

      unschedule("tick1");

      unschedule("tick2");

      schedule("tick3", 1);

      schedule("tick4", 1);

    }

}

==>지금까지는 대부분이 생성자에서 스케쥴링하는것인데 비해서 
   이번것은 selector에서 스케쥴을 생성해도 되는 것이냐 인데  됩니다. ㅎ
   이것도 흐름만을 잘읽어 간다면 무리없을듯 합니다.

3.6 static classSchedulerSchedulesAndRemove extends                                                SchedulerTestLayer 

static class TestNode extends CCNode implements UpdateCallback {

    String string_;

    publicTestNode(String string, int priority) {

      super();

      string_ = string;

      scheduleUpdate(priority);

    }

    public void update(float dt) {

      ccMacros.CCLOG(LOG_TAG, string_);

    }

}

static class SchedulerUpdate extendsSchedulerTestLayer {

    publicSchedulerUpdate() {

      super();

      //schedule in different order... just another test

      TestNode d = new TestNode("---", 50);

      addChild(d);

      TestNode b = new TestNode("3rd", 0);

      addChild(b);

      TestNode a = new TestNode("1st", -10);

      addChild(a);

      TestNode c = new TestNode("4th", 10);

      addChild(c);

      TestNode e = new TestNode("5th", 20);

      addChild(e);

      TestNode f = new TestNode("2nd", -5);

      addChild(f);

      schedule("removeUpdates", 4.0f);

    }

    public Stringtitle() {

      return "Schedule update with priority";

    }

    public Stringsubtitle() {

      return "3 scheduled updates. Priority shouldwork. Stops in 4s. See console";

    }

    public void removeUpdates(float dt) {

      if(getChildren() != null) {

        for (CCNodenode : getChildren()) {

          node.unscheduleAllSelectors();

        }

      }

    }

}


==>위의 예제는 2가지를 담고 있습니다. 한가지는 자식 노드의 스케쥴방법과 스케쥴의 
   우선순위 입니다.
==> 잘생각해본다면 우리가 구현하고자 하는 레이어의 어디에서 스케쥴을 정했는지 알수 
   있습니다. 바로 생성자에서 지정했습니다. 그리고 레이어쪽만 하다 잠시 까먹을 수도 
   있지만. 레이어도 Scene의 자식 CCNode 입니다. 똑같죠  ㅎㅎㅎㅎ
==> 자그럼 이번에 할것은 스케쥴이 동시에 발생하면 어느것이 먼저 발생할까요? 그거야    먼저 실핼됐던놈이 먼저 시작되는게 원칙이겟죠 ㅎㅎ



3-7 static classSchedulerUpdateAndCustom                                extends SchedulerTestLayer implements pdateCallback

static class SchedulerUpdateAndCustom extends                               SchedulerTestLayer implementsUpdateCallback {

    publicSchedulerUpdateAndCustom() {

      super();

      scheduleUpdate();

      schedule(newUpdateCallback() {       

        @Override

        public void update(float d) {

          tick(d);

        }

      });

      schedule(newUpdateCallback() {

        @Override

        public void update(float d) {

          stopSelectors(d);

        }

      }, 4.0f);

    }

    public Stringtitle() {

      return "Schedule Update + customselector";

    }

    public Stringsubtitle() {

      return "Update + custom selector at the sametime. Stops in 4s. See console";

    }

    public void update(float dt) {

      String s = String.format("update called:%f", dt);

      ccMacros.CCLOG(LOG_TAG, s);

    }

    public void tick(float dt) {

      String s = String.format("custom selector called:%f", dt);

      ccMacros.CCLOG(LOG_TAG, s);

    }

    public void stopSelectors(float dt) {

      unscheduleAllSelectors();

    }

}

==> 여기에서는 scheduleupdate() 함수와 커스텀 updatecallback 를 썩어 놓았습니다. 동작은 매 프레임마다 update()와 tick() 이 호출됩니다. 
이두개는 현제 레이어에 포함되어 있으므로 최종적으로 unscheduleAllSelectors();에 의해서 모두 제거 됩니다. 



3.8 static classSchedulerUpdateFromCustom extends                               SchedulerTestLayer implementsUpdateCallback

static class SchedulerUpdateFromCustom extends SchedulerTestLayer implementsUpdateCallback {

    publicSchedulerUpdateFromCustom() {

            super();

      schedule("schedUpdate", 2.0f);

    }

    public Stringtitle() {

      return "Schedule Update in 2 sec";

    }

    public Stringsubtitle() {

      return "Update schedules in 2 secs. Stops 2sec later. See console";

    }                 

    public void update(float dt) {

      String s = String.format("update called:%f", dt);

      ccMacros.CCLOG(LOG_TAG, s);

    }

    public void stopUpdate(float dt){

      unscheduleUpdate();

      unschedule("stopUpdate");

    }

    public void schedUpdate(float dt) {

      unschedule("schedUpdate");

      scheduleUpdate();

      schedule("stopUpdate", 2.0f);

    }

}

 

==> 여기서도 진행상에는 무리가 없습니다. 클래스명에서도 알수 있듯이 
    커스텀으로 만든 selector 에서 scheduleUpdate(); 를 사용하였습니다. 
    어찌보면 당연한 말이지요. 왜 이렇게 까지 했나 싶기도 하거든요. ㅎㅎㅎ


ScheduleTest.java 힘들고 복잡할꺼라 생각했는데 생각보다 별내용은 없네요
정리 하자면 이렇습니다.

1. 스케쥴을 생성하는 방법으로 3가지 있습니다. 
  1-1, selector이용
  1-2, updateCallback() 의 구현.
  1-3, update() 이용 입니다. 
  ==> 1-2와 1-3 거의 같은 말입니다.

2, 스케쥴 우선순위
3, 스케쥴 해제 방법

요렇게 3가지 정도로 압축되네요.  

Posted by 수다쟁이증후군 :
메뉴관련 예제를 정리하고  마지막으로 총정리 해봅니다. 

CCMenu  클래스 설명입니다. 

/** A CCMenu
 * 
 * Features and Limitation:
 *  - You can add MenuItem objects in runtime using addChild:
 *  - But the only accecpted children are MenuItem objects
 */
 


특징과 제한 
- CCMenuItem 인스턴스를 넣고 싶은때 언제나 멤버로 넣을수 있다 .
- 다만. CCMenuItem 이나 이를 상속한 클래스만 을 넣을수 있다 .

그럼 이제 CCMenuItem에는 어떤것들이 있나 보겟습니다. 
총 6개가 아래와  같이 있습니다. 

CCMenuItemAtlasFont

CCMenuItemFont

CCMenuItemImage

CCMenuItemLabel

CCMenuItemSprite

CCMenuItemToggle


위에 이놈들은 직접적이든 간접적이든 CCMenuItem을 상속 받았습니다. 
다만 요놈들끼리도 상속 구조를 이루는 부분들이 있는데 확인해보게습니다.



일단 CCMenuItem을 사용처에따라 분류해봅니다. 

1.이미지 메뉴아이템을 만들때 :
CCMenuItemSplite 을 사용하세요  
그리고 좀더 편하게 사용한다면 
CCMenuitemImage 를 사용하세요( 파일 이름으로 바로 생성가능 - 관련 강좌 클릭)
 

2.글자 메뉴아이템을 만들때
:
CCMenuItemLable를 사용하세요
그러나 다른 폰트및 사용자 폰트를 사용하려면 
CCMenuitemFont 와 CCMenuItemAtlasFont 를 사용하세요 
CCMenuitemFont는 디바이스 내장 폰트 사용하고 
CCMenuItemAtlasFont 사용자 폰트를 사용합니다. 
(
CCMenuItemLable 을 이용하여 사용자 폰트도 만들수 있지만. 개인적인 생각으로 는 분명 특화된 클래스가 있는데 그걸 사용하지않고 다른걸 기본클래스를 사용한다는 것은 시간낭비적
요소가 있지 않나 싶습니다.물론 세부적인 컨트롤이 가능하다는 측면이 있지만 그런일은 별로
없을듯 합니다. )



3.메뉴아이템을에 여러가지 상태값을 넣고 변경하고자 한다면 

CCMenuItemToggle을 사용하세요 



위 관련내용중 CCMenuItemSplite와 CCMenuItemImage를 제외하고 
다른 메뉴아이템은 클릭시에 기본액션은 글자확대=>복귀 이 있습니다. 


진짜 상세히는 못다루었지만. 이제 어떤메뉴라도 충분히 다룰수 있지 않았나 합니다. 
지금까지 전체 MenuTest관련 5강좌를 전부 읽고도 
메뉴를 만들지 못하신다면 문의 주세요 만들어 드립니다. ㅎㅎㅎ
 
 
 

 




 
Posted by 수다쟁이증후군 :

자자 거의 다와 가네요

이전 시간에는               

1.CCMenuItem 할 때 크기를 따로 지정한다
 item1.setScaleX(1.5f);

2.CCMenu 수직 수평 정렬할때 padding값을 주어서 간격을 
 조절한다. 

 
menu.alignItemsVertically(40);

 menu.alignItemsHorizontally(40);    

요거했네요 진짜 별거 없없죠 ㅎ
이번엔느 Layer3를 해보죠 이번에는 좀더 건질것이 많이 있기를 바라면서
전체 소스 한번 볼까요?

        

아 실망 스럽게도 메뉴 관련해서는 특이할만게 별로없고 다만 Action에 관한것 밖에 없에요 .            
두번째 강좌에서 이미  봤던내용의 반복입니다. 
CCAction 부분도 
기본개념 강좌 2
번째 강좌에서 다루었던내용이고  머 . .


CCJumpBy에대해서 상세하게 다루지 않았기에 간단히 정리 해봅시다.

CCIntervalAction jump = CCJumpBy.action(3.0f, CGPoint.ccp(400,0), 50, 4);

item2.runAction(                CCRepeatForever.action(CCSequence.actions(jump, jump.reverse())));
첫번째 파라미터는 시간
두번째 파라미터는 얼마만큼 이동할것 인가?
세번째 파라미터는 점프을 얼마만큼?
네번째 파라미터는 시간내에 몇번을 점프할것인가?
입니다. 

그리고 CCMenuItem 의 액션을 시행하는데
미리 지정한 점프액션과 그에 대한 역액션을 순서대로 무한반복해라 입니다.
진짜 별거 없죠 ㅎㅎ. 

콜백에서 참고할만 것이 있는가 보니 

disabledItem.setIsEnabled(!disabledItem.isEnabled());
disabledItem.stopAllActions(); 

요고 있네요 .
MenuItem 비 활성화와
해당 MenuItem의 액션을 정지 시키기
입니다.



그럼 Layer4로 바로 갈께요 .  아래는 전체 소스 보기 입니다.
 

오호 라 새로운것 하나 나왔습니다. 

바로 CCMenuItemToggle 입니다.  자자 가볼까요 ?
토글 말그대로 입니다. 2가지의 상태변화 입니다. 
A => B , B => A
입니다.  
CCMenuItemToggle item1 = CCMenuItemToggle.item(this,                                       "menuCallback",

                          CCMenuItemFont.item("On"),
                          CCMenuItemFont.item("Off")};
별거 없죠 
첫번째 파라미터 타겟 CCNode
두번째 파라미터는 콜백함수 
세번째와 네번째는 상태변화 될  MenuItem 입니다. 
상태변화도리 MenuItem은 몇개든지 추가 될수 있습니다. 

CCMenuItemToggle item1 = CCMenuItemToggle.item(this,                                       "menuCallback",

                          CCMenuItemFont.item("On"),
                          CCMenuItemFont.item("Off"),
                          CCMenuItemFont.item("On1"),
                          CCMenuItemFont.item("On2"),
                          CCMenuItemFont.item("On3"),
                          CCMenuItemFont.item("On4"),
                          CCMenuItemFont.item("On5"),
                          CCMenuItemFont.item("On6"),
                          CCMenuItemFont.item("On7"),
                          CCMenuItemFont.item("On8"),
                          CCMenuItemFont.item("On9")
};
이렇게 말이죠 메뉴아이템은 콜백과 별도로
상태변화MenuItem들을 순차적으로 변화시켜줍니다. 맨 끝으로 변화 되면 다시 첫번째가 나타납니다. 한마디로 루프죠 . 

다르게 추가 하는방법은
바로 아래에 나오는데요.
CCMenuItemToggle item4 = CCMenuItemToggle.item(this, "menuCallback", CCMenuItemFont.item("Off")); 

ArrayList<CCMenuItemFont> more_items = new ArrayList<CCMenuItemFont>();

            more_items.add(CCMenuItemFont.item("33%"));

            more_items.add(CCMenuItemFont.item("66%"));

            more_items.add(CCMenuItemFont.item("100%"));
item4.getSubItemsRef().addAll(more_items); 

ArrayList에 추가 해서 한번에 할당하기 입니다.간단하죠 .

한가지 추가로 MenuItemToggle이 첫번째 로딩될때 나올 순서를 미리 정할수 도 있는데 그건 아래와 같습니다.  
item4.setSelectedIndex(2);
이로써 기본적인것은 되었구요 . 

하나 재미난것이 있던데 메뉴 정리할때

CCMenu menu = CCMenu.menu(title1, title2, item1, item2, title3, title4, item3, item4, back); // 9 items.

menu.alignItemsInColumns(new int[]{2, 2, 2, 2, 1}); 

첫번째 라인에 순서대로 2개배치하고
2번째 라인에 그다음 2개를 배치하고
3번째 라인에 그다음 2개를 배치하고 
....

마지막은 1개를 배치합니다. 
이런식으로 배치합니다.  

다됐네요
메뉴관련해서는 별다른 내용이 없네요 다만 MenuItem의 선언부분만 잘체크한다면 별다른 어려움없이 정리 될듯합니다.

이로써 한개의 예제를 끝냈는데요 아직 저도 미숙하고 글적는 솜씨도 부족해서
의도가 잘전달 안됐을것도 같네요 .
다음 예제는 이번에 글적으면서 부족했던점을 좀더 보완하여 체계적으로 적어도록
노력하겟습니다. 다음 강좌도 많이 봐주세요  






 

              

                

                   

Posted by 수다쟁이증후군 :
자 이번엔.menuTest.java 의 마지막 시간이 될듯합니다. 

Layer2 클래스에 대해서 알아보죠  

아래는 전체 소스 입니다. 

 
결과 물입니다.  


첫번째는 가로 정렬 
두번째는 about버튼을 눌렀을때 나타나는 화면입니다.

간단히 이야기 하자면 메뉴 2개 만들어서 가로 정렬 해보고 세로정렬 해봤습니다. 
그럼 일단 메뉴2개를 만들어보죠 

public static final int kTagMenu = 1;

public Layer2() {

   super();

      for( int i=0;i < 2;i++ ) {

         CCMenuItemImage item1 = CCMenuItemImage.item("btn-play-normal.png", "btn-play-selected.png", this, "menuCallbackBack");

         CCMenuItemImage item2 = CCMenuItemImage.item("btn-highscores-normal.png", "btn-highscores-selected.png", this, "menuCallbackOpacity");

         CCMenuItemImage item3 = CCMenuItemImage.item("btn-about-normal.png", "btn-about-selected.png", this, "menuCallbackAlign");

  item1.setScaleX(1.5f);

         item2.setScaleY(0.5f);

         item3.setScaleX(0.5f);

         CCMenu menu = CCMenu.menu(item1, item2, item3); 

               menu.setTag(kTagMenu); 

               addChild(menu, 0, 100+i);

               centeredMenu = menu.getPosition();

        } 

     alignedH = true;

     alignMenusH();
}
생성자에서 만들었네요
CCMenuItemImage 를 이용해서 이미지버튼을 3개 만들고 
각 버튼의 크기를 셋팅합니다.
첫번째 CCMenuItemImage는 원래 사이즈에서 가로 1.5배 
두번째 CCMenuItemImage는 원래 사이즈에서 세로를 0.5배 
세번째 CCMenuItemImage는 원래 사이즈에서 가로 0.5배

이버튼들을 Menu에 넣었습니다. 그리고 수평정렬 함수를 호출합니다.
centeredMenu의 값은 ( 0 , 0 )  입니다 앵커의값이죠 
갤럭시 기준으로 하면 480 800  인니까 240 에 400 이 되겟네요 

------------------2011년 9월 10일 추가 내용 TAG--------------------
제가  이부분을 깝빡 했네요 

menu.setTag(kTagMenu); 
addChild(menu, 0, 100+i);
태그는 말그대로 꼬리표입니다.
안드로이드에서는 View클래스에 id 를 할당합니다.
그 아이디를 기반으로 R.java 클래스 변수로 등록되고 액티비티
어디에서든 접근 가능합니다.

그럼 cocos2d에 대한 구분자는 어떻게 할까요 ?
바로 TAG입니다  

안드로이드 id는  유일한 값입니다 이는 어플리케이션 package에서 관리
하기때문입니다.
그럼 cocos2d에서는 tag는 어디서 관리할까요?
바로 자기 자신이 관리 합니다. 
그럼 으로서 활용방법은 2가지 입니다. 
Node의 독립성을 확보하기 위해 각기 고유 코드값으로 줄수도 있고
분류를 위한  비슷한 역활을 하는 Node들에서 공통의 값을 줄수도 있습니다.(2011년 9월 26일 수정)

바로 부모 CCNode에서 관리합니다.

결국 이말은 부모만 다르다면 같은 TAG 값을 가져도 됩니다. 이명제의 대우는 무엇일까요? 
같은 부모를 가지는 CCNode는 서로 다른 값을 가져야 한다는 말과 같습니다. 즉 유니크 해야 한다는거죠 ㅎㅎㅎ
Tag에 대해서 간단히 살펴 보았습니다.

헷살리는 분이 있으시면 댓글로^^;

-------------------------------------------------------------



자그럼 수평정렬 함수를 확인해보겟습니다.

public void alignMenusH() {

    for(int i=0;i<2;i++) {

       CCMenu menu = (CCMenu) getChildByTag(100+i);

       menu.setPosition(centeredMenu);

       if(i==0) {

           // TIP: if no padding, padding = 5

           menu.alignItemsHorizontally();              

           final CGPoint p = menu.getPositionRef();

           menu.setPosition(CGPoint.ccpAdd(p, CGPoint.ccp(0,30)));

       } else {

           // TIP: but padding is configurable

           menu.alignItemsHorizontally(40);

           final CGPoint p = menu.getPositionRef();

           menu.setPosition(CGPoint.ccpSub(p, CGPoint.ccp(0,30)));

       }

   }
}

메뉴를 불러와서 하나는 CCMenu 에 있는 MenuItem 간의 간격이 을 결정합니다. 
디폴트로 5가 삽입되어있구요  밑에는 40이라는 상수 값을 주었네요 .
menu.setPosition(CGPoint.ccpAdd(p, CGPoint.ccp(0,30)));
menu.setPosition(CGPoint.ccpSub(p, CGPoint.ccp(0,30))); 

그리고 위에는 센터에서 y좌표값이 +30 이니까 화면에서 위로 올라 가겟고 
아래는 센터에서 30 내려 가는 것이니까 화면에서 내려 가겟네요 ^^;


수직정렬도 이와 거의 똑같습니다. 
 public void alignMenusV() {

    for(int i=0;i<2;i++) {

       CCMenu menu = (CCMenu) getChildByTag(100+i);

       menu.setPosition(centeredMenu);

       if(i==0) {

           // TIP: if no padding, padding = 5

           menu.alignItemsVertically();              

           final CGPoint p = menu.getPositionRef();

           menu.setPosition(CGPoint.ccpAdd(p, CGPoint.ccp(100,0)));

       else {

           // TIP: but padding is configurable

           menu.alignItemsVertically(40);

           final CGPoint p = menu.getPositionRef();

           menu.setPosition(CGPoint.ccpSub(p, CGPoint.ccp(100,0)));

       }

   }
}

 이정도야 머 쉽죠이 ㅎ.ㅎ 

자 마지막으로  콜백에서 볼만한게 있는지 확인해볼까요?

public void menuCallbackBack (Object sender) {

     ((CCMultiplexLayer)getParent()).switchTo(0);

}
이거는 이미 한번 했고 레이서 순서 바꾸기 


public void menuCallbackOpacity (Object sender) {

     CCMenuItem item = (CCMenuItem)sender;

     CCMenu menu = (CCMenu)item.getParent();

     int opacity = menu.getOpacity();

     if (opacity == 128)

         menu.setOpacity((byte) 255);

     else

         menu.setOpacity((byte) 128);     
}
opacity 는 불투명도는 나타내죠 그런데 255로 변화 시키니까 아에 안보이고
이벤트도 안먹네요  흠... 이벤트 안먹히고 이건 따로 한번 알아 볼께요 
사라지는것 까지는 이해 했는데 이벤트라 ... 아시는분 댓글좀^^;; 

public void menuCallbackAlign (Object sender) {

     alignedH = ! alignedH;

     if( alignedH )

         alignMenusH();

     else

         alignMenusV();

}
기건머 2말 할필요없죠 ^^





자 그럼 여기까지가 . Layer2엿습니다.


여기서 새롭게 알게 된거는

1.
CCMenuItem 할 때 크기를 따로 지정한다

 item1.setScaleX(1.5f);

2.CCNode 의 TAG
 CCNode는 자식간의 구별과 접근 용이성을 높이기 위해 TAG을 할당한다. 입니다. 

3.CCMenu 수직 수평 정렬할때 padding값을 주어서 간격을
 조절한다.

 menu.alignItemsVertically(40);
 menu.alignItemsHorizontally(40);

딸랑 요거 하나네요 .

Posted by 수다쟁이증후군 :
쏘스를 하나 하나 씹어 먹어 봅시다 . 
일단.  먼저 할것은 Menu 관련 입니다. 
경로는 org.cocos2d.tests 패키지에 MenuTest.class 입니다.  
 @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE); 

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

                WindowManager.LayoutParams.FLAG_FULLSCREEN);

 

        mGLSurfaceView = new CCGLSurfaceView(this);

        setContentView(mGLSurfaceView);

    }
 

requestWindowFeature(Window.
FEATURE_NO_TITLE);
==>타이틀바 를 삭제 합니다. 

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,                WindowManager.LayoutParams.FLAG_FULLSCREEN);
==>상태바 (안테나 뜨는 부분을 삭제합니다) 

mGLSurfaceView = new CCGLSurfaceView(this);
setContentView(mGLSurfaceView);
==>CCGLSurfaceView 클래스 GLSurfaceView 를 상속합니다. 
여기에 대해서 말할거리는 정말 많죠 그러나 일단은 성능 좋은 이미지뷰를 화면에
생성 한다 라고 만 알아둡시다 . 추후에 여기에 대해서 장기간에 걸쳐서 강좌를
진행해보겟습니다.  

onCreate() 부분을 간단히 요약하자만 cocos2d를 사용하기 위해서 
View 하나 생성 했다 입니다. 물론 전체 화면이니 나발이니 하는것은
하나의 옵션입니다. 이로써 준비는 끝났습니다. 실제 코드에 슬슬 들어 가보죠  

다음 라이프 싸이클에 따라 

@Override

    public void onStart() {

        super.onStart(); 

        // attach the OpenGL view to a window

        CCDirector.sharedDirector().attachInView(mGLSurfaceView); 

        // set landscape mode

        CCDirector.sharedDirector().setLandscape(false); 

        // show FPS

        CCDirector.sharedDirector().setDisplayFPS(true); 

        // frames per second

        CCDirector.sharedDirector().setAnimationInterval(1.0f / 60); 

        CCScene scene = CCScene.node(); 

        CCMultiplexLayer layer = CCMultiplexLayer.node(new Layer1(),

                                    new Layer2(), new Layer3(), new Layer4());

        scene.addChild(layer, 0);

        CCDirector.sharedDirector().runWithScene(scene);

    }

주석이 참 친절하게 잘되어있네요 . 
CCDirector.sharedDirector().attachInView(mGLSurfaceView);
이전강좌에서 CCDirector의 개념을 잠시 언급한적이 있죠 감독이며 자혼자 뿐이라고 
싱글스톤 입니다. CCDirecto 레퍼런스 변수 생성방법이 바로 요헐게 
CCDirector.sharedDirector() 입니다. 그리고 난후에 위의 onCreate에서 생성했던 성능 좋은 이미지뷰를 감독에게 넘겨줍니다. 전권 위임입니다.  

자그럼 프로그래머 입장에서 보면 감독을 한놈 정하고 그놈에서 전권을 맡긴 것이죠.
코드한줄에 주석이빠이 ㅎ. ㅎㅎ 

CCDirector.sharedDirector().setLandscape(false);
이부분은 감독에서 세로모드로 영화를 찍어라고 하는겁니다
인자값이 true면 당연히 가로 16:9 와이드로 영화를 찍어라고 하는것이죠. 근데 막상 감독이라고 해놓고 보니 아직은 지혼자 할 줄 아는게 없네요 프로그래머가 일일이 지시해야 하고 에휴~~ 이래서 머리 좋은 시다바리를 둬야 한다는 거죠 . ㅎ 자자 각설하고 
다음줄 

CCDirector.sharedDirector().setDisplayFPS(true);
화면 귀퉁이 FPS를 숫자로 보여 줄것인가 말것인가를 감독에게 시킵니다. FPS는 초당 프레임수 초당 화면 갱신을 몇번하는가를 말합니다. 그러면 초당 몇번 보여라고 지정하는부분도 있겟죠 그게 바로 다음줄 
 

CCDirector.sharedDirector().setAnimationInterval(1.0f / 60);
입니다. CCAction 기초강좌 에서도 보았듯이 cocos2d의 시간 단위는 1초입니다.
변수 타입은 float 입니다. 그러니까 1.0f는 1초 0.5f는 0.5초 입니다. 이를
60으로 나누었으니 초당 60번의 화면 갱신이 일어나게끔 한다는것입니다. 일반적인
에니메이션은 24프레임이고 디즈니가 36프레임인가로 알고 있는데 상당히 부드럽자나요 .
그것보다 더 부드럽게 움직이라고 하는겁니다.  실제 화면구동에서는 이보다 속도가 안나올수도있습니다 많이 내려갈때는 30프레임 까지 내려가더군요 . 그래도 상당히 아니 매우 빠른속도니까 화면의 대상은 부드럽게 움직입니다.  

CCScene scene = CCScene.node();
드디어 이제 시작인가요 .ㅎ ㅎ 여기서 강좌끝내버리면 낚시겟죠 ㅎㅎ.
CCScene 인스턴스를 생성하는 방법입니다. 참쉽죠 
CCScene.node();이렇게 클래스명적고 .node()라고 하면 되니까 ㅎ 
이렇게 선언하면됩니다. 


CCMultiplexLayer layer = CCMultiplexLayer.node(new Layer1(),

                            new Layer2(), new Layer3(), newLayer4());

입니다. 레이어 선언이네요 CCLayer를 상속한  CCMultiplexLyer
이름도 거창한 멀티플렉스 전부 아시죠 멀티플렉스영화관 영화관은 영화관인데 기본의 상영관이 1개인 영화관은 한건물에 때려넣은 영화관!

자기 이름도 영화관이면서 안에 1개짜리 영화관을 때려넣고 앞에 멀티플렉스라고 명명한
건물. 여기서도 동일하게 적용됩니다. CCLayer클래스인데 안에 멤버변수(ArryList)로 다른 CCLayer를 담을수 있는 이름도 거창한. CCMultiplexLayer 입니다. 
그러고 보니까 안쪽에 레이어를 쳐담고 있죠 new로 생성해서요 . 

" 어라 cocos2d에 Layer1()이란 클래스가 있었나 ?" 라는 궁긍증일어나겟죠  
결론적으로 없습니다, 걍 다음 소스에서 도 나오겟지만. 예제 만든사람이  CCLaer클래스를 상속하여 만든것뿐입니다. 오해가 없으시길. 

scene.addChild(layer, 0);

CCDirector.sharedDirector().runWithScene(scene);

어라 이제까지 우리가 만들어 놓은 걸 담고 있네요 . 이는 기본강좌 에도 나와 있지만. ^^ (거의 중간 광고 수준이네요 ㅋㅋㅋ 한번쯤 읽어 보라는 압력. ㄷㄷ ) 
CCDirector는 CCScene를 담을수 있고  
CCSecen은 CCLayer를 담을수 있고
CCLayer는 CCSplite를 담을수 있습니다. 

담는 방법은 위에 나와 있습니다.
scene.addChild(layer, 0);==>CCSecen은 CCLayer를 담을수 있고
CCDirector.sharedDirector().runWithScene(scene);==>CCDirector는 CCScene를 담을수 있고
입니다. add든 runWithScene든 결과는 담는 겁니다. 

자이제 화면이 ON 되었습니다. 
그럼 이제 화면이 어떻게 움직일까요? 우리가 보았듯이 이름만 거창한 멀플렉스레이어가 실제 우리 눈에 보이는 부분입니다.
그럼 이놈을 분석해보면 화면이 어떻게 돌아 가는지 알수 있겟죠 ㅎㅎ;


일단 중간 정리 한번하고 가죠 . 
OnCreate()에서 한일은 
1.전체화면 만들기 
2.성능좋은 이미지뷰 생성하기

OnStart()에서 한일은. 
1. 감독을 만들어 성능 좋은이미지 뷰랑 연결해주기 
2. 가로모드 세로모드 결정
3. FPS 정해주기 
4. CCScene와 CCLayer를 생성
5. 그릇 순서에 따라 담기 . 

자 ~~ 기본적인 것 정리는 다됐고  슬슬 또 진행해봅시다.


글중 에 잘못된 부분있다면 이야기 해주세요; ㅎㅎ 

Posted by 수다쟁이증후군 :