我想要完成什么:我希望能够循环遍历基类向量并引用子类上的接口。
我现在在哪里:我正在为一个拥有游戏对象的游戏创建一个系统,您可以通过添加组件来向游戏对象添加功能。
我创建了一个包含组件列表的 GameObject 类。该类循环遍历所有组件并调用组件上的三个函数:
handleInput()
、update()
和draw()
。
GameObject.h
#include "IInitialize.h"
#include "IInput.h"
#include "IUpdate.h"
#include "IDraw.h"
#include "TransformComponent.h"
class Component;
class GameObject : public IInitialize, IInput, IUpdate, IDraw
{
public:
TransformComponent transform;
GameObject();
void addComponent(Component* component);
bool IInitialize::initialize()
{
return true;
}
void IInput::handleInput(sf::RenderWindow* window, sf::Event* event)
{
for (auto it = components.begin(); it != components.end(); it++)
{
IInput* component = dynamic_cast<IInput*>(*it);
if (component != nullptr)
{
component->handleInput(window, event);
}
}
}
void IUpdate::update(float deltaTime)
{
for (auto it = components.begin(); it != components.end(); it++)
{
IUpdate* component = dynamic_cast<IUpdate*>(*it);
if (component != nullptr)
{
component.update(deltaTime);
}
}
}
void IDraw::draw(sf::RenderWindow* window)
{
for (auto it = components.begin(); it != components.end(); it++)
{
IDraw* component = dynamic_cast<IDraw*>(*it);
if (component != nullptr)
{
component.draw(window);
}
}
}
private:
std::vector<Component*> components;
};
游戏对象.cpp
#include "GameObject.h"
GameObject::GameObject()
{
transform = TransformComponent();
transform.position = sf::Vector2f(960, 540);
}
void GameObject::addComponent(Component* component)
{
component->parent = this;
components.push_back(std::move(component));
}
在
handleInput()
、update()
和 draw()
函数中,我尝试从组件中获取接口来调用它们。
Component 基类不实现接口,但 Component 基类的子类实现。
组件.h
#include "IInitialize.h"
class GameObject;
class Component : public IInitialize
{
public:
GameObject* parent;
Component();
virtual bool IInitialize:: initialize()
{
return true;
}
};
TextComponent.h
#include "Component.h"
#include "IUpdate.h"
#include "IDraw.h"
class TextComponent : public Component, IUpdate, IDraw
{
public:
std::string text = "Text";
sf::Color color = sf::Color::White;
int size = 25;
TextComponent(std::string text = "Text", sf::Color color = sf::Color::White, int size = 25);
void setPosition();
bool IInitialize::initialize() override
{
if (!_font.loadFromFile(_fontPath))
{
return false;
}
return true;
}
void IUpdate::update(float deltaTime)
{
_text.setString(text);
_text.setFillColor(color);
_text.setCharacterSize(size);
setOrigin();
setTextPosition();
}
void IDraw::draw(sf::RenderWindow* window)
{
window->draw(_text);
}
private:
sf::Font _font;
sf::Text _text;
std::string _fontPath = "Assets/Fonts/accidental_presidency.ttf";
void setOrigin();
};
我的问题:我的问题是我存储在组件向量中的对象是从 Component 类派生的子类。我认为发生对象切片是因为基组件类没有实现任何接口,并且当 GameObject 尝试将组件类转换为
IInput
、IUpdate
或 IDraw
时,它会失败,因为基类没有实现不实现这些接口。
我尝试过的:
我考虑过尝试将组件向下转换为正确的类型以获得接口,但这需要游戏对象了解不同类型的组件,并且我不确定它是否需要了解它们。它还需要我在每次创建新组件时更新 GameObject 类。
我尝试创建一个始终从接口派生的中间人类。这限制了接口的使用,并使得有时某个函数因为组件不需要使用它而未被使用。
我已将接口添加到基类中,并在子类中重写它们。这也导致有时有些接口功能无法使用。我的目标是只将接口添加到需要使用它们的对象中。
我的问题:如何设计架构,以便我可以在子对象上使用接口,而不必向游戏对象提供太多有关组件类型的信息?
详细说明@user4581301的评论,并解答您的疑虑:
这也导致有时有些接口功能无法使用。我的目标是只将接口添加到需要使用它们的对象中。
您可以将接口定义为
pure virtual
并在基类中提供默认实现(它可以不执行任何操作,或记录某些内容等)。
请参阅带有实现的纯虚函数了解更多详细信息。