8월, 2012의 게시물 표시

setDesignResolutionSize 사용시 CCListView와 CCScrollView 버그 해결

이미지
지난 포스팅에서 cocos2d-x 플랫폼별 해상도와 리소스 관련된 내용을 다뤘는데요, 이것과 관련한 버그가 존재하네요.
eglView.setFrameSize(800, 480); eglView.setDesignResolutionSize(480, 320); 일단 제 폰이 800 x 480이라 2배 뻥튀기 하기위해 위와 같이 설정했구요 아래 스샷을 보시죠.

< 비정상 >


< 정상 >


어떠신가요? 스샷만 보더라도 뭔가.. 잘 못 되었다라는 것을 알수 있겠죠? 저와 같은 문제에 빠진 분들이 있더군요. 대충 소스를 보니 setDesignResolutionSize를 통해 CCEGLView의 ScreenScaleFactor는 1.0이 아닌 값으로 변경이 되어지는데 반해 CCDirector에 있는 ContentScaleFactor은 1.0 그대로 여서 아래의 소스에서 문제가 발생합니다.


void CCListView::visit(void) { if (!m_pListViewParent) { CCRect rectSelf; float factor = CC_CONTENT_SCALE_FACTOR(); rectSelf.origin = convertToWorldSpace(CCPoint(0,0)); rectSelf.origin.x *= factor; rectSelf.origin.y *= factor; rectSelf.size = this->getContentSize(); rectSelf.size.width *= factor; rectSelf.size.height *= factor; glScissor((GLsizei)rectSelf.origin.x, (GLsizei)rectSelf.origin.y, (GLsizei)rectSelf.size.width , (GLsizei)rectSelf.size.height); g…

cocos2d-x 플랫폼별 해상도와 리소스 관련 정리

이미지
이번 포스팅에서는 cocos2d-x 기반으로 게임 개발할 때 이슈 내용인 해상도별 그래픽 리소스 관련 된 것을 정리해볼까 합니다. 회사나 1인 개발자들 또는 인디 팀에 따라 그래픽 리소스 개발 기준도 다를텐데요, 일단 아이폰 3gs가 지원하는 480 x 320과 레티나 디스플레이용인 960 x 480 2개의 리소스가 있다는 전제로 진행합니다.
여담이지만 일반 PC게임 만들때는 하나의 결정된 해상도의 리소스를 가지고 모든 해상도를 커버하겠지만, 아직은 하드웨어적인 발전 가능성이 큰 스마트 기기인 만큼 최적화를 위해서 지원 해상도별로 리소스 제작하는게 어쩔 수 없는 부분인 듯 싶네요.
플랫폼별 정리에 앞서 cocos2d-x에서 해상도와 리소스 관련 된 소스 부분들을 먼저 알아보겠습니다. 참고로 일단은 win32기반으로 설명을 진행하고, 나머지 android나 ios기반은 소스부분이 살짝 다를 수 있는데 이건은 따로 간략히 추가하는 식으로 진행하겠습니다.
먼저 제일 첫 부분인 main.cpp에 있는 부분입니다.
CCEGLView& eglView = CCEGLView::sharedOpenGLView(); eglView.setFrameSize(480, 320); // set the design resolution screen size, if you want to use Design Resoulution scaled to current screen, please uncomment next line.//eglView.setDesignResolutionSize(480, 320); 해상도와 관련된 초기화가 진행되는 부분입니다. setFrameSize는 윈도우 사이즈를 결정하는데 쓰입니다. setDisignResolutionSize는 내부적으로 (윈도우 사이즈 / 디자인 사이즈)를 계산해서 ScreenScaleFactor를 설정하게 됩니다. 그리고 DesignResolutionSize에 Factor를 적용해서 뷰포트 사이즈가 산출 됩니다. 즉, 아래와 같습니다. Fr…

cocos2d-x android PREBUILT_STATIC_LIBRARY 만들어서 작업하기

이미지
이전 포스팅에서 cocos2d-x에 static lib를 만들어서 사용하는 것을 정리했었는데요, 만들 lib를 배포용으로 하기에는 뭔가 반쪽짜리 내용이었습니다. 왜냐면 각 게임마다 static lib로 만든 framework 원본 폴더를 필요로 하기 때문이죠. 마치 win32 플젝 진행할 때 하나의 솔루션에 필요 lib의 프로젝트까지 읽어다가 종속성 포함시켜 개발하는 것 처럼요. 이렇게 하면 굳이 static lib로 만든 의미가 없어지죠... cpp가 다 노출이 되니...해서 이번에야 말로 h파일과 확장자 a인 lib파일만으로 빌드 할 수 있게 구성해 보았습니다.

일단 기존 static lib로 빌드시에 만들어진 obj/local/armeabi/libframework.a를 저는 Libs/Framework/android/armeabi/ 에 파일을 복사해 넣었습니다. 원래는 Framework를 따로 ndk-build해서 해야하는데 이렇게 해도 되고, 따로 ndk-build는 아직 안해봤네요. Framework SDK상위 폴더인 include에는 Engine/Framework/ 의 하위폴더와 같은 구조로 h 파일들만 들어가 있구요.

여기서 잠깐, batch file로 h파일만 복사하던 것에 대한 포스팅이 있었는데요 막상 pribuilt_static_library로 진행하다보니 포스팅 내용과는 다르게 폴더구조까지 해서 h 파일을 복사해야 했습니다. framework 내부에서나 이것을 사용하는 게임에서 framework 파일들 include관련 된 것을 제가 하위 폴더까지 포함 디렉토리까지 안하고 Framework 이 부분만 포함하고 했더니 sdk폴더에도 폴더구조가 필요했던거죠. 즉, Framework/ 에는 여러 하위 폴더가 있고 그중에 Framework/abc/def.h 가 있다면 전 Framework만 포함 폴더라서 include abc/def.h 이런 식으로 했다는 야기 입니다. 결론은 아래와 같이 batch file의 내용 변경이 있었습니다.

xcopy *.…

cocos2d-x에 android 정적 lib 만들어 붙일때 Android.mk 변동사항

이미지
프레임워크라고 부르기도 민망한 기능들을 기존에는 게임 프로젝트에 직접 추가해서 작업중이었습니다. 몇몇 기능들이 배포 가능 수준이 되면 팀원들과 공유를 소스로 공유했지만 그 부분에 있어서 불필요한 과정이 생겨서 lib로 만들어 sdk로 배포하자고 마음 먹고 따로 Framework라는 프로젝트를 만들어 봤습니다.
일단 win32환경에서 빌드 및 실행이 잘 되야하는 것은 당연하겠고, Framework에 Android.mk를 아래와 같이 작성했습니다. 보통 대충 빨리 만들다보면 create-android-project.bat로 해서 바로 cocos2d-x 폴더안에 게임 프로젝트들을 만드실텐데요 저는 스샷과 같이 폴더 구조가 다른데 이부분 참고하시면서 보시면 되겠습니다.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

#모듈 이름
LOCAL_MODULE := framework_static

#빌드되서 만들어지는 모듈 파일명
LOCAL_MODULE_FILENAME := libframework

LOCAL_STATIC_LIBRARIES := curl_static_prebuilt

#작업하신 cpp들을 넣어주시면 된다
LOCAL_SRC_FILES := \
frameworkcppfiles

LOCAL_C_INCLUDES := $(LOCAL_PATH) \
                    $(LOCAL_PATH)/../cocos2d-2.0-rc2-x-2.0.1/cocos2dx \
                    $(LOCAL_PATH)/../cocos2d-2.0-rc2-x-2.0.1/cocos2dx/include \
                    $(LOCAL_PATH)/../cocos2d-2.0-rc2-x-2.0.1/cocos2dx/kazmath/include \
                    $(LOCAL_PATH)/../cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/android

#stat…

배치 파일 for 문법으로 하위폴더의 파일을 폴더구조 빼고 대상에 복사하기

lib로 모듈을 만들어서 sdk개념으로 배포할려고 준비중에 여러 하위 폴더에 있는 h파일을들 한 곳에 복사해줘야 하는 일이 생겼습니다. 그래서 바로 xcopy로 옵션을 줘가면서 해봤지만 하위 폴더 구조 통으로 대상 폴더에도 복사가 되더군요. 대상 폴더에는 폴더 구조는 빼고 파일만 복사가 되었으면 했는데 암만 옵션 찾아보고 구글링 해봐도 xcopy로는 해결이 안되었습니다.

그래서 이번에 c#도 공부했겠다 후딱 툴로 만들어버릴까? 하다가 순간 bat 파일로 만들어보자해서 구글링을 통해 아래와 같이 만들었습니다.



@echo off

for /r %%i in (*.h) do copy "%%i" d:\z



위에 처리한 명령에 대한 설명입니다.

/r : 하위 디렉토리 파일까지 처리
%%i : 변수명으로 대소문자 구분.
(*.h) : 와이들카드 기입하면 된다. h 파일만 복사할 것이므로 이렇게 처리.
do 다음 : 원하는 명령어 기입
"%%i" : 파일명들이 명령어에 자동 대입되는 부분이다. ""로 둘러싸야 공백 있는 파일명도 처리할 수 있다.
d:\z : 복사 대상 폴더. 원하는 대상으로 기입

더 세부적인 처리에 대해 알고 싶다면 콘솔창에서 for/? 하시면 됩니다.

error LNK2019: "__declspec(dllimport) public: class cocos2d::extension::CCNodeLoader * __thiscall cocos2d::extension::CCNodeLoaderLibrary::getCCNodeLoader(char const *)" 에러

error LNK2019: "__declspec(dllimport) public: class cocos2d::extension::CCNodeLoader * __thiscall cocos2d::extension::CCNodeLoaderLibrary::getCCNodeLoader(char const *)" (__imp_?getCCNodeLoader@CCNodeLoaderLibrary@extension@cocos2d@@QAEPAVCCNodeLoader@23@PBD@Z) 외부 기호(참조 위치: "public: void __thiscall GameStateManager::registerCCNodeLoader(char const *,class cocos2d::extension::CCNodeLoader *)" (?registerCCNodeLoader@GameStateManager@@QAEXPBDPAVCCNodeLoader@extension@cocos2d@@@Z) 함수)에서 확인하지 못했습니다.

현재 최신 버전인 cocos2d-2.0-rc2-x-2.0.1에서는 위와 같은 에러가 발생합니다. CCNodeLoaderLibrary.h 파일을 보면


CCNodeLoader * getCCNodeLoader(const char * pClassName); CCNodeLoader * getCCNodeLoader(CCString * pClassName); 있죠. 그래서

///const char* pClassName if( pNodeLoaderLibrary->getCCNodeLoader( pClassName ) == 0 ) 이렇게 사용하던 것을


if( pNodeLoaderLibrary->getCCNodeLoader( ccs( pClassName ) ) == 0 ) 이렇게 변경했습니다. CCString로 넘겨주려고요. 했더니 잘 되네요. CCNodeLoaderLibrary의 cpp를 보니 왠걸...인자로 const char* pClassName 으…

원격 서버에서 (425) 데이터 연결을 열 수 없습니다. 오류를 반환했습니다

try
{
     WebClient wc = new WebClient();
     wc.Credentials = new NetworkCredential(Id, Pass);

     string strRealServerAddr = Ip + ":" + Port + "/" + RootDir + "/";

     wc.UploadFile(strRealServerAddr + strServerFile, strLocalFile);

     AddLog("파일 업로드 중..." + strServerFile);
     return true;
}
catch (System.Exception ex)
{
     iTryCount++;
     AddLog("일시적 파일 업로드 에러 : " + ex.Message + " 다시 시도 합니다." + iTryCount.ToString(), true);
}


위와 같이 c#의 WebClient로 ftp에 파일 업로드를 하던 중에 '원격 서버에서 (425) 데이터 연결을 열 수 없습니다. 오류를 반환했습니다' 와 같은 예외가 발생할 수 있습니다.

MS IIS 상태 코드 설명 링크 밑부분쯤에 가보면 이것은

4xx - 일시적인 부정적 완료 회신

명령이 성공하지 못했지만 오류는 일시적입니다. 클라이언트가 명령을 다시 시도하면 성공할 수도 있습니다.
421 서비스를 사용할 수 없으며 컨트롤 연결을 닫습니다. 이것은 서비스가 프로그램을 종료해야 함을 아는 경우 명령에 대한 응답이 될 수 있습니다.425 데이터 연결을 열 수 없습니다.426 연결이 닫히고 전송이 중단됩니다.450 요청된 파일 동작이 수행되지 않았습니다. 파일을 사용할 수 없습니다(예: 파일 사용 중).451 요청된 동작이 중단되었습니다. 처리 중 로컬 오류가 발생했습니다.452 요청된 동작이 수행되지 않았습니다. 시스템의 저장 공간이 부족합니다.
일시적인 부정적 완료 …

크로스 스레드 작업이 잘못되었습니다. xxx 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다

이미지
c#으로 개발을 하다보면 '크로스 스레드 작업이 잘못되었습니다. xxx 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다' 이와 같은 에러가 발생할 수 있습니다. 컨트롤이 있는 스레드가 아닌 다른 스레드에서 컨트롤에 접근을해서 생긴 문제라고 하는데 전 따로 쓰레드를 만들지 않고 툴을 만들다가 폴더의 파일 변화 감지를 자동으로 하려고 FileSystemWatcher를 사용했고 폴더에 변화가 생기면 로그창에 로그를 찍으라고 했는데 이때 InvalidOperationException 예외가 발생하더군요. 내부적으로 등록한 이벤트가 쓰레드로 처리되는가 봅니다.

해결 방법은 크게 3가지가 있습니다.

CheckForIllegalCrossThreadCalls = false;

첫번째로 위 한 줄을 추가하면 해결이 가능합니다. 해당 예외는 debug에서만 발생하므로 이 한줄 추가로 예외를 무시할 수 있습니다.

두번째로 delegate와 Invoke를 사용해서 처리합니다.

delegate void FileWatcherDelegate(string text);
/// <summary>
/// 리스트 박스에 로그 출력
/// </summary>
/// <param name="strLog"></param>
public void AddLog(string strLog)
{
    try
    {
        if (this.patchLogList.InvokeRequired)
        {
            FileWatcherDelegate fileWatcherDelegate = new FileWatcherDelegate(AddLog);
            this.patchLogList.Invoke(fileWatcherDelegate);
        }
        else
        {
            this.patchLogList.Items.Add(strLog);

cocos2d-x android curl로 파일 전송시 CURLE_COULDNT_RESOLVE_HOST 에러

cocos2d-x에 들어있는 크로스플랫폼 지원인 curl로 파일 다운로드시 win32에서는 잘 되는데 안드로이드에서는 에러를 뿜어내더군요.

CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
6번 에러인데 tests 샘플과 비교해보니 답이 나왔습니다. 해당 프로젝트의 AndroidManifest.xml을 열어 </manifest> 전에 아래 내용을 추가해줍니다.

    <uses-permission android:name="android.permission.INTERNET"/>

또는 GUI적으로 uses permission을 추가 하시려면 링크를 참고하시면 됩니다.

인터넷 접근 허가를 해주기 위한 것인거 같네요.

cocos2d-x xxx.o 에서 필요로 하는 타겟 xxx.cpp 를 만들 규칙이 없습니다

이미지
$ sh build_native.sh
Using prebuilt externals
make: Entering directory `/cygdrive/c/Android/cocos2d-2.0-rc2-x-2.0.1/projectc/proj.android'
Gdbserver      : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup       : libs/armeabi/gdb.setup
make: *** `obj/local/armeabi/objs-debug/game_shared/__/__/Classes/Layer/OptionLayer.o'에서 필요로 하는  타겟 `jni/../../Classes/Layer/OptionLayer.cpp'를 만들 규칙이 없습니다.  멈춤.
make: Leaving directory `/cygdrive/c/Android/cocos2d-2.0-rc2-x-2.0.1/projectc/proj.android'

위와 같이 에러가 발생한다면 개인 프로젝트시 수정사항에서 수정했던 Android.mk 파일을 수정하셔야 합니다. 혹시나 win32등에서 개발중에 불필요 파일이 생겨 파일을 지우시지 않았는지 생각하시고 지우셨던 파일을 Android.mk에서 지워주면 됩니다.

cocos2d-x android 신규 프로젝트 생성 후 빌드 실행까지

이미지
혹시 windows에서 cocos2d-x와 이클립스 기반 기본적인 빌드 환경이 구성안되신 분들은 이 게시물을 보시기 전에 아래 링크의 게시물을 먼저 보신 후 빌드 환경을 세팅하시기 바랍니다.

cocos2d-x window에서 이클립스 기반 안드로이드 빌드 세팅


먼저 create-android-project.bat를 수정합니다. 위 스샷과 같이 _CYGBIN, _ANDROIDTOOLS, _NDKROOT 부분을 각 설치 환경에 맞게 변경해줍니다.
안드로이드 새 프로젝트를 만들기 위해 create-android-project를 실행합니다. 그리고 package path와 project name을 원하시는대로 입력해줍니다.

제 폰이 4.0.4라서 4번인 4.0.3을 선택했습니다.

프로젝트가 생성중입니다.
cygwin에서 만들어진 프로젝트 폴더로 이동해서 build_native.sh를 실행합니다.
또 Permission denied가 발생하는군요. 왜자꾸 발생하는지.. 쩝.. chmod로 속성 변경을 해줍니다. 안나시는 분들도 있을듯?

이클립스를 실행해서 만든 프로젝트를 로드하시고 Run -> Run Configurations를 선택합니다.

Android Application에 위 스샷처럼 뭔가 없고 비어있으시면 더블 클릭하셔서 새로운 설정을 만듭니다.

만드셨다면 위에 보이는 스샷에서 Browse를 선택해합니다.

Project Selection창에서 만들었던 package.project 이름으로 된 것을 선택해줍니다.

Target탭에서 run에 사용할 적절한 것을 선택하시고요. 전 폰으로 하려고 Active devices를 선택했습니다.

준비는 끝났습니다. run을 해보시고 만약 위처럼
Error No resource found that matches the given name( at 'icon' with value '@drawable/icon') 로그 메세지와 함께 에러가 발생한다면 프로젝트 생성시 icon명이 잘 못 생성 되서 생…

cocos2d-x curl 사용시 빌드 문제 해결

fatal error: curl/curl.h: No such file or directory

C:/Android/cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/third_party/win32/curl/curlrules.h:79:4: error: #error "CURL_SIZEOF_LONG definition is missing!"
C:/Android/cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/third_party/win32/curl/curlrules.h:94:4: error: #error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
C:/Android/cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/third_party/win32/curl/curlrules.h:99:4: error: #error "CURL_FORMAT_CURL_OFF_T definition is missing!"
C:/Android/cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/third_party/win32/curl/curlrules.h:104:4: error: #error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
C:/Android/cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/third_party/win32/curl/curlrules.h:109:4: error: #error "CURL_FORMAT_OFF_T definition is missing!"
C:/Android/cocos2d-2.0-rc2-x-2.0.1/cocos2dx/platform/third_party/win32/curl/curlrules.h:114:4: error: #error "CURL_SIZEO…

cocos2d-x android 개인 프로젝트 빌드를 위해 수정, 추가할 것들

이미지
자동 생성되는 HelloWorldScene를 쓰시는 분들은 없겠죠? 물론 쓰신다면 남겨두어야 하겠지만, 이 포스팅에서는 안 쓰는 것을 전재로 설명합니다.

일단 Classes 폴더에서 필요없는 HelloWorldScene의 cpp와 h 파일을 지웁니다.

proj.android/jni/helloworld/main.cpp 에서 #include "HelloWorldScene.h"를 삭제하고 #include "cocos2d.h" 를 추가합니다.

다음으로 proj.android/jni/Android.mk 파일을 수정해야합니다.
LOCAL_SRC_FILES 파일에서 ../../Classes/HelloWorldScene.cpp 부분을 삭제합니다. 그리고 Win32환경에서 개발했던 source, resource를 복사 후 빌드 전 역시나 LOCAL_SRC_FILES 부분에 개발했던 cpp 파일들을 추가해 줍니다.

../../Classes/GameState/TitleState.cpp \

이런식으로 말이죠. 마지막 추가에는 \ 빼시구요. 만약 추가 없이 빌드를 하면 아래와 같은 에러 메세지를 뿜어냅니다.


SharedLibrary  : libgame.so ./obj/local/armeabi/objs-debug/game_shared/__/__/Classes/AppDelegate.o: In function `TitleLayer::create()': C:\Android\cocos2d-2.0-rc2-x-2.0.1\projectc\proj.android/jni/../../Classes/TitleState.h:17: undefined reference to `TitleLayer::TitleLayer()' ./obj/local/armeabi/objs-debug/game_shared/__/__/Classes/AppDelegate.o: In function `~AppDelegate': C:\Android\cocos2d-2.0-rc2-x-2…

cocos2d-x 개발시 크로스플랫폼 error: 'GetTickCount' was not declared in this scope

error: 'GetTickCount' was not declared in this scope

GetTickCount는 윈도우용이므로 cocos2d-x 기반 안드로이드나 ios 빌드시에는 당연히 에러를 뿜어주네요.

보통 리눅스에서는 아래처럼 대신해서 구현을 한다고 하는데요,



unsigned int GetTickCount() { struct timeval gettick; unsigned int tick; gettimeofday(&gettick, NULL); tick = gettick.tv_sec*1000 + gettick.tv_usec/1000; return tick; } cocos2d-x에는 CCTime::gettimeofdayCocos2d 라는것이 있습니다. 하지만 내부적으로 위에처럼 *, / 연산까지 해서 틱을 돌려주진 않고 아래처럼 따로 처리해야 합니다.



struct cc_timeval getTick; CCTime::gettimeofdayCocos2d( &getTick, 0 ); unsigned int iTick = getTick.tv_sec * 1000 + getTick.tv_usec / 1000; 따로 간단히 함수로 만들면 되겠죠.

cocos2d-x cygwin 안드로이드 빌드시 At global scope error: extra qualification

cocos2d-x 에서 윈도우 환경에서 잘 개발 후 안드로이드 빌드 시 아래와 같은 에러가 발생할 수 있습니다.

jni/../../Classes/Factory/DataTableFactory.h: At global scope:
jni/../../Classes/Factory/DataTableFactory.h:11:2: error: extra qualification 'DataTableFactory::' on member 'DataTableFactory' [-fpermissive]
jni/../../Classes/Factory/DataTableFactory.h:11:2: error: extra qualification 'DataTableFactory::' on member 'DataTableFactory' [-fpermissive]

class DataTableFactory : public Factory { FACTORY_CREATE_FUNC( DataTableFactory );
FACTORY_CREATE_FUNC 라는 define을 쓰는 놈이 있는데요,
#define FACTORY_CREATE_FUNC( type ) \ public: \ type::type(){} \ type::~type(){} \
이렇게 되어 있던 것을
#define FACTORY_CREATE_FUNC( type ) \ public: \ type(){} \ ~type(){} \
이렇게 수정했습니다. 이 define을 사용하면 h파일에 하게 되는 것인데 어찌보면 당연한 것인데 visual studio 2010에서는 아무 문제없이 컴파일이 되던것이 cygwin의 gcc에서는 에러를 뿜어내는군요.
표준문제 인듯보이는데 굳이 cocos2d-x가 아니더라고 리눅스기반 gcc 컴파일할 때 조심해야할 듯 하네여.