현재 pc 환경엣 웹페이지의 로딩 속도에 불편함을 느낀적이 있는가라고 물으면 어떠한가?
머 별로? 4~5년전에 나온 PC 라면 모를까 웹페이지 로딩에 대해서 불편함을 느낀적은
없다.
그런 데 구글이 다트를 발표했다. javascript 보다 속도가 획기적으로 빠르다라는것이다.
불편함을 느끼지 않는데 왜 속도에 중점을 맞춘 웹프로그래밍 언어를 개발 한거지?
답은 모바일이이다. 현재 스마트폰에서 웹페이지 볼려면 진짜 속터진다. 마치 2000년도 쯤에
pc로 웹페이지를 보던 경험을 다시 느끼고 있다. 그래서 요즘에 속도를 한층 높인. LTE 4세대통신이 뜨고있지 않은가? 아직 전국적으로 망이 깔리려면 시간이 좀더 걸리겟지만. 말이다.
그런데 구글은 이 답답함을 하드웨어적 접근이 아닌 소프트웨적으로 접근한다.
아예 속도저하의 하나인 js를 대체 하겟다는 것이다. 역시 구글 답다라는 생각이 든다.
얼마전에 아마존에서 실크라는 웹브라우저를 발표했다. 이는 웹페이지를 클라우스서버에서 한번 가공하여 사용자에게 전달해주는 방식인데 이또한 모바일 웹환경에 대한 속도의 문제를 위한 해결책이 었다. (개인정보가 클라우드에 저장된다는 문제가 남아 있지만. )
실크는 이미 킨틀의 내장 브라우저이고 다트는 본격적인 행보를 시작한다라고 외쳤다.
아마도 곧 구글의 다트는 안드로이드 운영체제의 웹브라우져에 버추얼머신(VM)이 탑제 될것이다.
이는 저의 지극히 개인적인 생각입니다. 그렇지만 가장 간단하면서도 확실히 저변을 확대할수
방법을 두고 구글이 돌아 갈 필요가 있을까요? 이렇게 VM이 기본탑제가 된다면 기존의 포털은
사용자에게 보다 쾌적하게 서비스를 제공해줄 방법으로 다트를 외면하긴 어려울겁니다.
" 아!!!. 네XX 스마트폰에서 느려서 못해먹겟다 아 젠장. "이말보다는
" 역시 네XX 로딩속도 좋아 ㅎㅎㅎ" 이말이 더좋을겁니다.
현재는 어떠한 싸이트던지 속도가 거기서 거기니까 별 차이점이 없겟지만.
한 군데라도 차이가 나기 시작한다면 후발업체는 당연히 따라가겟죠 결국 다트는 안정정인 기반을
다지게 됩니다.
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);
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와 충돌하지 않고
움직이지 안는다.
세번재 단계로 그라운드 폴리곤을 생성한다. 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을
시뮬레이션한다.
타일 기반 게임의 장점
* 메모리를 절약할 수 있다.
* 게임 세계의 효과적인 공간 분할에 따른 이점이 있다. 타일에 속성을 부여함으로써 충돌검사나 랜더링을 쉽게 할 수 있다. 캐릭터와 배경과의 상호작용을 처리하기가 쉽다.
* 그래픽 디자이너가 아닌 누구라도, 디자이너가 만들어둔 타일셋으로 맵 디자인을 할 수 있다.
타일 기반 게임의 단점
* 그래픽이 다소 지루하고 경직되어 보인다. 반복되는 타일 이미지가 많이 나타나며 유연성이 부족하다.
* 타일 이미지 제작, 관리가 힘들고 불편하다.
* 통짜맵에 비해 랜더링 알고리즘이 복잡하고 느리다.
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 을 보고 있는 것이다.
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 값을 갖는다.
그래서, 해당 작업은 다음과 같다:
Tiled 열기
배경 레이어 선택 (예: grass)
Tiled → Layer → Layer Properties
추가: cc_vertex = -1000
전경 레이어 선택 (예: trees)
Tiled → Layer → Layer Properties
추가: 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) ];
}
A: cc_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 을 사용한다.
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로 이동한다.
==>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도 별다른 차이점이 없다 여기서 설명한 내용이 전부 일뿐이다.
그런데 어떻게 글을쓰다 보니까 반말이 되었네요^^;;
글 수정하기도 ~~ 좀 그러니 ㅎㅎㅎ 이번만 양해 해주세요
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)를 구성하는 두 입자의 거리가 절대로 바뀌지 않을 때 그러한 물체를 강체라고 한다.
다이아몬드처럼 단단한 물체이다.
물리현상에서 실제로 존재하지 않지만 단순화된 물리 법칙을 구현하기 위해 가정하는 형태이다.
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 의 팩토리 함수를 호출할 필요가 있습니다.
다른방법으로 이런것들을(바디 조인트....)을 할당할 필요없습니다.
바디와 조인트를 만들때 definution을 필요로 한다. 그 definitions에는 바디와 조인트를 만드는데
필요한 정보들이 포함되어 있어야 한다.
이러한 접근법은
객체생성에서 에러를 줄일수 있고,
파라미터의 수를 줄일수 있고,
알맞은 정의를 제공할수 있고,
접근자의 수도 줄일수 있다.
fixtures 는 바디를 부모로 해야 하기때문에 b2Body의 팩토리 메소드를 이용해서 생성하도 해제 한다.
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를 이해하고 메뉴얼을 해석하는 것이 아니기 때문에
번역상의 이상한점이아 오류들이 많을수 있습니다. 지적 해주시면 감사 하겟습니다.
0. EaseActionsTest 에 들어가며 ==> 기본클래스 심화에 EaseAction에서 상세히 다루어서 그 관련 글들만 잘 보신다면. 분석 하는데 별무리 없을듯 보입니다. 그래서 EaseAction클래스 심화내용중 중요부분만 발췌하여 이번 분석예제를 대체하고 자 합니다. 1.EaseAction의 기본 적인 내용
1. 클래스 설명
Base class for Easing actions
==> 액션을 쉽게 하게위한 기본 클래스 입니다.
==> 말그대로 쉬운 액션 입니다. 액션을 보다 쉽고 재밌게 쓰기 위한 기본클래스입니다.
==> 이렇게 클래스 소스에서 뽑아 낼수 있는 자료는 별로 없네요 그래서 홈페이지 있는
자료를 참고 해봅니다.
public static final float M_PI_X_2 = (float) (Math.PI * 2.0f);
protected CCIntervalAction other;
==>첫번째 멤버변수 M_PI_X_2 가 있는 것을 보니 액션을 사용할때 수학적인 요소를 사용하려
나 봅니다.
==>두번째 멤버변수 other CCIntervalAction을 멤버변수로 하나더 가지고 있습니다. 이걸 왜
가지고 있을까요? 위에서 설명한바와 같이 액션의 기간을 수정하기위함입니다.
이는 기본액션의 인스턴스를 생성자의 파라미터로 가지기 때문입니다.
그럼 기본액션들은 어떨까요?. 다른 기본액션들은 속성에 대한 데이터를 액션 생성자의
파라미터로 넘깁니다. 여기에 중요한 포인트입니다.
한마디로 EaseAction은 다른 기본액션을 담는 통이라는것입니다. 이와 유사한것을로
시퀀스, 리핏, 무한리핏 또한 이런류의 액션을 담는 통입니다.
==> 위를 6개묶음으로 분류한것은 내부액션의 기간 수정 방법에 대한것입니다.
(결과값을 만들어내는 수식의 종류에 따라)
5. 쓰이는 곳
==> 실제적으로 코드에서 사용할일은 없을듯합니다. CCEaseAction 클래스를 기반으로
확장된 클래스(4번참고)를 사용하세요
==> cocos2d는 아직 확장중인 엔진으므로 혹시 사용자가 나만의 EaseAction을 구현할때나
쓰일 것 입니다.
6. 최종정리 어떻게 하다보니 org.cocos2d.actions.ease 관련 클래스를 모두 정리하였습니다. 막상정리하고 보니 별것도 없고 그냥 그렇네요 그런데 어떤 EaseAction을 쓸것인가 에 대한 고민을 안할수가 없네요 . 어떻게 해야 할까요? 하나하나 정리 테스트 해보면 좋겟지만. 먼가 감도 안오고 흠... 그래서 준비 했습니다.
휘어지는 정도가 한눈에 보이네요 ㅎㅎㅎ 그럼 잘 골라서 쓰세요 ㅎㅎ
기존에는 텍스쳐를 이용한 렌더링을 하였습니다. 이제 모든 그리기 라이브러리의 기초인
기본도형 그리기를 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
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 )
사전 필요 지식
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-1에서 설명을 잘 이해 하셨다면 이번 내용은 어렵지 않겟 받아 들일것이라 생각합니다.
자식Node의 위치=position은 부모의 0.0 점을 기준으로 해서 결정된다 라고 위에서 이야기 드렸습니다. 그럼 그 부모노드가 속해있는 부모노드 그러니까 할배노드라 합시다.
부모노드의 position은 할배노드의 0,0을 기준하겟죠, 결국 자식노드의 위치는 부모노드뿐만 아니라 할배노드에게도 영향을 받습니다.
이것을 액션의 rotate(회전변화)을 이용하여 상당히 적절하게 표현되고 있습니다. 실제 코드를
돌려보기 전에 머리속으로 한번 그려보세요
할배노드 = Test2
부모노드 = sp1, sp2
자식노드 = sp3, sp4
입니다. 그와 더불어 부모노드에 대한 액션은 자식 노드에도 영향을 끼칩니다.
(강좌 업데이트때 이미지추가)
xy 축에 더불어 한가지 축 z축 입니다. z값이 양수면 화면앞 그러니까 사용자의 눈쪽
가까이 위치하고 음수면 ,화면 너머에 위치합니다. 그러니까 이미지가 겹쳐질때 맨위로 오느냐
맨뒤로 가서 가려지느냐의 차이를 설명한것입니다.
(참고이미지는 강좌 업데이트 하면서추가 하겟습니다.)
태그는 말그대로 꼬리표입니다.
안드로이드에서는 View클래스에 id 를 할당합니다.
그 아이디를 기반으로 R.java 클래스 변수로 등록되고 액티비티
어디에서든 접근 가능합니다.
그럼 cocos2d에 대한 구분자는 어떻게 할까요 ?
바로 TAG입니다
안드로이드 id는 유일한 값입니다 이는 어플리케이션 package에서 관리
하기때문입니다.
그럼 cocos2d에서는 tag는 어디서 관리할까요?
바로 자기 자신이 관리 합니다.
그럼 으로서 활용방법은 2가지 입니다.
Node의 독립성을 확보하기 위해 각기 고유 코드값으로 줄수도 있고
분류를 위한 비슷한 역활을 하는 Node들에서 공통의 값을 줄수도 있습니다.
부모노드에서 제거될때 자식노드의 상태에 대해서
기술됩니다. 이는 단지 화면에서만 사라지는 것이 아니라
자식노드가 가지고 있는 액션과 콜백/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가 된다.
이번번 예제는 할배노드에서 부모노드를 삭제할때 자식노드의 액션과 콜백은 어떻게 되느
냐를 묻는 건데요.결론만 먼저 말하자면 모두 삭제 됩니다.
자세한 내용은 cocos2d 내부 소스를 보시면 이해가 빠를겁니다.^^ 결론은 간단한데
그 내부를 설명하려면 몇단계를 거쳐야 하기때문에 일단 여기서는 제외합니다.
ccMacros.CCLOG(LOG_TAG, "Thisscheduler should not be removed");
}
publicvoid 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);
publicvoid tick(float dt) {
ccMacros.CCLOG(LOG_TAG, "Thisscheduler should not be removed");
}
에서 볼수 있듯이 기본본적으로 로그를 확인해야 알수 있다 .
==>Log 사용법은 tick(float dt)에 나와 있듯이 사용하면됩니다.
==>schedule 함수 에서 알수 있듯이 첫번째 파라미터는 콜백함수 두번째 파라미터는
반복적으로 호출되어질 주기를 설정한다.
==>콜랙함수를 String 타임으로 넘기는것을 selector 라고 한다 당장은 이걸 왜
빨간색으로 했는지는 모르겟지만 뒤에 이것에 대한 것이 나온다 . 일단 알고갑시다.
==>unschedule("autoremove"); 에서 볼수 있듯이 스케쥴의 해제는 unschedule(String selector)을 쓴다.
==>특별히 어려운건 없습니다.
return"Scheduler should be paused after 3seconds. See console";
}
}
==>schedule(new UpdateCallback() {
@Override
publicvoid update(float d) {
tick1(d);
}
} , 0.5f);
에서 볼수 있듯이 좀전과는 다르게 selector를 사용하지 않고 UpdateCallback()
인터페이스를 구현 해서 스케쥴하였습니다. 뒤에 0.5f 는 당연히 주기겟죠
좀전에 selector를 기어억하라고 했던것은 이 때문입니다.
==>schedule을 구현하는데 있어서 2가지 방법이 바로 selector 와 UpdateCallback()구현입니다. 잘기억해두세요
return"All scheduled selectors will beunscheduled in 4 seconds. See console";
}
publicvoid tick1(float dt) {
ccMacros.CCLOG(LOG_TAG, "tick1");
}
publicvoid tick2(float dt) {
ccMacros.CCLOG(LOG_TAG, "tick2");
}
publicvoid tick3(float dt) {
ccMacros.CCLOG(LOG_TAG, "tick3");
}
publicvoid tick4(float dt) {
ccMacros.CCLOG(LOG_TAG, "tick4");
}
publicvoid unscheduleAll(float dt) {
unscheduleAllSelectors();
}
}
==> 이번에 하는것은 첫번째 것을 잘 보셨다면 무리 없이 진행 하실수 있을것입니다.
selector를 이용한 스케쥴링입니다.
==> 다만 새롭게 나온것은 unscheduleAllSelectors(); 별거 없습니다.
selector로 등록했으니까 AllSelectors란 접미사가 붙는건 당연합니다.
selector로 등록한 모든 콜백을 삭제하라입니다.
==> 3.3의 살짝 변형인데요 모두 동일하고
3.3은 CCNode의 unscheduleAllSelectors() 함수를 이용했고
3.4는 sharedScheduler를 직접 이용했습니다. ==> 바로 여기서 결정적인 차이가 나는데요 . CCNode의 schedule()함수를사용
하면 해당 CCNode의 스케쥴만 헤제되는데 비해서 3.4처럼 해줘버리면
cocos2d 전체의 스케쥴 걸어놓은것이 다 멈추어 버립니다. 그래서 제목에 Hard가 붙은것이죠
//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";
}
publicvoid removeUpdates(float dt) {
if(getChildren() != null) {
for (CCNodenode : getChildren()) {
node.unscheduleAllSelectors();
}
}
}
}
==>위의 예제는 2가지를 담고 있습니다. 한가지는 자식 노드의 스케쥴방법과 스케쥴의
우선순위 입니다.
==> 잘생각해본다면 우리가 구현하고자 하는 레이어의 어디에서 스케쥴을 정했는지 알수
있습니다. 바로 생성자에서 지정했습니다. 그리고 레이어쪽만 하다 잠시 까먹을 수도
있지만. 레이어도 Scene의 자식 CCNode 입니다. 똑같죠 ㅎㅎㅎㅎ
==> 자그럼 이번에 할것은 스케쥴이 동시에 발생하면 어느것이 먼저 발생할까요? 그거야 먼저 실핼됐던놈이 먼저 시작되는게 원칙이겟죠 ㅎㅎ
return"Update + custom selector at the sametime. Stops in 4s. See console";
}
publicvoid update(float dt) {
String s = String.format("update called:%f", dt);
ccMacros.CCLOG(LOG_TAG, s);
}
publicvoid tick(float dt) {
String s = String.format("custom selector called:%f", dt);
ccMacros.CCLOG(LOG_TAG, s);
}
publicvoid stopSelectors(float dt) {
unscheduleAllSelectors();
}
}
==> 여기에서는 scheduleupdate() 함수와 커스텀 updatecallback 를 썩어 놓았습니다. 동작은 매 프레임마다 update()와 tick() 이 호출됩니다.
이두개는 현제 레이어에 포함되어 있으므로 최종적으로 unscheduleAllSelectors();에 의해서 모두 제거 됩니다.
1. 정의 스프라이트 별거 없습니다 그냥 2D이미지입니다.단지 용어가 익숙하지 않을뿐. 다시 반복하자면 에스. 피. 엘. 아이. 티. 이s p r i t e스프라이트.2D 이미지 간단히 사진이라 그림,글자 그림 이라고 생각하시면 됩니다.
==>cocos2d 를 배우는 이유가 화면에 이미지띄우고 왔다리 갔다리 하기위한거니까
생성방법은 숙지하세요... 사실 숙지고 머고간에 너무 간단해서 그냥 한번만 보면되요 ㅎ
==> 위와 같이 동일하게 파일 이름을 이용하지만 CGRect.make(top,left,bottm,rigth) 를 이용하여 이미지 파일의 특정영역으로 부터 CCSprite 객체를 생성합니다. ==> CGRect 클래스는 간단하게 자바클래스 RectF클래스와 유사하다고 생각해주세요 바로 보실분들은 보세요^^;;
package org.cocos2d.types;
publicclass CGRect {
public CGPoint origin;
public CGSize size;
public CGRect() {
this(0, 0, 0,
0);
}
public CGRect(final CGPoint origin, final CGSize
size) {
1. 라스트 정리
어떻게 하다보니 org.cocos2d.actions.ease 관련 클래스를 모두 정리하였습니다.
막상정리하고 보니 별것도 없고 그냥 그렇네요 그런데 어떤 EaseAction을 쓸것인가
에 대한 고민을 안할수가 없네요 . 어떻게 해야 할까요? 하나하나 정리 테스트 해보면
좋겟지만. 먼가 감도 안오고 흠... 그래서 준비 했습니다.
휘어지는 정도가 한눈에 보이네요 ㅎㅎㅎ 그럼
잘 골라서 쓰세요 ㅎㅎ
==> sin 함수,cos함수를 시뮬레이션화 한 클래스들 입니다.
==> 네이밍만 이 싸인함수라고했지만.
실제로는 CCEaseSineIn /CCEaseSineInOut 이 2개는 코사인 함수를 이용합니다. ==> 단지 MoveAction 만을 위한 클래스는 아니며 CCNode 속성에 있는 모든 값을 대상으로 합니다. ==> (참고 : EaseAction 이란 ?)
2. 클래스 관계도
3.추가된 멤버 변수 / 함수 ==>추가된 멤버 변수는 없습니다. ==> 없습니다. 라고 단호하게 말할까 했지만. 클래스 멤버 변수가 없다는것뿐이지 EaseAction의 핵심 함수 update(오버라이드됨)에 있습니다. 이는 EaseAction의 특성을 구별지을수 있는 핵심 부분이기에 각 클래스별 오버라이딩된 update(float t)를 살펴보겟습니다. ==> EaseAction의 동일한 반복입니다.
==> 클래스 관계도의 특성표는 위에 오버라이딩된 함수공식에 따른것입니다. ==> 바로 여기에서 알수 있듯이 CCEaseAction을 상속해서 여기처럼 update() 부분을 오버라이딩해서 쓴다면 사용자별 CCEaseRateAction을 만들수 있을것 입니다. (솔직히 저거 쓸수 있는 사람은 별로 안되겟죠^^)
4-4.사용법및 적용가능한곳.
public static CCEaseSineIn action(CCIntervalAction action) {
Base class for Easing actions with rate parameters
==> rate 파라미터롤 가속도를 나타냅니다. (시간변위당 속도변위) ==> 가속도 효과를 나타내기 위해서 내부 액션의 가속도를 변경 변경시키기 위한 추상화 클래스가 아닙니다. 기존에는 추상화 해놓고이거는 왜
추상화 안해 놓았는지 .... cocos2d가 아직 완성이 안되었다는걸가요? 흠...
조금더 고민을 해보아야 할듯합니다. ==> 단지 MoveAction 만을 위한 클래스는 아니며 CCNode 속성에 있는 모든 값을 대상으로 합니다. ==> (참고 : EaseAction 이란 ?)
2. 클래스 관계도
3.추가된 멤버 변수 / 함수 ==>추가된 멤버 변수는 이고
/** rate value for the actions */ float rate;
==> 추가된 멤버 함수(추상화 함수 가 아닌 단지 오버라이드 함수 입니다.) ==> 멤버변수가 늘어난것이니만큼 기존의 copy()와 reverse()를 새롭게 정의하는것은 당연합니다.
@Override
public CCEaseRateAction copy() {
return new CCEaseRateAction(other.copy(), rate);
}
@Override
public CCIntervalAction reverse() {
return new CCEaseRateAction(other.reverse(), 1 / rate);
}
4.CCEaseRateAction를 상속하는 클래스들
CCEaseIn.java
CCEaseInOut.java
CCEaseOut.java
==> 기존의 네이밍 규칙과 좀 다르네요 머 제가 한게 아니니까 일단 그려려니 할께요^^;; ==> 위의 클래스 설명을 따로 뺄까생각해보았지만. 좀 비효울적인듯 하여 아래에 추가로 올립니다.
4-1 CCEaseIn/ CCEaseInOut / CCEaseOut 클래스 설명
==>기존의 CCRateAction을 상속하여 지수함수를 시뮬레이션 합니다.
==>CCEaseExponential~~ 류의 클래스와 거의 비슷하게 나오지만 조금 다르네요 쪼끔...
개인적인 생각으로 굳이 이럴필요 있나 싶을정도로 말이죠.
4-2. 클래스 관계도
==> 진짜 보면 볼수록 너무 유사하군요. 왜 이런류의 클래스를 만들어서 사람 귀찮게시리 . 쯧..
4-3. 추가된 멤버변수/함수 ==> 없습니다. 라고 단호하게 말할까 했지만. 클래스 멤버 변수가 없다는것뿐이지 EaseAction의 핵심 함수 update(오버라이드됨)에 있습니다. 이는 EaseAction의 특성을 구별지을수 있는 핵심 부분이기에 각 클래스별 오버라이딩된 update(float t)를 살펴보겟습니다. ==> EaseAction의 동일한 반복입니다.
==> 클래스 관계도의 특성표는 위에 오버라이딩된 함수와 float rate변수 의 공식에 따른것입니다. ==> 바로 여기에서 알수 있듯이 CCEaseRateAction을 상속해서 여기처럼 update() 부분을 오버라이딩해서 쓴다면 사용자별 CCEaseRateAction을 만들수 있을것 입니다. (솔직히 저거 쓸수 있는 사람은 별로 안되겟죠^^)
4-4.사용법및 적용가능한곳.
public static CCEaseIn action(CCIntervalAction action, float rate) {
==>클래스 관계도의 특성표는 위에 오버라이딩된 함수의 공식에 따른것입니다. ==> 바로 여기에서 알수 있듯이 EaseAction을 오버라이딩하고 여기처럼 update() 부분을 오버라이딩해서 쓴다면 사용자별 EaseAction을 만들수 있을것 입니다. (수학책을 방정식 공석을 찾아 한번 해보세요 ㅎㅎㅎ 나중에 저도 도전해볼려고 합니다) ==> 오버라이딩된 함수 내부를 상세하게 설명할까 고민했지만 이건 별의미 없는것 같아서 패스 합니다.
4.사용법및 적용가능한곳.
public static CCEaseExponentialIn action(CCIntervalAction action) {
return new CCEaseExponentialIn(action);
}
public static CCEaseExponentialOut action(CCIntervalAction action) {
return new CCEaseExponentialOut(action);
}
public static CCEaseExponentialOut action(CCIntervalAction action) {
return new CCEaseExponentialOut(action);
}
==> 이처럼 동일합니다. ==> CCNode의 속성을 변경시키는 액션은 어떤것이든지 적용이 가능합니다만. CCSequence 또는 CCSpawn 액션은 자신이 원했던 결과물을 얻을수 있습니다.
These actions alters the time simulating an elastic. Elastic actions will use time values greater than 1 and lower than 0, so the inner action should be prepared to handle this special values.
==> 이 액션은 고무밴드를 시뮬레이션(흉내내는) 액션입니다. Elastic action은 사용되는 시간변수는 1보다 크고 0보다 작습니다. 내부부액션(EaseAction이 멤버변수로 가지고 있는
는 CCIntervalAction 레퍼런스변수) 이 특수한 변수를 다루기 위해서이다. ==> 말 그대로 탄력성이 느껴지는 효과를 나타내기 위해서 내부 액션의 가속도를 변경 변경시키기 위한 추상화 클래스입니다. ==> 단지 MoveAction 만을 위한 클래스는 아니며 CCNode 속성에 있는 모든 값을 대상으로 합니다. ==> (참고 : EaseAction 이란 ?)
2. 클래스 관계도
3.추가된 멤버 변수 / 함수 ==>추가된 멤버 변수는 이고
/** period of the wave in radians. default is 0.3 */ protected float period_;
==> 추가된 멤버 함수(추상화 함수 )
==> 멤버변수가 늘어난것이니만큼 기존의 copy()와 reverse()를 새롭게 정의하는것은
당연합니다.
@Override
public abstract CCEaseAction copy();
@Override
public abstract CCIntervalAction reverse();
4.CCEaseBounce 를 상속하는 클래스들
CCEaseElasticIn.java
CCEaseElasticInOut.java
CCEaseElasticOut.java
==> 위의 클래스 설명을 따로 뺄까생각해보았지만. 좀 비효울적인듯 하여 아래에 추가로 올립니다.
==> 음... 설명이 조금 애한데요 원활한 설명을 위해서 클래스 관계도 를 먼저 보겟습니다
4-2. 클래스 관계도
==> 이제 클래스 설명을 다시 보겟습니다. 애매한 단어가 "어떤 변수는 한번 이상을 트리거하게 됩니다" 이라는 말인데 위에 그림에 보면 이해가 좀더 잘 될것입니다 (여기서 변수라함은 시간변수입니다. update() 에 들어가는 시간값입니다.) ==> 바로 위에 설명은 반복되고 있어 뺄까 고민했지만. 아직은 필요한듯 하여 그냥 두기로 했습니다
==> 솔직히 이게 왜 탄력적인 느낌이 나는지 이해가 잘 안됩니다. 그냥 이런가보다 아~~ 하는
정도죠 ㅎㅎ
4-3. 추가된 멤버변수/함수 ==> 없습니다. 라고 단호라게 말할까 했지만. 클래스 멤버 변수가 없다는것뿐이지 EaseAction의 핵심 함수 update(오버라이드됨)에 있습니다. 이는 EaseAction의 특성을 구별지을수 있는 핵심 부분이기에 각 클래스별 오버라이딩된 update(float t)를 살펴보겟습니다. ==> EaseAction의 동일한 반복입니다.
==> 클래스 관계도의 특성표는 위에 오버라이딩된 함수와 period_변수 의 공식에 따른것입니다. ==> 바로 여기에서 알수 있듯이 CCEaseElastic 을 오버라이딩하고 여기처럼 update() 부분을 오버라이딩해서 쓴다면 사용자별 CCEaseElastic 을 만들수 있을것 입니다.
(솔직히 저거 쓸수 있는 사람은 별로 안되겟죠^^)
4-4.사용법및 적용가능한곳.
public static CCEaseElasticIn action(CCIntervalAction action) {
return new CCEaseElasticIn(action, 0.3f);
}
public static CCEaseElasticIn action(CCIntervalAction action, float period) {
==> 보시다 싶이 지금까지와는 달리 period 값을 추가로 줄수 있습니다. 실다면
디폴트로 0.3이 할당 됩니다. ==> CCNode의 속성을 변경시키는 액션은 어떤것이든지 적용이 가능합니다만. CCSequence 또는 CCSpawn 액션은 자신이 원했던 결과물을 얻을수 없을지도 모릅니다.
==> 말 그대로 공이 통통 튕기듯한 효과를 나타내기 위해서 내부 액션의 가속도를 변경
변경시키기 위한 추상화 클래스입니다.
==> 단기 MoveAction 만을 위한 클래스는 아니며 CCNode 속성에 있는 모든 값을
대상으로 합니다.
==>(참고 : EaseAction 이란 ?)
2. 클래스 관계도
==> CCAction 에서부터 많이 흘러 왔네요 어디까지 흘러갈지 저도 궁금합니다. ㅎㅎㅎ
3.추가된 멤버 변수 / 함수 ==>추가된 멤버 변수는 없습니다. ==>추가된 멤버 함수는 있습니다.
protected float bounceTime(float t) {
if (t < 1 / 2.75) {
return 7.5625f * t * t;
} else if (t < 2 / 2.75) {
t -= 1.5f / 2.75f;
return 7.5625f * t * t + 0.75f;
} else if (t < 2.5 / 2.75) {
t -= 2.25f / 2.75f;
return 7.5625f * t * t + 0.9375f;
}
t -= 2.625f / 2.75f;
return 7.5625f * t * t + 0.984375f;
}
==> 바운스 효과를 나타내기 위한 수학공식인듯합니다.
7.5625 / 2.75 / 2.25 / 0.984375
==> 이거 확인해봏수 있으면 좋지만 수학은 젬뱅이라. ㄷㄷ 어디 참고할만 거 없나요?
4.CCEaseBounce 를 상속하는 클래스들
CCEaseBounceIn.java
CCEaseBounceInOut.java
CCEaseBounceOut.java
==> 위의 클래스 설명을 따로 뺄까생각해보았지만.
좀 비효울적인듯 하여 아래에 추가로 올립니다.
4-1 CCEaseBounceIn /CCEaseBounceInOut / CCEaseBounceOut 클래스 설명
==> 음... 설명이 조금 애한데요 원활한 설명을 위해서 클래스 관계도 를 먼저 보겟습니다
4-2. 클래스 관계도
==> 이제 클래스 설명을 다시 보겟습니다. 애매한 단어가 "어떤 변수는 한번 이상을 트리거하게 됩니다" 이라는 말인데 위에 그림에 보면 이해가 좀더 잘 될것입니다 (여기서 변수라함은 시간변수입니다. update() 에 들어가는 시간값입니다.)
==> 바로 위에 설명은 반복되고 있어 뺄까 고민했지만. 아직은 필요한듯 하여 그냥 두기로
했습니다
4-3. 추가된 멤버변수/함수 ==> 없습니다. 라고 단호라게 말할까 했지만. 클래스 멤버 변수가 없다는것뿐이지 EaseAction의 핵심 함수 update(오버라이드됨)에 중요한 지역변수가 있습니다. 이는 EaseAction의 특성을 구별지을수 있는 핵심 부분이기에 각 클래스별 오버라이딩된 update(float t)를 살펴보겟습니다. ==> EaseAction의 동일한 반복입니다.
CCEaseBounceIn public void update(float t) {
float newT = 1 - bounceTime(1 - t);
other.update(newT);
}
CCEaseBounceInOut
@Override
public void update(float t) {
float newT = 0;
if (t < 0.5) {
t = t * 2;
newT = (1 - bounceTime(1 - t)) * 0.5f;
} else
newT = bounceTime(t * 2 - 1) * 0.5f + 0.5f;
other.update(newT);
}
CCEaseBounceOut
@Override
public void update(float t) {
float newT = bounceTime(t);
other.update(newT);
}
==> 클래스 관계도의 특성표는 위에 오버라이딩된 함수와 bounceTime() 의 공식에
따른것입니다. ==> 바로 여기에서 알수 있듯이 EaseAction을 오버라이딩하고 여기처럼 update() 부분을 오버라이딩해서 쓴다면 사용자별 EaseAction을 만들수 있을것 입니다. (수학책을 방정식 공석을 찾아 한번 해보세요 ㅎㅎㅎ 나중에 저도 도전해볼려고 합니다)
4-4.사용법및 적용가능한곳.
public static CCEaseBounceIn action(CCIntervalAction action) {
return new CCEaseBounceIn(action);
}
public static CCEaseBounceInOut action(CCIntervalAction action) {
return new CCEaseBounceInOut(action);
}
public static CCEaseBounceOut action(CCIntervalAction action) {
return new CCEaseBounceOut(action);
}
==> 이처럼 동일합니다. ==> CCNode의 속성을 변경시키는 액션은 어떤것이든지 적용이 가능합니다만. CCSequence 또는 CCSpawn 액션은 자신이 원했던 결과물을 얻을수 없을지도 모릅니다.
==> 음... 설명이 조금 애한데요 원활한 설명을 위해서 클래스 관계도 를 먼저 보겟습니다
2. 클래스 관계도 ==> 이제 클래스 설명을 다시 보겟습니다. 애매한 단어가 "어떤 변수는 한번 이상을 트리거하게 됩니다" 이라는 말인데 위에 그림에 보면 이해가 좀더 잘 될것입니다 (여기서 변수라함은 시간변수입니다. update() 에 들어가는 시간값입니다.)
3. 추가된 멤버변수/함수 ==> 없습니다. 라고 단호라게 말할까 했지만. 클래스 멤버 변수가 없다는것뿐이지 EaseAction의 핵심 함수 update(오버라이드됨)에 중요한 지역변수가 있습니다. 이는 EaseAction의 특성을 구별지을수 있는 핵심 부분이기에 각 클래스별 오버라이딩된 update(float t)를 살펴보겟습니다.
CCEaseBackIn 클래스
@Override
public void update(float t) {
float overshoot = 1.70158f;
other.update(t * t * ((overshoot + 1) * t - overshoot));
}
CCEaseBackInOut
@Override
public void update(float t) {
float overshoot = 1.70158f * 1.525f;
t = t * 2;
if (t < 1) {
other.update((t * t * ((overshoot + 1) * t - overshoot)) / 2);
} else {
t = t - 2;
other.update((t * t * ((overshoot + 1) * t + overshoot)) / 2 + 1);
}
}
CCEaseBackOut
@Override
public void update(float t) {
float overshoot = 1.70158f;
t = t - 1;
other.update(t * t * ((overshoot + 1) * t + overshoot) + 1);
}
==>클래스 관계도의 특성표는 위에 오버라이딩된 함수의 공식에 따른것입니다. ==> 바로 여기에서 알수 있듯이 EaseAction을 오버라이딩하고 여기처럼 update() 부분을 오버라이딩해서 쓴다면 사용자별 EaseAction을 만들수 있을것 입니다. (수학책을 방정식 공석을 찾아 한번 해보세요 ㅎㅎㅎ 나중에 저도 도전해볼려고 합니다) ==> 오버라이딩된 함수 내부를 상세하게 설명할까 고민했지만 이건 별의미 없는것 같아서 패스 합니다.
4.사용법및 적용가능한곳.
public static CCEaseBackIn action(CCIntervalAction action) {
return new CCEaseBackIn(action);
}
public static CCEaseBackInOut action(CCIntervalAction action) {
return new CCEaseBackInOut(action);
}
public static CCEaseBackOut action(CCIntervalAction action) {
return new CCEaseBackOut(action);
}
==> 이처럼 동일합니다. ==> CCNode의 속성을 변경시키는 액션은 어떤것이든지 적용이 가능합니다만. CCSequence 또는 CCSpawn 액션은 자신이 원했던 결과물을 얻을수 없을지도 모릅니다.
public static final float M_PI_X_2 = (float) (Math.PI * 2.0f);
protected CCIntervalAction other;
==>첫번째 멤버변수 M_PI_X_2 가 있는 것을 보니 액션을 사용할때 수학적인 요소를 사용하려
나 봅니다.
==>두번째 멤버변수 other CCIntervalAction을 멤버변수로 하나더 가지고 있습니다. 이걸 왜
가지고 있을까요? 위에서 설명한바와 같이 액션의 기간을 수정하기위함입니다. (기간 수정
이란 말은 액션의 속도를 바꾼다는 말입니다.)
위에 그림에서 보다 시피 실질적으로 쓰이는 부분은 CCOrbitCamera 입니다.
즉 카메라 관련 Action을 하려면 CCOrbitCamera 을 쓰세요
그럼 본격적으로 CCOrbitCamera 을 알아보고자 합니다.
일단 클래스 설명부터
/** CCOrbitCamera action
* Orbits the camera around the center of the screen using spherical coordinates
*/
구면자표계를 사용하여 화면가운데를 이동하는 카메라의 궤도이다? 정확안 해석은 아닌데
의미는 대충 알것네요.
(구면좌표계란 ? 중심에서의 거리, 방위각, 위도를 이용하여 3차원 위치를 표시하는 방법. 구면에서 나타나는 현상이 나 구면 형태로 전파되는 현상을 기술하기에 편리함.(출처 네이버 지식사전))
멤버변수로
float radius; 거리
float deltaRadius; 목표 거리
float angleZ; 방위각
float deltaAngleZ; 목표방위각
float deltaAngleX; 목표위도
float angleX; 위도 있습니다. 다른멤버 변수가 있기는 하지만. 이는 위에서 설정한 값을 라디언값으로 바꾸어 부분이므로 우리가 참고 할 필요는 없습니다.
생성자는 아래와 같습니다.
elapsed는 경과된,., 이니까 경과된시간. ...아~~~
CCFinteTimeAction 에 일정 시간이 있으니까
그 일정 시간과 비교할 다른 참고 변수를 가진다는거죠
그리고 멤버 함수를 보니 아니나 다를까 .
CCFinteTimeAction에서 선언한. duration과
CCIntervelAction 에서 선언한 elapsed을 비교하는 구문이 있었습니다.
바로 요놈 입니다.
public boolean isDone() {
return (elapsed >= duration);
}
참이면 stop가 호출 되겟고 아니면 step이 호출되겟죠ㅎ
여기서 한가지 의문점은 이럴꺼면 왜 궅이 CCFinteTimeAction 가 CCIntervelAction 을 분리시켰냐에 대한 의문이 들더군요, 단지 변수 하나 추가하고 함수 오버라이딩 할꺼면 한번에 다하면 되지 왜 궅이 이렇게 귀찮게 해야 하나 라는거죠
이렇게 클래스 분리함으로써 얻을수 있는 장점은 무엇일까요? 이를 설명하기 위해서는CCFinteTimeAction 을 상속한 또 다른 클래스 CCInstantAction을 알면 해결될수 있을것이라 생각합니다.
그럼 CCInstantAction 을 살펴보면
/** Instant actions are immediate actions. They don't have a duration like
the CCIntervalAction actions.
*/
즉시 실행되는 액션이고 CCIntervalAction처럼 duration을 가지지 않는다.
추가된 멤버변수도 없습니다.
오히려 생성자에서
protected CCInstantAction() {
super(0);
}
@Override
public boolean isDone() {
return true;
}
@Override
public void step(float dt) {
update(1.0f);
}
@Override
public void update(float t) {
// ignore
}
자신의 부모클래스의 멤버변수인 duration의 값을 0로 줘버리더군요 이말은 실행하는 즉시 결과가 화면에 도출된다는것을 의미합니다. 함수 오버라이딩 해놓은걸보면.
step 이 바로 1로써 업데이트 되어 버립니다.
음. 이렇게 살펴 보았지만 위의 의문점은 해결이 안되는군요 .
이럴꺼 전부 CCFinteTimeAction 과 CCIntervelAction 과 CCInstantAction 을 하나의 클래스로 만들어서 멤버 변수의 값만 바꿔주면 되지 않나? 라는 생각이 들더군요 .
의문점을 해결하고자 했는데 오히여 더 복잡해지네요 . . ㄷㄷㄷ
이에 대해서 좀더 알아보고자 한다면. 다른 클래스들을 살펴보아야겟네요. 파고 들어갈수록 점점 이상해지네요 . ㅋㅋㅋ 일단 의문점은 남겨두고 갈께요. Action에 대해서 어느 정도 정리가 되면 이 의문점에 대해서 생각해보겟습니다.
혹시 까먹을지도 모르니 아래와 같이 체크해놓고 ㅎㅎ
Q.이럴꺼 전부 CCFinteTimeAction 과 CCIntervelAction 과 CCInstantAction 을 하나의 클래스로 만들어서 멤버 변수의 값만 바꿔주면 되지 않나?
그럼 멤버 변수가 머 볼거 없으니 멤버 함수를 확인해 보니.
Action이 한프레임동안 하는 일들을 알수 있었습니다.
바로 아래와 같은데요.
//! called before the action start. It will also set the target.
public void start(CCNode aTarget) {
originalTarget = target = aTarget;
}
//! called after the action has finished. It will set the 'target' to nil.
//! IMPORTANT: You should never call "[action stop]" manually. Instead, use: "[target stopAction:action];"
public void stop() {
// target = null;
}
//! return YES if the action has finished
public boolean isDone() {
return true;
}
//! called every frame with it's delta time. DON'T override unless you know what you are doing.
public abstract void step(float dt);
//! called once per frame. time a value between 0 and 1
//! For example:
//! * 0 means that the action just started
//! * 0.5 means that the action is in the middle
//! * 1 means that the action is over
public abstract void update(float time);
멤버 함수별 상세한 설명은 안에 잘되어 있으니
하나의 프레임동안 호출되는 함수들의 순서를 정리하겟습니다.
바로 이렇습니다. 여기서 유추할수 있는건 이런 액션멤버변수들을 호출하는 무언가가 있다라는것이죠 일단 지금은 그정도로만 알고 있죠 무언가가 액션의 멤버 변수를 호출한다.그것도 체계적으로 말이죠