我不确定如何说出这个问题的标题,但这是我的问题:
我正在使用实体组件系统架构开发C ++游戏。在此体系结构中,每个游戏对象都表示为一个类:
class Object
一个类只不过是组件的容器,它处理游戏对象逻辑的一部分。
class Component
每个组件都有针对特定事件的更新功能和事件处理程序。每个事件都来自一个公共基类,每个子对象都有自己的数据字段来描述事件。在我的实际代码中,基本Event类具有一些所有Events共享的属性。
class Event
{
};
class OnDeathEvent : public Event
{
public:
int getKillerID() const
{
return 92341;
}
};
class OnLevelEnterEvent : public Event
{
public:
int getLevelEnteredID() const
{
return 100;
}
};
在整个代码中,我们将事件发送到对象。这是我为测试我的示例代码而编写的主要函数:
int main()
{
Object obj;
obj.sendEvent(OnLevelEnterEvent());
obj.sendEvent(OnDeathEvent());
std::cin.ignore();
return 0;
}
当一个Object收到一个事件时,它会将该事件的责任委托给它的组件。
for (auto& component : components)
{
component->handleEvent(e);
}
我想为每种事件类型使用函数重载。事件处理功能的目的就变得非常明确了。
void handleEvent(const OnLevelEnterEvent& e)
但这样做需要Object类和Component基类都声明每个Event类型的所有重载。显然,这是我们想要避免的,因为我们必须更改多个类才能为游戏添加新的事件类型。以下是示例代码的其余部分:
class Component
{
public:
virtual void handleEvent(const Event& e) {}
virtual void handleEvent(const OnDeathEvent& e) {};
virtual void handleEvent(const OnLevelEnterEvent& e) {};
};
class TestComponent : public Component
{
public:
virtual void handleEvent(const OnDeathEvent& e)
{
std::cout << "You died. Your killer was: " << e.getKillerID() << std::endl;
}
};
class AnotherComponent : public Component
{
public:
virtual void handleEvent(const OnLevelEnterEvent& e)
{
std::cout << "Level Entered with ID: " << e.getLevelEnteredID() << std::endl;
}
};
对象类:
class Object
{
public:
Object()
{
components.push_back(new TestComponent());
components.push_back(new AnotherComponent());
}
void sendEvent(const Event& e)
{
for (auto& component : components)
{
component->handleEvent(e);
}
}
void sendEvent(const OnDeathEvent& e)
{
for (auto& component : components)
{
component->handleEvent(e);
}
}
void sendEvent(const OnLevelEnterEvent& e)
{
for (auto& component : components)
{
component->handleEvent(e);
}
}
private:
std::vector<Component*> components;
};
我们希望能够通过继承Event类来添加新的Event类型,而无需更改其他文件或创建新文件(新的Event类除外)。构建代码的优雅方法是什么?
欢迎任何建议。
答案 0 :(得分:1)
您的组件可以注册该活动。 调用子事件时,它可以通知其注册的事件侦听器。您可以定义一个接口并使用接口继承。
答案 1 :(得分:1)
#include <iostream>
#include <vector>
#include <boost/signals2.hpp>
class Event
{
public:
typedef boost::signals2::signal<void (Event&) > T_notify_signal;
virtual ~Event(){}
void Register(const T_notify_signal::slot_type& c) {m_listeners.connect(c);}
void NotifyListeners() {m_listeners(*this);}
virtual std::string info() const = 0;
private:
T_notify_signal m_listeners;
};
class OnDeathEvent : public Event
{
public:
virtual ~OnDeathEvent(){}
virtual std::string info() const { return "you are dead"; }
};
class OnLevelEnterEvent : public Event
{
public:
virtual ~OnLevelEnterEvent(){}
virtual std::string info() const { return "you are in a new area"; }
};
//----------------------------------------
class Component
{
public:
virtual ~Component(){}
};
class TestComponent : public Component
{
public:
TestComponent(){}
virtual ~TestComponent(){}
virtual void notifyLevelEnter(Event& e) {std::cout << "TestComponent::notifyLevelEnter(" << e.info() << ")" << std::endl;}
};
class AnotherComponent : public Component
{
public:
AnotherComponent(){}
virtual ~AnotherComponent(){}
virtual void notifyDeath(Event& e) {std::cout << "AnotherComponent::notifyDeath(" << e.info() << ")" << std::endl;}
virtual void notifyLevelEnter(Event& e) {std::cout << "AnotherComponent::notifyLevelEnter(" << e.info() << ")" << std::endl;}
};
//----------------------------------------
class Object
{
public:
Object(){}
~Object(){}
void addComponent( Component& component ) {m_components.push_back( &component );}
void sendEvent(Event& e) {e.NotifyListeners();}
private:
std::vector< Component* > m_components;
};
//----------------------------------------
int main()
{
Object obj;
// create components
TestComponent tc;
AnotherComponent ac;
// create events
OnDeathEvent death_event;
OnLevelEnterEvent level_enter_event;
// hook up events to components
death_event.Register( boost::bind( &AnotherComponent::notifyDeath, &ac, _1 ) );
level_enter_event.Register( boost::bind( &TestComponent::notifyLevelEnter, &tc, _1 ) );
level_enter_event.Register( boost::bind( &AnotherComponent::notifyLevelEnter, &ac, _1 ) );
// add components to object
obj.addComponent( ac );
obj.addComponent( tc );
// process game loop
while ( true )
{
std::cout << "obj.sendEvent(level_enter)" << std::endl;
obj.sendEvent(level_enter_event);
std::cout << "obj.sendEvent(death)" << std::endl;
obj.sendEvent(death_event);
std::cout << "obj.sendEvent(level_enter)" << std::endl;
obj.sendEvent(level_enter_event);
std::cout << "obj.sendEvent(level_enter)" << std::endl;
obj.sendEvent(level_enter_event);
std::cout << "obj.sendEvent(death)" << std::endl;
obj.sendEvent(death_event);
break;
}
return 0;
}
答案 2 :(得分:0)
如果我理解正确,您需要一个sendEvent
方法,以及发送任何通用Event
类型。在这种情况下,您可以按如下方式创建sendEvent(const Event* _event)
方法:
void sendEvent(const Event* _event) {
for (auto& component : components) {
component->handleEvent(_event);
}
}
如果你已经正确地实现了Event
的所有派生类,那么多态将处理允许根据handleEvent
的特定子类自动调用正确的Event
方法的事情。 (以及指向它的指针)传递给sendEvent
。