BLOG main image
우리는 오프라인 제작법과 다른 온라인 제작법을 연구하고 있습니다.
게임을 테스트하거나, 아마추어 게임을 제작하거나,
시간이 없어서 남이 만들 것을 차용하거나 이런 저런 이유로 좋은 스프라이트가 필요하다.

좋은 리소스를 찾는 것은 즐겁지만, 때로는 중독되어 사람이 미쳐버린다. 
따라서 주의할 것.

MMO RPG와 같은 온라인 게임은 스프라이트가 공개되지는 않지만 구글링을 하면 어떻게든 구할 수 있다.
대다수 불법으로 팩킹을 풀어놓은 경우일 것이다. 동인 게임이 아니면 오픈 소스를 쓰는 것이 좋다.
아니면 오픈 소스에 자신의 리소스를 기부하거나..

그리고 라이센스, 저작권 문제는 꼼꼼하게 살펴봐야 한다.

난 돈 주고 산다.
http://www.gamesource.co.kr
나도 돈 주고 사고 싶다. 돈 많이 벌어서 사야지.
난 직접 뽑는다.
http://cafe.naver.com/agpn.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=45&
이런 식으로 노가다 하는 방법도 있는데, 별로.. 차라리 언팩한다.



게임 스프라이트
http://sdb.drshnaps.com/
spriters-resource와 함께 스프라이트의 쌍두마차
http://spriters-resource.com/ 
내가 꼽는 최고의 스프라이트 수집 사이트.
http://pixels.seiha.org/
윤구가 추천해준 사이트. 정말 좋은 것이 많다.
http://www.videogamesprites.net/
여기도 정말 쓸만하다.
 http://www.gsarchives.net/
여기도 가끔 방문한다.
http://gmc.yoyogames.com/index.php?showtopic=11203
누군가 친절하게 많은 양을 링크해놨다. 종합적으로 쓸만하다.


게임 음악
http://soundsresource.com/
어지간한 것은 다 있다. 다만 외국인 소리가 많다.
http://www.nes-snes-sprites.com/

http://www.freesound.org/
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 정상택
pThread로 가급적 cocos2d-x 함수를 쓰면 안된다.
기본적으로 cocos2d-x에서는 release, retain과 같은 메모리에 관련된 함수가 쓰이기 때문이다.
일상적으로 factory된 함수를 사용하는 것이 cocos2d-x이기 때문에, 당장 코드에 release, retain함수가 없다고 해도 방심해서는 안된다. 기본적으로 CCNode를 상속받은 클래스는 retain 및 autorelease를 내장하고 있으니 각별하게 주의해야 한다.

굳이 쓰겠다면 2개의 쓰레드에 각각 retain과 release를 걸고 retainCount로 측정해보면 알 수 있다.
메모리 뻑난다.

따라서 데이터만 쓰레드로 주고 받는 것을 추천한다.

이것은 내가 pthread_cond_wait와 pthread_cond_signal을 이용하여 쓰레드 통신을 테스트 해본 예제이다.
pthread_cond_wait는 pthread_cond_signal에서 신호를 보내기 전까지 대기하고 있는다. 따라서 데드락이 걸릴 수 있으니 매우 조심해야 한다. 실험 결과가 매우 흥미롭다. 

참조한 소스는 다음과 같다.
http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Thread/Beginning/PthreadApiReference
http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/3/pthread_cond_wait 


테스트한 소스를 첨부한다. 이 소스를 Appdelegate.cpp에서 다음과 같이 사용하면 된다.


Appdelegate.cpp 

bool AppDelegate::applicationDidFinishLaunching()

{

CCDirector *pDirector = CCDirector::sharedDirector();

 
pDirector->setOpenGLView(&CCEGLView::sharedOpenGLView());

 
pDirector->setDisplayFPS(true);

 
pDirector->setAnimationInterval(1.0 / 60);

 
CCScene * scene =ThreadTestScene::scene();

pDirector->runWithScene(scene);

 
return true;

}


