【发布时间】:2011-04-19 05:32:23
【问题描述】:
我想让编译器为物理碰撞系统建立函数连接。我有测试碰撞功能:
template <typename T, typename U>
inline void Collision(T& t, U& u)
{
if(u.CheckCollision(t.GetCollider()))
{
u.HitBy(t);
t.Hit(u);
}
}
然后我使用一个碰撞器对象来保存碰撞对象。
template <typename T>
class Collidable
{
T m_Collider;
VictimEffect m_HitBy;
MenaceEffect m_Hit;
public:
void SetCollider(const T& t) { m_Collider = t; }
void SetVictim(VictimEffect effect) { m_HitBy = effect; }
void SetMenace(MenaceEffect effect) { m_Hit = effect; }
T& GetCollider()
{
return m_Collider;
}
template <typename V>
void HitBy(V& menace)
{
m_HitBy.HitBy(menace.GetCollider());
}
template <typename V>
void Hit(V& victim)
{
m_Hit.Hit(victim.GetCollider());
}
template <typename V>
bool CheckCollision(V& menace)
{
return m_Collider.CheckCollision(menace);
}
};
我为效果函数添加了一个间接级别
class VictimEffect
{
public:
template<typename C>
void HitBy(C&)
{;}
};
class MenaceEffect
{
public:
template<typename C>
void Hit(C&)
{;}
};
我最终想要的是一种在具有正确函数签名但不需要不会命中的类型的任何对象中调用函数的方法。
class Wall;
class Ball : public MenaceEffect
{
public:
void Hit(Wall& wall);
void Hit(Ball& ball);
};
class Wall : public VictimEffect
{
public:
void HitBy(Ball& ball);
};
请注意,我不想让墙撞墙的功能。我只想为应该发生的交互编写或提供函数。我知道这不起作用,因为 VictimEffect 没有“看到”派生函数。
我想分派而不必在任何使用它们的地方指定模板参数。我想在可碰撞之外构建我的可碰撞效果,并将其一般地赋予可碰撞对象。我不想为每个可以碰撞的事物集合使用不同的可碰撞对象。基本上我想要
vector<collidable> movingThings;
vector<collidable> staticThings;
// get iterators ...
Collide(Moving, Static);
我在这里需要更多的间接层,但我就是看不到它。我知道这是可以做到的,因为所有信息在编译时都可用。不需要动态多态解决方案。
非常感谢任何帮助!
更新 我想做的是建立自己的现代(如安德烈的书)游戏库。到目前为止,我已经解决了大部分关系,但这一个让我难过。这不是时间关键问题,而是结果关键问题。我从事游戏工作很多年了,我不喜欢我从事过的任何游戏引擎。这意味着易于使用且易于扩展。现在控制台编译器已经变得不那么糟糕了,它可以在任何平台上运行。
这是我想要写的一个简单的例子。
int main()
{
// System must come first
System system(640, 480, false);
Renderer renderer;
Mouse mouse;
Keyboard keys;
// Make the ball
Bounce ball;
Sprite ballSprite("02.bmp");
CollisionBox ballPhysics;
BallCommand ballBehavior;
ball.SpriteMover = boost::bind(&Sprite::Observer<Pos2D>, &ballSprite, _1);
ball.PhysicsMover = boost::bind(&CollisionBox::Move, &ballPhysics, _1);
// Make the bounds
Boundary bounds;
// Set up Physics
Collidable<Boundary> boundC;
boundC.SetCollider(bounds);
boundC.SetVictim(ballBehavior);
Collidable<CollisionBox> ballC;
ballC.SetCollider(ballPhysics);
PretendPhysics physics;
physics.SetBall(ballC);
physics.SetBounds(boundC);
while(!mouse.LeftClick() && !keys.AnyKey())
{
ball.MoveRel(ballBehavior.Delta());
physics.Update();
renderer.Clear();
renderer.Render(ballSprite);
renderer.SwapBuffers();
}
}
所有的物理都是在制品,不是我希望它结束的地方,但它正在到达那里。 System object 初始化 Windows 和平台特定的渲染器。在这种情况下,它是 openGL。尽管它被编译为控制台应用程序,但它会创建所有 Windows 组件。我不想让人们处理 main() 与 winmain()。除了物理,没有继承。在我将场景导入系统后,三个渲染调用将被替换为一个。我计划使用我不久前写的东西,结合 Gary Powell 和 Martin Weiser 的 View 模板库。
我知道我只是看的不对。访客可以帮助改变我的方法。
这就是我想要做的。
更新 2 好的。到目前为止,我从 cmets 和答案中得到了一些启发,这就是我去的地方,但我还没有完成。
template <typename T, typename V = VictimEffect, typename M = MenaceEffect>
class Collidable
{
T m_Collider;
V m_HitBy;
M m_Hit;
public:
Collidable(T collide, V victim, M menace) : m_Collider(collide), m_HitBy(victim), m_Hit(menace) {;}
Collidable(T collide) : m_Collider(collide) {;}
Collidable(T collide, V victim) : m_Collider(collide), m_HitBy(victim) {;}
T& GetCollider()
{
return m_Collider;
}
template <typename V>
void HitBy(V& menace)
{
m_HitBy.HitBy(menace.GetCollider());
}
template <typename V>
void Hit(V& victim)
{
m_Hit.Hit(victim.GetCollider());
}
template <typename V>
bool CheckCollision(V& menace)
{
return m_Collider.CheckCollision(menace);
}
};
然后使用它我这样做
Collidable<Boundary, BallCommand> boundC(bounds, ballBehavior);
Collidable<CollisionBox> ballC(ballPhysics);
无所不在是对的。通过传入基础,我丢失了类型信息。现在基地在那里只是为了捕捉我不关心的东西。
对于我的容器,我认为我可以使用类型列表来收集添加到容器中的每种类型,并使用它来声明特定类型的容器,然后处理信息。一个问题是我不能取出普通的迭代器,传递函数对象会更容易。
也许 C++ 0X 可以帮助处理这个新的未知类型变量。 (忘记叫什么了)。
【问题讨论】:
-
我不相信这些信息在编译时可用。通过将基类实例(或者,更可能是引用派生实例的基类型的引用(一般意义上的指针计数))放入向量中,它已从编译时知识中“删除”。我认为您以某种方式无法使用虚函数。
-
我知道,一旦我进行了继承,信息就会丢失,而且我知道将所有内容都放入一个集合中还有进一步的挑战。也许在那一点上它不能完成,但至于触发一个具有共同签名且仅在参数上有所不同的事件。我认为这是可以做到的。我可以用 Ball 和 Wall 做到这一点,但如果有意义的话,我不能用 (Ball Wall) 做一个对象,而用 Wall 做另一个对象。我也可以通过专门研究所有可能的结果来做到这一点,但这很乏味。
-
@Tavison - 一旦你开始使用虚函数,类访问者模式似乎会得到你想要的。
-
Tavison 你能更好地解释一下你想做什么吗?我不明白你的问题。给我们 Collidable 和 Victim/MenaceEffect 之间关系的完整代码?
-
这可能有助于正确的方向。我已经成功地将观察者模式模板化,以使用命令模式移动物理和渲染对象。我不急于寻求解决方案。这更像是 Andrei 的书试图为游戏引擎设计寻找纯粹的通用解决方案。我在业余时间构建了一个现代游戏引擎,因为我讨厌迄今为止我使用过的所有引擎。感谢访客提示。我在 Modern C++ Design 中看到 Andrei 有一个访问者模板。很好的帮助。
标签: c++ templates game-physics double-dispatch