2023년 11월 25일 토요일

[cocos2d-x] 2d 게임엔진으로 플래피버드 클론 게임 만들기 (오브젝트 레이어, 콜라이딩, 월드 좌표계)

 


1. 타일맵의 오브젝트 레이어

​

어떤 게임은 보면, 타일맵일텐데 화면에 나열된 아이템은 위치나 크기가 제각각인 경우가 있습니다.

타일의 규격을 벗어난 위치와 크기를 가지는 아이템들.

이번 챕터는 그런 내용을 구현해주는 역할을 합니다.

​

오브젝트 레이어는 눈에 보이지 않는 정보를 담고 있습니다.

여기 담긴 정보를 TMX맵 api로 받아오면 ValueVector타입으로 받아집니다. 각각은 ValueMap으로 파싱할 수 있습니다.

​

ValueMap의 내용은, 직접 .tmx 파일을 텍스트 에디터로 열어보면 알 수 있습니다.



통상의 맵 데이타는 암호화/압축되어 있지만 오브젝트 레이어 정보는 보입니다.

(그러므로, 중요한 정보는 오브젝트 레이어에 놓지 않거나, 혹은 맵 데이타 자체에 보안을 걸 필요가 있습니다. 이거만으로 몇 챕터는 나오니까 간략하게 단서만 남기자면, 다운로드 또는 암호가 걸린 압축파일을 씁니다)

​

원래는 이 정보를 바탕으로 물리엔진의 콜라이더를 생성하는 목적으로 만들어졌습니다.

경사로라라던가 여러가지 복잡 다양한 지형을 구현할 수 있습니다만,

여기서는 단순히 좌표정보만 떼다가 아이템을 생성하기 위한 정보로 썼습니다.

​

그런데 이렇게 하면 아이템을 배치하기가 너무 힘들지 않아요?

일정 높이와 간격으로 자연스럽게 배열된 아이템은 어떻게 구현하면 좋을까요.

​

기존 타일 방식으로 된 아이템 레이어와 오브젝트 레이어를 참조한 아이템 생성을 병용하면 됩니다.

​

또, 아이템 레이어에서도 아이템을 타일로 그대로 구현하는게 아니라 타일은 아이템 생성 정보로만 참조하고,

별도의 아아이템 스프라이트를 추가 생성해 add하는 방법을 쓸 수 있습니다.

이 방법은 까까런에서 사용하고 있으니까 그쪽도 참고해 주세요.

​

p.s. 레이어의 visible을 false해도 해당 레이어의 타일 GID등을 읽어올 수 있습니다. 보이지 않을 뿐.

​



2. cocos2d-x의 단순 콜라이딩(충돌 체크)

​

getBoundingBox() api는 해당 스프라이트가 화면에서 차지하고 있는 영역을 사각형(Rect)으로 얻어오는데

보통 물리엔진을 사용하지 않고, 스프라이트끼리의 충돌을 처리할 때 사용됩니다.

​

단, 이때 텍스처에 공백이 있을 경우에는 공백을 포함한 영역을,

스프라이트가 회전해서 대각선 상태일 경우에는 그걸 모두 포함하는 영역을 받아오기 때문에

보통 보이는 스프라이트보다 큰 사각형이 얻어집니다.

​

그때문에 보통 바운딩박스끼리의 충돌을 사용하지 않고,

한쪽만 바운딩박스를 쓰고 상대는 점 좌표나 원형 영역 내에 겹치는지 여부를 보게 됩니다.

​

Rect끼리의 겹침 체크 : intersectsRect

Rect와 점 좌표의 겹침 체크 : containsPoint

Rect와 원의 겹침 체크 : intersectsCircle

(intersectsCircle의 경우, 인수로 대상의 좌표와 반지름을 줍니다)




3. cocos2d-x에서 좌표계 변환

​

우리가 다루는 노드의 좌표는 모두 부모 노드에 대한 상대 좌표(노드 좌표)입니다.

이때 getBoundingBox로 얻어지는 Rect의 좌표(origin)도 마찬가지로 상대 좌표입니다.

​

이 게임의 경우 마녀와 하트가 각각 다른 부모 위에 올라가 있으므로 제대로 충돌체크를 하려면 같은 좌표계(월드 좌표)로 변환해줘야 합니다.

​

이때 쓰는 것이 convertToNodeSpace, convertToWorldSpace인데,

문제는 인수로 주는게 노드가 아니라 Vec2 값이기 때문에, 제대로 된 Vec2 값을 주지 않으면 엉뚱한 값을 얻게 됩니다.

이 점이 convertToNodeSpace, convertToWorldSpace를 쓰기 어렵게 하는 원인입니다.

​

그래도 외워?서 쓸만한 것이라면, A노드의 월드 좌표를 얻으려면

Vec2 a_worldPos = A-〉getParent()-〉convertWorldSpace(A-〉getPosition());

같은 식으로, 부모를 기준으로 얻어오면 됩니다. 너무 부모자식 관계가 복잡하면 안 될 수도 있는데, 보통은 됩니다.

​

그리고 convertToNodeSpace에는 위 월드 좌표를 인수로 대입해주면 잘 얻어집니다.

댓글 없음:

댓글 쓰기

[cocos2d-x] 2D 엔진으로 만드는 3D 슈팅게임

왜 2D 게임엔진으로 3D 게임 만들려고 삽질을 합니까?   예 뭐 3D 게임 만드는데 좋은 엔진은 아닙니다. 셰이더도 부실하고 물리엔진 쓰기도 까다롭고. 요즘은 외부업체 SDK 인트하기도 점점 힘들어지고.. ​ 그래도 기왕 해 본 거, 여기까지 왔으...