1

I'm using a factory to create Shape instances for a physics engine. The size of each shape is not known until construction time, hence a factory being used in place of stack memory + cloning. A Shape is then supplied to the physics Scene to create a Body:

// Sphere derives from Shape
Sphere *s = Scene.CreateSphere( radius );

// Construct a rigid body with a certain shape
Body *b = Scene.CreateBody( s );

The issue: I wish for each Shape to be associated with only one Body at any given time. I need to disallow the user from doing this:

Body *b1 = scene.CreateBody( );
Body *b2 = scene.CreateBody( );
Shape *s = scene.CreateBox( 1.0f, 1.0f, 1.0f );
b1->AddShape( s );
b2->AddShape( s ); // bad

Additional info: Expensive performance checks for pointer uniqueness would be best to be avoided, as performance is important here. However in debug mode performance hits for error checking are acceptable.

It is important to be able to construct shapes separately from creating bodies, as multiple shapes can be apart of an aggregate rigid body:

Body *b = Scene.CreateBody( );
b->AddShape( shapePtr1 );
b->AddShape( shapePtr2 );

Shape instances should also be able to be transferred from one Body to another during run-time;

Body *b1, b2; // initialized elsewhere
Shape *s;     // initialized elsewhere, is attached to b1
b1->RemoveShape( s );
b2->AddShape( s );

Perhaps I should go about a different api design? Perhaps cloning could be used somehow?

4

2 回答 2

1

First, make all your Create*() functions take a Body parameter, as a form of dependency inversion.

Then you can only create a Shape for a single Body. You can also assert or otherwise error out if you try to create a Shape on a Body that already has a shape.

You can support the moving of Shape objects with the simple requirement that the destination Body does not already have an attached Shape. Do not have a DetachShape, which would allow "dangling" shapes, but rather simply a MoveShapeTo and a ReleaseShape. Alternatively, just use a smart pointer of some variety to ensure that "dangling" shapes are cleaned up properly, if that's your primary worry.

于 2013-07-20T01:34:05.190 回答
1

Make Body::AddShape(...) private, and remove the ctor that takes a Shape* argument.

void Body::AddSphere(float radius)
{
  AddShape(Scene.CreateSphere(radius));
}

void Body::transferShape(Shape *s, Body &B2)
{
  RemoveShape( s );
  B2.AddShape( s );
}

// Construct a rigid body with no Shapes (yet)
Body *b = Scene.CreateBody();

// Give it a Sphere
b->AddSphere(radius);

// Transfer it to another body:
Body *b2 = Scene.CreateBody();
Shape *s = b->GetShapePointerSomehow();
b->transferShape(s, *b2);

Note that there is no way to add a preexisting Shape to a Body without removing it from another Body. No outside code can cause two Bodies to contain the same Shape.

于 2013-07-20T01:38:49.817 回答