2015.08.23 22:46


1. Node

cocos2d-x의 기본 단위

거의 모든 객체들은 이 Node클래스를 상속받는다. 이것만 잘 알아도 cocos2d-x의 많은 부분을 알수 있다.

http://www.cocos2d-x.org/reference/native-cpp/V3.0alpha0/d3/d82/classcocos2d_1_1_node.html

Node의 멤버들..

-position : 위치 값,

-scale : 크기 배율값,

-rotation : 회전 각도,

-anchor point : 앵커 포인터(위치값의 기준 점을 설정 0~1까지 float),

-size : width, height,

-visible : 보이는지 여부,

-z-order : 출력시 위에 보이느냐 아래 보이느냐를 결정하는 수치

node->setPosition(Point(0, 0));
//대부분의 속성값은 get / set으로 사용가능

부모자식관계

Node의 가장 중요한 특징은 부모자식관계라고 생각한다. 클래스 상속과는 별개의 영역이며, 햇갈려서는 안된다.

자식은 부모의 영역안에서 상대적인 좌표로 이동, 회전, 스케일된다. 예를 들어 부모노드가 100, 100 좌표에 위치한다면, 그 자식인 노드의 좌표값이 0, 0 이라도 부모노드의 상대적 좌표값이 적용되어 실제로 전체화면에서는 100, 100 좌표에 있는 것 처럼 보인다.

반대로 여러 자식들을 가지고 있는 부모노드의 위치 스케일 등을 변경하면 그 안에 들어있는 모든 자식노드들의 값이 한꺼번에 변경된다. 이 때문에 부모 노드는 자식 노드를 담는 컨테이너로 사용되기도 한다.

parent->setPosition(Point(100, 100)); // 부모를 100, 100위치에 놓는다.
auto child = Node::create(); //자식을 만든다.
child->setPosition(Point(0,0));//자식을 0,0에 놓는다.
parent->addChild(child) //자식이 100, 100자리에 그려진걸 보고서 당황하지 않는다.

스마트 포인터

Node를 상속받는 모든 클래스들은 CREATE_FUNC(ClassName)으로 등록하면, ClassName::create()하는 것만으로 자동으로 메모리를 할당하고 알아서 해제가 된다.

새로운 인스턴스 생성할때, virtual bool init()이라는 함수를 자동으로 호출하므로 반드시 init함수의 형태를 구현해두어야한다.

기본적으로 레퍼런스 카운트 방식을 사용한다. addChild(node)하면 알아서 카운트가 1이 증가하고, removeChild(node)하면 카운트가 1줄어든다. 카운트가 0이되면 사라진다.

만약 할당한 메모리를 유지하고 싶다면, 인스턴스 객체에 node.retain()을 걸어주면 수동으로 카운트가 1 증가한다. 반대로 node.release()를 걸어주면 수동으로 카운트가 1 줄어든다. 하지만 메모리 릭이 발생하지 않도록 주의해서 관리해야한다.

스케쥴

http://injakaun.tistory.com/102

노드를 상속받은 클래스들은 스케쥴을 통해 게임 루프를 처리해주는 스케쥴러에 특정 함수를 등록할 수 있다. 스케쥴로 등록한 함수는 게임 루프시마다 호출된다. 주로 각 객체의 update함수들이 등록되어 루프할때마다 호출된다.

schedule( schedule_selector( GameLayer::update ) , 0.1f );
//schedule_selector의 인자로 함수포인터를 넘겨주는데, 반드시 앞에 어떤 클래스의 함수인지를 써줘야한다.
//그리고 뒤에 이 함수가 실행되는 딜레이를 적어준다.
scheduleUpdate(); //귀찮으면 이걸 쓴다. 대신 update함수는 노드에서 제공하는 형식을 맞춰줘야한다.

