问题描述
class SceneManager //控制所有内容在世界游戏
{
public:
void Add(SceneObject * object); //添加到向量
private:
vector< SceneObject *> _worldObjects; //包含它们的所有类
}
游戏继承自SceneObject:
class SceneObject
{
public:
virtual void Draw )= 0;
}
class Image:public SceneObject
{}
class Sprite:public SceneObject
{}
class Model3D:public SceneObject
{}
所以我知道我可以为我的矢量中的所有对象调用Draw()。
但是我一直在努力优化,我试图摆脱所有的继承和虚拟函数,并使用组合,因为它们不能被内联,并且似乎是一个主要的性能问题,当执行一个每个对象的基础。
我正在寻找一些C ++技术,我可以使用它来存储一堆SceneObject在我的向量中,然后调用Draw (),它正确地绘制与之相关的对象。这也适用于我用作虚拟的Update()函数。
所以这段代码:
void SceneManager :: Add(SceneObject * object)
{
_worldObjects.push_back(object);
}
void SceneManager :: DrawTheWorld()
{
for(unsigned int i = 0; i< _worldObjects.size(); i ++)
{
_worldObjects [i] - > Draw(); // SceneObject被称为
}
}
...将成为:
void SceneManager :: Add(Image * image)
{
SceneObject * object = new SceneObject );
//将对象链接到图像,尝试将其用作图像的成员
_worldObjects.push_back(object);
}
void SceneManager :: DrawTheWorld()
{
for(unsigned int i = 0; i< _worldObjects.size(); i ++)
{
// _ worldObjects [i] - >
//我需要某种方式才能将指针返回到原来的类
//它可以是一个图像,精灵,model3d,任何东西
}
}
我不认为如果我添加开关或如果/ elses和删除虚拟我会获得任何表现,所以我试图弄清楚是否有一个干净的方式来处理这个。
任何想法?
您可以使用免费功能来模拟对象的 drawable
方面:
#include< iostream>
class Image {};
class Sprite {};
class Model3D {};
命名空间draw_aspect
{
void draw(Image const& image){std :: cout<<< 画图 }
void draw(Sprite const& sprite){std :: cout<<< 画精灵; }
void draw(Model3D const& model3D){std :: cout<<< drawing model3D\\\
;
}
现在,三个单独的向量(这可能是最佳的,取决于集合之间的对象之间的顺序关系?),或考虑一个变体类型向量:
1。使用变体类型
#include< boost / variant.hpp>
使用SceneObject = boost :: variant< Image,Sprite,Model3D> ;;
命名空间draw_aspect {
struct draw_visitor:boost :: static_visitor<> {
template< typename T> void operator()(T const& t)const {draw(t); }
};
void draw(SceneObject const& sobj){
static const draw_visitor _vis;
boost :: apply_visitor(_vis,sobj);
}
}
后者的一个完整的概念证明:
#include< vector>
class SceneManager //控制世界游戏中的所有内容
{
public:
void Add(SceneObject v){_worldObjects.emplace_back(std :: move (ⅴ)); }
friend void draw(SceneManager const& sm){return sm.draw();
private:
void draw()const {
for(auto& sobj:_worldObjects)
draw_aspect :: draw(sobj);
}
std :: vector< SceneObject> _worldObjects; //包含所有的
}的向量;
int main()
{
SceneManager sman;
sman.Add(Image());
sman.Add(Sprite());
sman.Add(Model3D());
sman.Add(Image());
draw(sman);
}
输出
绘图图像
绘图精灵
绘图模型3D
绘图图像
2。单独的集合
使用单独向量的替代方法:
class SceneManager //控制世界游戏中的所有内容
{
public:
void Add(Image v){_images .emplace_back(std :: move(v)); }
void Add(Sprite v){_sprites .emplace_back(std :: move(v)); }
void Add(Model3D v){_model3Ds.emplace_back(std :: move(v)); }
friend void draw(SceneManager const& sm){return sm.draw(); }
private:
void draw()const {
for(auto& sobj:_images)draw_aspect :: draw(sobj); (auto& sobj:_sprites)
draw_aspect :: draw(sobj); (auto& sobj:_model3D)
draw_aspect :: draw(sobj);
}
std :: vector< Image> _图片;
std :: vector&Sprite> _sprites;
std :: vector< Model3D> _model3Ds;
};
int main()
{
SceneManager sman;
sman.Add(Image());
sman.Add(Sprite());
sman.Add(Model3D());
sman.Add(Image());
draw(sman);
}
请注意,输出为不同(排序) :
绘图图像
绘图图像
绘图精灵
绘图model3D
I'm coding a game engine and I have this class set up for objects:
class SceneManager //controls everything in the "world" game
{
public:
void Add(SceneObject* object); //adds to the vector
private:
vector<SceneObject*> _worldObjects; //the vector that contains all of them
}
And all classes I work on the game inherit from SceneObject:
class SceneObject
{
public:
virtual void Draw() = 0;
}
class Image : public SceneObject
{ }
class Sprite : public SceneObject
{ }
class Model3D : public SceneObject
{ }
So I know I can call Draw() for all objects in my vector.But I've been working on optimizations and I'm trying to get rid of all inheritance and virtual functions, and use composition instead, since they can't be inlined and seems to be a major performance issue when performed on a per-object basis.
I'm looking for some C++ technique that I can use to be able to store a bunch of SceneObjects in my vector, and then call Draw() on it and it properly draws the object related to it. This will also work for the Update() function I'm using as virtual.
So this code:
void SceneManager::Add(SceneObject* object)
{
_worldObjects.push_back(object);
}
void SceneManager::DrawTheWorld()
{
for(unsigned int i = 0; i < _worldObjects.size(); i++)
{
_worldObjects[i]->Draw(); //SceneObject's being called
}
}
...would become:
void SceneManager::Add(Image* image)
{
SceneObject* object = new SceneObject();
//link object to image somehow, tried to use it as a member of image
_worldObjects.push_back(object);
}
void SceneManager::DrawTheWorld()
{
for(unsigned int i = 0; i < _worldObjects.size(); i++)
{
//_worldObjects[i]->
//I need somehow to be able to get the pointer back to the original class
//It can be an image, sprite, model3d, anything
}
}
I don't think if I add a switch or if/elses and removing the virtual I'd gain any performance, so I'm trying to figure if there's a clean way to deal with this.
Any ideas?
You can use free functions to model the drawable
aspect of your objects:
#include <iostream>
class Image { };
class Sprite { };
class Model3D { };
namespace draw_aspect
{
void draw(Image const& image) { std::cout << "drawing image\n"; }
void draw(Sprite const& sprite) { std::cout << "drawing sprite\n"; }
void draw(Model3D const& model3D) { std::cout << "drawing model3D\n"; }
}
Now, either use three separate vectors (this could well be most optimal, depending on the ordering relationship between the objects across collections?), or consider a variant type vector:
1. Using variant types
#include <boost/variant.hpp>
using SceneObject = boost::variant<Image, Sprite, Model3D>;
namespace draw_aspect {
struct draw_visitor : boost::static_visitor<> {
template <typename T> void operator()(T const& t) const { draw(t); }
};
void draw(SceneObject const& sobj) {
static const draw_visitor _vis;
boost::apply_visitor(_vis, sobj);
}
}
A complete proof of concept of the latter: Live on Coliru
#include <vector>
class SceneManager //controls everything in the "world" game
{
public:
void Add(SceneObject v) { _worldObjects.emplace_back(std::move(v)); }
friend void draw(SceneManager const& sm) { return sm.draw(); }
private:
void draw() const {
for(auto& sobj : _worldObjects)
draw_aspect::draw(sobj);
}
std::vector<SceneObject> _worldObjects; //the vector that contains all of them
};
int main()
{
SceneManager sman;
sman.Add(Image());
sman.Add(Sprite());
sman.Add(Model3D());
sman.Add(Image());
draw(sman);
}
Outputs
drawing image
drawing sprite
drawing model3D
drawing image
2. Separate collections
The alternative using separate vectors: Live on Coliru
class SceneManager //controls everything in the "world" game
{
public:
void Add(Image v) { _images .emplace_back(std::move(v)); }
void Add(Sprite v) { _sprites .emplace_back(std::move(v)); }
void Add(Model3D v) { _model3Ds.emplace_back(std::move(v)); }
friend void draw(SceneManager const& sm) { return sm.draw(); }
private:
void draw() const {
for(auto& sobj : _images) draw_aspect::draw(sobj);
for(auto& sobj : _sprites) draw_aspect::draw(sobj);
for(auto& sobj : _model3Ds) draw_aspect::draw(sobj);
}
std::vector<Image> _images;
std::vector<Sprite> _sprites;
std::vector<Model3D> _model3Ds;
};
int main()
{
SceneManager sman;
sman.Add(Image());
sman.Add(Sprite());
sman.Add(Model3D());
sman.Add(Image());
draw(sman);
}
Note that the output is different (ordering):
drawing image
drawing image
drawing sprite
drawing model3D
这篇关于生成没有虚拟功能的接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!