3

我有一个游戏引擎,我将物理模拟与游戏对象功能分开。所以我有一个物理身体的纯虚拟课程

class Body

我将从中推导出物理模拟的各种实现。我的游戏对象类看起来像

class GameObject {
public:
   // ...
private:
   Body *m_pBody;
};

我可以插入该特定游戏所需的任何实现。但是Body当我只有一个GameObject. 所以我发现自己写了很多东西,比如

Vector GameObject::GetPosition() const { return m_pBody->GetPosition(); }

我很想把所有这些都抓起来,然后做类似的事情

pObject->GetBody()->GetPosition();

但这似乎是错误的(即违反了得墨忒耳法则)。另外,它只是将详细程度从实现推到了使用。所以我正在寻找一种不同的方式来做到这一点。

4

4 回答 4

3

您可以采取的一种方法是将Body接口拆分为多个接口,每个接口都有不同的用途,并GameObject仅授予它必须公开的接口的所有权。

class Positionable;
class Movable;
class Collidable;
//etc.

具体Body实现可能会实现所有接口,但GameObject只需要公开其位置的只会引用(通过依赖注入)Positionable接口:

class BodyA : public Positionable, Movable, Collidable {
    // ...
};

class GameObjectA {
private:
    Positionable *m_p;
public:
    GameObjectA(Positionable *p) { m_p = p; }
    Positionable *getPosition() { return m_p; }
};

BodyA bodyA;
GameObjectA objA(&bodyA);

objA->getPosition()->getX();
于 2009-01-22T05:11:48.583 回答
3

The idea of the law of Demeter is that your GameObject isn't supposed to have functions like GetPosition(). Instead it's supposed to have MoveForward(int) or TurnLeft() functions that may call GetPosition() (along with other functions) internally. Essentially they translate one interface into another.

If your logic requires a GetPosition() function, then it makes sense turn that into an interface a la Ates Goral. Otherwise you'll need to rethink why you're grabbing so deeply into an object to call methods on its subobjects.

于 2009-01-22T08:37:53.003 回答
1

游戏层次结构不应涉及大量继承。我无法将您指向任何网页,但这是我从多个来源收集到的感觉,其中最著名的是游戏宝石系列。

You can have hierarchies like ship->tie_fighter, ship->x_wing. But not PlaysSound->tie_fighter. Your tie_fighter class should be composed of the objects it needs to represent itself. A physics part, a graphics part, etc. You should provide a minimal interface for interacting with your game objects. Implement as much physics logic in the engine or in the physic piece.

With this approach your game objects become collections of more basic game components.

All that said, you will want to be able to set a game objects physical state during game events. So you'll end up with problem you described for setting the various pieces of state. It's just icky but that is best solution I've found so far.

I've recently tried to make higher level state functions, using ideas from Box2D. Have a function SetXForm for setting positions etc. Another for SetDXForm for velocities and angular velocity. These functions take proxy objects as parameters that represent the various parts of the physical state. Using methods like these you could reduce the number of methods you'd need to set state but in the end you'd probably still end up implementing the finer grained ones, and the proxy objects would be more work than you would save by skipping out on a few methods.

So, I didn't help that much. This was more a rebuttal of the previous answer.

In summary, I would recommend you stick with the many method approach. There may not always be a simple one to 1 relationship between game objects and physic objects. We ran into that where it was much simpler to have one game object represent all of the particles from an explosion. If we had given in and just exposed a body pointer, we would not have been able to simplify the problem.

于 2009-01-22T06:08:06.410 回答
0

Do I understand correctly that you're separating the physics of something from it's game representation?

i.e, would you see something like this:

class CompanionCube
{
    private:
        Body* m_pPhysicsBody;
};

?

If so, that smells wrong to me. Technically your 'GameObject' is a physics object, so it should derive from Body.

It sounds like you're planning on swapping physics models around and that's why you're attempting to do it via aggregation, and if that's the case, I'd ask: "Do you plan on swapping physics types at runtime, or compile time?".

If compile time is your answer, I'd derive your game objects from Body, and make Body a typedef to whichever physics body you want to have be the default.

If it's runtime, you'd have to write a 'Body' class that does that switching internally, which might not be a bad idea if your goal is to play around with different physics.

Alternatively, you'll probably find you'll have different 'parent' classes for Body depending on the type of game object (water, rigid body, etc), so you could just make that explicit in your derivation.

Anyhow, I'll stop rambling since this answer is based on a lot of guesswork. ;) Let me know if I'm off base, and I'll delete my answer.

于 2009-01-22T06:53:14.243 回答