무작정 스케쥴업데이트를 사용하면 업데이트 순서가 꼬일 수 있으니 주의하자. 자식노드의 업데이트를 부모노드의 업데이트에 몰아서 한큐에 처리하는 방식으로 꼬임 문제를 해결하였다. sheduleUpdateWithPriority를 사용하는 것도 방법이 될 수 있을 거라 생각한다.

unschedule을 통해서 스케쥴러에서 제외시킬 수 있고, pause와 resume을 통해 잠시 멈췄다가 다시 수행하게 할 수 있다. scheduleOnce를 잘쓰면 괜히 여러번 호출할 필요없이 한번만 불러오게 할 수도 있다.

*removeChild이나 changeScene을 하면 그 안에 있던 객체는 retain을 해서 남아있더라도 그 객체에서 shedule된 함수들이 스케쥴러에서 제외된다. 제외된 함수들은 다시 스케쥴러에 넣어주지 않는한 루프에 호출되지 않는다.

2.Node의 상속자들

cocos2d::Scene / cocos2d::Layer / cocos2d::Sprite

Director

디렉터는 Node의 상속자는 아니지만 다른 상속자들과 밀접한 관련이 있기에 미리 언급하고 넘어간다. 디렉터는 cocos2d-x 내부에 있는 싱글톤 클래스로 화면을 관리하는 역할을 담당한다. 주로 화면에 출력할 Scene을 선택하고 전환하는 역할로 사용되었다. 추가로 다양한 씬 전환기법도 제공한다.

http://injakaun.tistory.com/98

Director::runWithScene(menuScene); //일단 디렉터로 씬하나 띄워야 뭐가 실행된다.
Director::getInstance()->replaceScene(gameScene); //적당히 조건에 맞게 씬을 변경한다.
//replaceScene을 하면 기존에 있던 씬은 제거(refCount--)된다. 추가로 업데이트들도 스케쥴에서 제외되므로 주의한다.

Scene

씬은 cocos2d-x에서 가장 기본이 되는 화면이다. Node의 상속자들의 부모자식관계망에서 제일 꼭대기에 위치한다. Scene에는 직접 스프라이트같은걸 붙이지는 않는다. 세부적인 화면 형태는 Layer에서 결정하고, 그런 Layer들을 모아서 한번에 출력하는 컨테이너로 Scene을 사용하는게 편리하다.

Layer

Layer도 Scene이랑 크게 다를것은 없으나 Scene과는 달리 여러개가 동시에 한 화면에 올릴 수 있기 때문에 각 분류에 따라 만들어지는 경향이 있다. 우리 프로젝트에서도 UI, Game, Background Layer들로 나누어서 각각 자신의 처리를 할 수 있게 하였다. 그리고 각 레이어들의 z축 값을 다르게 줘서 특정 레이어를 위에 특정 레이어를 아래 배치할 수도 있다.

auto gameLayer = Layer::create(); //게임 레이어를 만들어줍니다.
auto uiLayer = Layer::create(); //UI레이어도 만들어요
auto gameScene = Scene::create(); //게임이 돌아가느 화면인 게임씬을 만들고
gameScene->addChild(gameLayer, 1); //게임 레이어를 게임씬에 붙입니다. z축 값을 1로줘서 
gameScene->addChild(uiLayer, 2); //z축 값을 2 로 줘서 들어간 ui레이어는 항상 게임레이어보다 위에 출력됩니다.
Director::runWithScene(gameScene); //이걸 디렉터한테 실행시킵니다.

Sprite

실제 이미지가 올라가는 대부분의 노드가 Sprite이다. Sprite도 다른 Sprite를 자식노드로 가질 수 있기 때문에, 플레이어스프라이트에 장비스프라이트를 자식 노드로 붙여 계속 플레이어를 따라다니는 것처럼 만들어 줄 수 있다.

그리고 스프라이트는 여러장의 이미지들을 계속 변경하는 에니메이션을 추가하여 실제 움직이는 객체처럼 만들어 줄 수도 있다.

신고


Posted by injunech