ThreadTestScene.h

#ifndef __THREAD_TEST_SCENE_H__

#define __THREAD_TEST_SCENE_H__


#include "cocos2d.h"

using namespace cocos2d;


class ThreadTest : public CCLayer

{

public:

    ThreadTest();

    ~ThreadTest();

    

    static CCScene* scene();

    LAYER_NODE_FUNC(ThreadTest);

    

    virtual bool init();

    virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);

    virtual void menuCallback(CCObject* pSender);

private:

    CCLabelTTF* m_pLabel;

    pthread_t m_pThread0;

    pthread_t m_pThread1;

    pthread_mutex_t m_lock;

};



ThreadTestScene.cpp


#include "ThreadTestScene.h"

#include <pthread.h> // pthread 사용

#include <unistd.h> // sleep() 사용



CCScene* ThreadTest::scene()

{

    CCScene* scene = CCScene::node();

    ThreadTest* layer = ThreadTest::node();

    scene->addChild(layer);

    

    return scene;

}


ThreadTest::ThreadTest()

{

    

}


ThreadTest::~ThreadTest()

{

    m_pLabel->release();

    

    if ( m_pThread0 )

    {

        pthread_detach(m_pThread0);

        m_pThread0 = NULL;

    }

    if ( m_pThread1 )

    {

        pthread_detach(m_pThread1);

        m_pThread1 = NULL;

    }

}


bool ThreadTest::init()

{

    bool bRet = false;

    {

        CCSize winSize = CCDirector::sharedDirector()->getWinSize();

        CCLabelTTF* label = CCLabelTTF::labelWithString("Thread Test", "Arial", 28);

        addChild(label, 0);

        label->setPosition( ccp(winSize.width/2, winSize.height-50) );

        

        setIsTouchEnabled(true);

        // create a label to display the tip string

        m_pLabel = CCLabelTTF::labelWithString("Touch the screen to connect", "Arial", 22);

        m_pLabel->setPosition(ccp(winSize.width / 2, winSize.height / 2));

        addChild(m_pLabel, 0);

        

        m_pLabel->retain();

        

        


        CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(

                                                                               "CloseNormal.png",

                                                                               "CloseSelected.png",

                                                                               this,

                                                                               menu_selector(ThreadTest::menuCallback) );

        

        pCloseItem->setPosition( ccp(winSize.width - 20, 20) );

            

        // create menu, it's an autorelease object

        CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem, NULL);

        pMenu->setPosition( CCPointZero );

        this->addChild(pMenu, 1);

        

        bRet = true;

    }

    

    return bRet;

}


// 뮤텍스 객체 선언

int flag = 0;

int MAX_ROOP = 5; // "thread 실행할 것인가?" 정하는 값이다.

pthread_mutex_t mutex_lock;

pthread_cond_t  thread_cond_write = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t  thread_cond_read  = PTHREAD_COND_INITIALIZER;


// 뮤텍스로 보호할 정보와 객체

struct CharaterParameter

{

    int hp;

    int mp;

};


struct CharaterParameter charaterParameter;


void* do_write(void* data)

