티스토리 뷰

함수 포인터를 사용해서 콜백 함수를 생성할 수 있는 CallFunc 클래스를 만들어 보자.



원하는 기능


MoveTo, RotateTo 같은 event가 완료 되었을 때 원하는 작업을 할 수 있도록 하고 싶다. 콜벡 이벤트를 만들어서 Sequence로 연결하여 사용하면 event가 끝나고 실행할 코드를 함수로 만들어서 사용할 수 있다.






클래스 구성


EventManager

- 모든 event클래스의 인스턴스들을 list로 관리한다. 리스트를 순회하며 종료된 event를 멈추고(Stop()) 삭제한다.


Event

- 모든 event의 최상위 클래스로 event의 추상적인 동작이 정의되어있다. 구체적인 event 클래스들은 이 클래스를 상속받는다.


CallFunc

- 콜백 함수를 등록할 수 있는 클래스. Event 클래스를 상속받았다.






프로그램의 흐름


1. CallFunc클래스의 인스턴스를 만든다.

- 콜백 함수로 사용할 함수를 매개변수로 생성한다.

2. EventManager에 인스턴스를 등록한다.

3. event를 실행시킨다.

4. EventManager는 때가 되면 등록된 CallFunc의 인스턴스를 동작시킨다.

5. 콜백 함수가 실행된다.






먼저 Event class (필요한 부분만 가져왔다.)


class Event{

private:

    float _duration; // 소요 시간

    float _elapse; // 경과 시간

public:

    virtual bool IsDone();

    virtual void Update(float dt);

}

 

// 경과 시간이 소요 시간보다 더 긴지 검사한다. 더 길다면 event가 끝났다는 의미.

bool Event::IsDone(){

    return _elapse>_duration;

}

 

// 매 프레임에 호출되는 함수. 경과 시간을 더한다.

void Event::Update(float dt){

    _elapse += dt;

}






EventManager는 event를 등록하고 관리하는 일을 한다.


class EventManager{

private:

    std::list<Event*> _events;

public:

    virtual void Update(float dt){

        for(std::list<Event*>::iterator it = _events.begin(); it!=_events.end(); ){

            if((*it)->IsDone()){        // 이벤트가 끝났으면

                (*it)->Stop();            // 이벤트를 정지시키고

                _events.erase(it++);    // 이벤트를 삭제한다.

            }

            else

                it++;

}

}

};   

 





이제 가장 중요한 CallFunc class. 구조를 조금 변형하면 특정 매개변수가 포함된 함수를 등록한다던지, duration을 설정할 수 있도록 해서 일정 시간 후에 callback 되는 event로도 만들 수 있다.


class CallFunc : public Event{ // Event 클래스를 상속받는다.

private:

    void (*_func)(); // 함수포인터를 맴버변수로 가진다.

public:

    CallFunc(void (*func)());

    virtual void Stop();

};

 

CallFunc::CallFunc(void (*func)()){

    _func = func; // 매개변수로 넘어온 함수를 저장한다.

    _duration = 0.0f; // duration0으로 설정한다.

}

 

void CallFunc::Stop(){

    _func(); // 콜벡함수를 호출한다.

}






만들어진 CallFunc는 아래와 같이 사용한다. 특정 event 다음에 실행되는 용도로 만들었기 때문에 MoveTo, RotateTo같은 event와 엮어서 함께 사용한다. 아래 예시는 Player에게 5초동안 (100,100) 위치로 이동하고 이동이 끝나면 MoveDone함수를 실행시키도록 하는 코드이다.

* player의 MoveDone을 CallFunc가 호출하기 위해서는 MoveDone은 static이어야 한다.


void Player::MoveDone(){ // Player 클래스의 static 맴버함수

    // ...

}

 

void Player::Move(){

    auto evt1 = new MoveTo(Vector(100, 100), 5.0f); // 100,100 위치로 5초동안 움직이라는 event

    auto evt2 = new CallFunc(MoveDone);

    auto evt3 = new Sequence(evt1, evt2); // 여러 event를 엮어서 순서대로 실행하는 하나의 event로 만든다.

 

    this->runEvent(evt3); // event를 실행한다. EventManager에 해당 event를 등록시키는 작업을 한다.

}






cocos2d-x의 CallFunc action을 흉내내기 위해 연구하면서 만들어낸 방법이다. cocos2d-x는 c++11부터 등장한 std::function, std::bind를 사용해서 더 유연하게 사용할 수 있는 콜벡 시스템을 사용하지만 c++11을 사용하지 못하는 경우 ( 그런 경우는 없겠지만 ) 이렇게 하는 것도 하나의 방법이 될 수 있겠다.

'Programming > C++' 카테고리의 다른 글

c++11 - std::shared_ptr로 thread safe callback 구현하기  (0) 2017.11.19
C++11 - std::bind  (0) 2017.09.21
C/C++ - sscanf, sscanf_s  (0) 2017.01.23
C/C++ - assert  (0) 2016.12.28
C/C++ - 가변인자 ...  (0) 2016.11.19
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함