2023년 6월부터 액트플래시가 게임 컨텐츠를 대폭 강화한 V3로 버전업 되었습니다.
신규 전투기 2종 추가.
100개 레벨에 도전하는 캠페인 모드, 3종류의 새로운 보스에게 도전하는 퀘스트 모드 추가.
기타 각종 편의기능 추가/개선.
자세한 내용은 [액트플래시] 버전 3 런칭! 에서 확인하실 수 있습니다.
2023년 6월부터 액트플래시가 게임 컨텐츠를 대폭 강화한 V3로 버전업 되었습니다.
신규 전투기 2종 추가.
100개 레벨에 도전하는 캠페인 모드, 3종류의 새로운 보스에게 도전하는 퀘스트 모드 추가.
기타 각종 편의기능 추가/개선.
자세한 내용은 [액트플래시] 버전 3 런칭! 에서 확인하실 수 있습니다.
※네이버 cocos사용자모임 카페에서
폰빌드는, 다른 서비스 모듈(광고라던가 인앱이라던가)을 붙이지 않는 선이라면 있는 그대로 써도 문제 없습니다. (주:현재 구글플레이스토어 기준으로는 target api level 33 이상을 의무화하고 있는데, 이것에 맞추려면 꽤 많은 수정이 필요합니다. 여기서는 간단하게 폰에만 올려보기 위해 target api level 31에 맞추고 진행했습니다)
이번에 주목할 것은, 주사율 120Hz를 지원하는 폰에서 cocos2d-x로 만들어진 게임이 터보부스트가 걸리는 문제입니다.
간단히 말해서 게임이 엄청 빨라집니다.
타이머 딜레이를 사용하니까 원칙적으로는 문제가 없어야 하는데 (그래서 액션을 사용하는 움직임들은 제대로 돌아가는 것 같은데)
뭐가 문제인지 스케줄러를 쓰는 경우 fps로 치면 멋대로 90~120fps 씩 나와버리는건데요,
해결방법은 위 스샷에 나와있는 것처럼 애니메이션 인터벌의 1.0f / 60을 1.0f / 59.94f 정도로 바꿔주는 겁니다. (이것도 최근에 일부 폰에서는 문제가 있다는 얘기가 있는데, 좀 더 구체적인 케이스를 확인 못해서 일단 그런게 있다는 정도로만..)
제 눈으로 직접 본 건 이번이 처음이라 이제야 제대로 문제를 이해했네요.
키보드 이벤트
EventListenerKeyboard로 생성하며,
onKeyPressed와 onKeyReleased를 오버라이딩 해 줍니다.
둘 중 하나만 해도 되며, onTouchBegan처럼 return true/false를 해 줄 필요는 없습니다.
키 입력으로 게임을 조작하고 싶으면, 키를 누르고 있는 상태를 읽어올 수 없기 때문에 오버라이드 함수 내에서는 상태변수의 값만 변환시키고 스케줄이나 update 함수 내에서 처리하는 방법을 써야 합니다.
몇 가지 트윈(액션)에 대한 tmi
3.xx 일부 버전에서는 RepeatForever는 Sequence를 실행 가능하지만 Repeat는 불가능했던 적이 있습니다.
FadeOut은 FadeTo::create([duration], 0)과
FadeIn은 FadeTo::create([duration], 255)와 같습니다.
Show, Hide : visible을 on/off하는 트윈입니다. (Show=setVisible(true), Hide=setVisible(false))
BezierTo, BezierBy : 4개의 점을 받아 베지어 곡선으로 움직이게 하는 트윈입니다.
좌표값을 받아낼 수는 없고, 액션으로만 동작합니다.
RemoveSelf : 자신을 삭제하는 트윈입니다.
Ease 트윈의 rate값
EaseIn, Out 액션에 들어가는 rate는 가속 비중을 정합니다. 1보다 클 때와 0<rate<1일 때의 동작이 다릅니다.
EaseIn : 1보다 클 때는, 클수록 느린 상태의 시간이 길어지고, 가속이 늦어집니다. 0<rate<1이면 rate가 작을수록 가속이 빨라지고 클수록 느려집니다.
EaseOut : 1보다 크면, 클수록 가속이 빨라지고 느려지는 구간에 늦게 진입합니다. 0<rate<1이면 rate가 작을수록 느린 상태의 시간이 깁니다.
EaseInOut의 경우, rate>1일 경우 duration의 1/2에 가까워질수록 빨라지고 빠른 상태의 시간이 짧아집니다.
솔직히 말로 설명해도 잘 느낌이 안 오기 때문에 실행해 보고 맘에 드는 움직임을 찾아야 합니다
그때문에 단순한 가속도 움직임을 제외하면 잘 안씁니다..
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에는 위 월드 좌표를 인수로 대입해주면 잘 얻어집니다.
왜 2D 게임엔진으로 3D 게임 만들려고 삽질을 합니까? 예 뭐 3D 게임 만드는데 좋은 엔진은 아닙니다. 셰이더도 부실하고 물리엔진 쓰기도 까다롭고. 요즘은 외부업체 SDK 인트하기도 점점 힘들어지고.. 그래도 기왕 해 본 거, 여기까지 왔으...