{

    charaterParameter.hp = 0;

    charaterParameter.mp = 0;

    

    CCLog("Write:: this scope is working once because it is not in While loop \n");

    

    while (1

    {

        CCLog("pthread Write");

        if(flag >= MAX_ROOP )

        {

            /*  thread 중지하지 않으면 Cocos2d-x 프로그램이 종료되지 않는다.

             강제 종료를 하여도 thread 계속 돌아간다.

             따라서 pThread_exit() 종료해줘야 한다.

             */

            pthread_exit(NULL);

        }

        

        /* pthread_cond_signal signal 보내는 역활이다

           쓰레드간의 통신을 위해서 사용한다.

           쓰레드 A pthread_cond_signal 사용하며, 쓰레드 B에는 pthread_cond_wait 사용한다고 가정하자.

           쓰레드 A pthread_cond_signal에서 보낸 signal 쓰레드 B pthread_cond_wait signal 받아야 한다.

           pthread_cond_wait 계속 pthread_cond_signal에서 signal 받아야 쓰레드를 작동시킨다.

           쓰레드 A signal 받지 못하면 계속 대기하기 때문에, 쓰레드 B 작동하지 않는다.

        */

        pthread_mutex_lock(&mutex_lock);

            pthread_cond_signal(&thread_cond_write);

                CCLog("pthread_cond_signal: thread_cond_write");

                charaterParameter.hp = random() % 6000;

                charaterParameter.mp = random() % 6000;

        if( flag > 0)

        {

            pthread_cond_wait(&thread_cond_read, &mutex_lock);

            CCLog("pthread_cond_wait  : thread_cond_read");

        }

        else

        {

            CCLog("pthread_cond_wait  : thread_cond_read is work after flag value over 1");

        }


        pthread_mutex_unlock(&mutex_lock);

        sleep(1);

        

    }

    

    CCLog("pthread function is never working after While loop finished");

    return NULL;

}


void* do_read(void* data)

{

    CCLog("Read:: this scope is working once because it is not in While loop \n");


    while (1

    {

        CCLog("pthread Read");

        if(flag >= MAX_ROOP )

        {

            pthread_exit(NULL);

        }

        

        pthread_mutex_lock(&mutex_lock);

            pthread_cond_wait(&thread_cond_write, &mutex_lock);

            CCLog("pthread_cond_wait  : thread_cond_write");

                CCLog("thread %4d :: %4d + %4d = %6d", flag, charaterParameter.hp, charaterParameter.mp, charaterParameter.hp + charaterParameter.mp);

                flag++;

            pthread_cond_signal(&thread_cond_read);

            CCLog("pthread_cond_signal  : thread_cond_read\n");

        pthread_mutex_unlock(&mutex_lock);

        //sleep(1);


    }

    return NULL;

}   



void ThreadTest::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)

{

    int a = 1;

    int b = 2;

    int thread_id[2] = {0};

    

    CCLog("pthread  초기화 작업 시작\n");

    flag = 0; // flag 초기화

    pthread_mutex_init(&mutex_lock, NULL);

    pthread_cond_init(&thread_cond_write, NULL);

    pthread_cond_init(&thread_cond_read, NULL);

    thread_id[0] = pthread_create(&m_pThread0, NULL, do_write, (void *)&a);

    thread_id[1] = pthread_create(&m_pThread1, NULL, do_read, (void *)&b);

    CCLog("pthread  초기화 작업 \n");

    

    if( thread_id[0] < 0 || thread_id[1] < 0 )

    {

        CCLog("pThread Error");

    }

    else

    {

        /* pthread_join 모든 쓰레드가 종료할 때까지 기다린다.

           왜냐하면 쓰레드 실행 도중에 부모 쓰레드가 종료되면 되기 때문이다.

           쓰레드가 모든 일을 끝내면 pthread_join 깨우게 된다.

           그렇게 되면 쓰레드가 가지고 있는 모든 자원을 되돌려준다.

         

           만일 실행되고 있는 쓰레드를 즉시 중지하기 원한다면 pthread_join 쓰지 않고

           pthread_cancel() pthread_terstcancel 쓰면 된다.

        */ 

        int status;

        CCLog("pthread  종료 작업 시작\n");

        pthread_join(m_pThread0, (void **)&status);

        pthread_join(m_pThread1, (void **)&status);

        pthread_mutex_destroy(&mutex_lock);

        pthread_cond_destroy(&thread_cond_write);

        pthread_cond_destroy(&thread_cond_read);

        CCLog("thread finished and status is %d", status);

        m_pThread0 = NULL;

        m_pThread1 = NULL;

        CCLog("pthread  종료 작업 \n");

    }

}



// 메뉴를 선택한다.

void ThreadTest::menuCallback(CCObject* pSender)

{

    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

exit(0);

#endif

}

 

결과:
각각 실행 결과가 달랐다. 특히 초반에 실행되는 순서가 다른 경우가 많앗다.
어느 순간에는 Write가 먼저 실행이 되거나, Read가 앞에 실행되거나 하는 현상이 보이며,
함수 앞부분에 출력해야 할 부분이 맨 뒷 부분에 출력되는 현상도 발견되었다.



1번째 실행


2번째 실행



3번째 실행



저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 정상택


Eclipse에서 curl을 추가하는 방법은 다음과 같다.
  1. Class/Android.mk에서 header 파일의 경로를 추가한다. 
  2. Eclipse에서 인터넷 퍼미션을 받는다.
Android에서 쓰일 Cocos2d-x의  curl의 경로는 다음과 같다.
/cocos2d-1.0.1-x-0.10.0/cocos2dx/platform/third_party/android



이 경로에는 오직 header file밖에 존재하지 않는다. 따라서 Xcode와 다르게 libcurl.a를 프로젝트에 추가할 필요는 없다. 


이제 안드로이드를 위한 셋팅에 들어간다.

1. Android.mk를 연다. 
  • Android 경로는 "프로젝트 이름/Classes/Anroid.mk" 이다.
    Xcode, Eclipse, EditPlus, vim 와 같은 코드를 편집하는 프로그램을 추천한다.


2. Anroid.mk를 다음과 같이 수정한다.

  • LOCAL_C_INCLUDES에는 다음과 같이 입력한다.
    추가하는 항목이 마지막 목록이면 " \ "기호를 뒤에 붙이지 않아도 된다. 
$(LOCAL_PATH)/../../cocos2dx/platform/third_party/android

  • LOCAL_LDLIBS에서는 다음과 같이 입력한다.
-L$(call host-path, $(LOCAL_PATH)/../../cocos2dx/platform/third_party/android/libraries/$(TARGET_ARCH_ABI)) -lcurl 
그리고 저장한다.



그리고 CURL 함수를 사용하여 코딩을 합니다.


3. 터미널(또는 콘솔)을 열고 build를 한다.
pwd는 지금 위치한 폴더의 경로를 나타내는 명령어로 빌드에는 필요없는 명령어다. 따라서 굳이 신경쓰지 않아도 된다. 
ls 역시 리눅스 명령어로 현재 폴더에 있는 파일을 나타내는 명령어이다. 따라서 굳이 신경쓰지 않아도 된다.

./build_native.sh를 입력하고 엔터를 치면 빌드가 실행된다.

4. 이클립스를 열고, AndroidManifect.xml을 선택한다.
그 후에 Permissions 탭을 누른다.
그 다음에 Add 버튼을 눌러 Permission을 추가한다.




5. 창이 뜨면 Uses Permission을 누르고, ok 버튼을 누릅니다.



6. Uses Permission에서 어떤 것을 포함해야 할 것인지 정해야 합니다.



CURL은 통신을 위한 것이므로 INTERNET 허락을 추가합니다.


7. clean을 한 후, RUN 버튼을 눌러서 RUN을 합니다.


8. 원하는 에뮬레이터 버전을 선택하고 실행하면 됩니다.


9. 실행합니다.


 
저작자 표시 비영리 동일 조건 변경 허락
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 정상택
◀ PREV : [1] : [2] : [3] : [4] : [5] : ... [136] : NEXT ▶

Statistics Graph

카테고리

분류 전체보기 (407)
미국 어학연수 (97)
게임 프로젝트 (20)
게임 제작 정보 (92)
포트폴리오 (21)
자유게시판 (79)
비밀 자료실 (1)
전공: 프로그래밍 (88)
사적인 기록 (0)

달력

«   2012/01   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31