Is there a better solution to update part of the compound body?
How would you go about doing this?
You can indeed avoid recreating the vehicle body if all you want to do is adjust the effective weight of subshapes.
The CompoundShape.Shapes list provides a read-only view of the CompoundShapeEntry objects used to create the CompoundShape. You'll probably want to keep a redundant list of CompoundShapeEntry objects handy, or just copy the list of CompoundShapeEntry objects from the CompoundShape.Shapes list into your own list when needed. Then, you can make whatever weight modifications you need to your mutable list, and give that list to the static CompoundShape.ComputeVolumeDistribution method.
The CompoundShape.ComputeVolumeDistribution method will return the new inertia tensor (unscaled by mass) and the new center of mass. Multiply the computed Matrix3x3 by the mass of the whole vehicle and set the result to the entity's LocalInertiaTensor.
Then, offset the vehicle body's shape by setting the vehicle.Body.CollisionInformation.LocalPosition to -newCenter. This will ensure that the newly computed center of the shape will be aligned with the center of mass. The collidable's offset is used by the Vehicle to position wheels, so no modifications to the wheel suspensions should be necessary.
Of course, there's still one problem to be addressed:
The issue is that when I do that, the wheels sometimes sink in the ground for a second then go back to their correct place. (my vehicle is quite heavy)
This is likely related to the fact that changing up these settings or recreating the entity with a new and different shape will actually scoot the shape around, even though the Entity.Position does not change. The Entity.Position must be scooted to compensate for changes made to the shape position.
The whole process looks like this:
Code: Select all
var bodies = new List<CompoundShapeEntry>
{
new CompoundShapeEntry(new BoxShape(2.5f, .75f, 4.5f), new Vector3(0, 0, 0), 60),
new CompoundShapeEntry(new BoxShape(2.5f, .3f, 2f), new Vector3(0, .75f / 2 + .3f / 2, .5f), 1)
};
compoundShape = new CompoundShape(bodies);
var body = new Entity(compoundShape, 61);
body.Position = position;
defaultShapeOffset = new Vector3(0, 0.5f, 0);
body.CollisionInformation.LocalPosition = defaultShapeOffset;
//This will hold our mutable view of the entries for computation.
mutableShapeEntries = new CompoundShapeEntry[compoundShape.Shapes.Count];
Vehicle = new Vehicle(body);
//... Later, at runtime, modify the effective weight...
private void IncreaseWeight()
{
compoundShape.Shapes.CopyTo(mutableShapeEntries, 0);
//Make the car-hat super heavy relative to the base!
mutableShapeEntries[1].Weight += (extraWeight += 20);
Vector3 newCenter;
var volumeDistribution = CompoundShape.ComputeVolumeDistribution(mutableShapeEntries, out newCenter);
Vehicle.Body.LocalInertiaTensor = volumeDistribution * Vehicle.Body.Mass;
var previousLocalPosition = Vehicle.Body.CollisionInformation.LocalPosition;
Vehicle.Body.CollisionInformation.LocalPosition = defaultShapeOffset - newCenter;
//Compensate for the vehicle body movement; to make sure the shape stays in the same spot, scoot the entity position itself.
Vehicle.Body.Position -= Vector3.Transform(Vehicle.Body.CollisionInformation.LocalPosition - previousLocalPosition, Vehicle.Body.Orientation);
}
You'll need to update to the very latest
development version for this to compile/work, though.