문제

DirectX9에 콜백 이벤트 시스템을 작성하려고합니다. 메소드 기능 포인터를 사용하여 이벤트를 Mouseclicks로 트리거하려고합니다. 그러나 나는 약간의 문제가 있습니다. 내 게임은 게임 관리자를 사용하여 렌더링을 관리합니다. 내 모든 게임 테이트는 기본 클래스 AbstractGamestate에서 파생됩니다.

이 특정 방법을 가진 스프라이트 객체가 있습니다.

m_NewGameSprite->OnClick(this, &MainMenuState::StartGame);

Main -Menustate는 내 게임이 현재 진행되는 현재 게임 인이며 StartGame 은이 클래스의 무효 방법 부분입니다. 사용자가 클릭 할 때 실행할 수 있도록 기능 포인터를 스프라이트 클래스 내 변수에 저장하고 싶습니다.

template <typename T>
void OnClick(GameState* LinkedState, void (T::*EventPointer)())
{
    m_LinkedGameState = LinkedState;
    m_EventPointer = EventPointer; // <- Doesnt compile
}

포인터를 다운 캐스트하려고 시도했지만 실제로는 작동하지 않았습니다.

내 스프라이트 클래스에는이 두 변수도 포함되어 있습니다

void                (GameState::*m_EventPointer)();
GameState*          m_LinkedGameState;

모든 도움이 감사하겠습니다

도움이 되었습니까?

해결책

나는 당신의 과제가 왜 작동하지 않는지 잘 모르겠습니다. 의심 할 여지없이 Litb는 곧 이유를 설명 할 것입니다. 부스트 기능 거의 모든 상황에서 기능 포인터를 대체 할 수있는 아름답고 일반적인 타입 및 표준 기능 객체입니다. 나는 이것을 할 것이다 :

typedef boost::function0<void> Event;
Event m_Event;

이벤트 클래스는 이제 호출하려는 객체를 포함하여 함수 호출의 상태를 캡슐화합니다. 일반적으로 당신도 사용합니다 부스트 클로저를 만들려면 자유 함수 나 다른 기능 객체에 쉽게 바인딩 할 수 있습니다.

void OnClick(Event &event)
{
  m_Event=event;
}

다음과 같이 부릅니다.

OnClick(boost::bind(&MainMenuState::StartGame, this));

이 체계를 사용하면 실제로 "링크 된 게임 상태"를 저장할 필요가 없습니다. 이것은 이벤트 객체에 캡슐화됩니다.

다른 팁

나는 매우 비슷한 문제가있었습니다. 내가 이것을 올바르게 읽는다면 당신은 거의 같은 시스템을 쓰려고합니다. ActionEvent 자바에서. 다음과 같이 보일 수 있습니다.

Component.addActionListener( new ActionEventListener( new ActionEvent(
            public void execute() { /* Component clicked Do Something */ } )));

C ++에서는 아래에 설명 된 것과 매우 유사한 일이 있습니다.

내 생각에, 이것은 실제로 메소드 호출을 재사용하고 마음대로 수정할 수 있기 때문에 훨씬 더 좋습니다. 이는 훨씬 더 많은 유연성을 제공합니다.

event.hpp

#pragma once

class Event 
{
    public:
        Event(void) { }
        ~Event(void) { }

    public:
        //Stores a function to callback. Example shown in Main.cpp
        void operator += (void (*callback)())
        {
            this->callback = callback;
        }

        //Executes our stored call back method at any given time.
        void execute(void)
        {
            callback();
        }

        //Variable of type VOID* -> This is a function which is stored + executed.
        private:
            void (*callback)();
};

main.cpp

#include <iostream>
#include "Event.hpp"

using namespace std;

void print(void)
{
    cout << "Hello This Works" << endl;
}

void print2(void)
{
    cout << "Success again!" << endl;
}

int main()
{
    Event task_event;
    task_event += print;
    task_event.execute();
    task_event += print2;
    task_event.execute();
    system("pause");
    return 0;
}

여기서 문제는 그 것입니다 StartGame 아무것도 부를 수 없습니다 GameState 인스턴스를 사용하는 인스턴스 this 매개 변수. 그것은 a로만 호출 될 수 있습니다 this 유형의 매개 변수 MainMenuState.

a void (GameState::*)() 정의 된 방법을 가리 킵니다 MainMenuState,이 방법은 GameState.

회원 기능 포인터를 저장하는 대신 다음과 같은 것을 사용하여 "명령 개체"(또는 functor) 포인터를 저장하는 것이 좋습니다.

class Callback
{
public:
    virtual void Execute() = 0;
};

그런 다음 다음과 같은 구현을 정의합니다.

template <typename TClass>
class MemberCallback : public Callback
{
public:

    MemberCallBack(TClass * pThis, void (TClass::*pFunc)() )
    {
        m_pThis = pThis;
        m_pFunc = pFunc;
    }
    void Execute()
    {
        m_pThis->*m_pFunc();
    }

private:
    TClass * m_pThis;
    void (TClass::*m_pFunc)();
};

그런 다음 유형의 멤버를 정의 할 수 있습니다 Callback *.

왜 거기에서 템플릿 기능을 사용하고 있습니까? OnClick 값을 위해 컴파일하거나 작동하지 않습니다 T 게임 외에.

그러나이 상황에서는 일반적으로 멤버 기능에 대한 포인터를 사용하지 않습니다. 나는 함수를 만들 것이다 물체, 과부하 operator(), 대신 주위를 통과하십시오. 더 나은 것입니다 : 구문이 더 명확하고, 필요한 경우 기능 개체에 일부 상태를 저장할 수 있습니다.

매개 변수를 다음으로 가져와야합니다.

void (GameState::*EventPointer)()

일단 포인터이기 때문에, 이와 같이 다운 캐스트 할 수는 없습니다 (기본 클래스에 동일한 포인터가 존재하는지에 대한 정보가 없습니다). 이 기능은이 작업을 위해 게임에 있어야합니다 (잠재적으로 가상)

하지만! 콜백을하고 있기 때문에 (기본적으로 관찰자 패턴) 오랫동안 살펴볼 수 있습니다. 부스트 :: 신호. 그것은이 모든 것을 (그리고 그 이상) 할 것입니다. 당신은 게임에 기능을 추가 할 필요가 없습니다.

class Foo {
 // ...
 template <typename T>
 boost::signals::connection OnClick(const boost::function<void ()>& func)
 {
    return sig.connect(func);
 }

 void FireClick() { sig_(); }
private:
  boost::signal<void ()> sig_;
};

int this_will_be_called() { }

Foo f = // ...;

f.OnClick(boost::bind(&this_will_be_called));
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top