Component that waits until a newly created ragdoll has ModelPhysics bodies, then applies a single impulse distributed evenly across those physics bodies and destroys itself.
using Sandbox;
using System.Linq;
/// <summary>
/// Waits for a newly created ragdoll's physics bodies, distributes an impulse
/// across them once, then removes itself.
/// </summary>
public sealed class RagdollImpulseApplier : Component
{
public Vector3 Impulse { get; set; }
protected override void OnUpdate()
{
// Only the network owner simulates and pushes the ragdoll. Proxies receive
// the resulting ModelPhysics transforms from that authoritative instance.
if ( IsProxy )
return;
if ( Impulse.LengthSquared <= 0f )
{
Destroy();
return;
}
var modelPhysics = GetComponent<ModelPhysics>();
if ( modelPhysics is null || modelPhysics.Bodies is null )
return;
// ModelPhysics keeps ragdoll rigidbodies in its Bodies collection rather
// than exposing them as normal components in the GameObject hierarchy.
var bodies = modelPhysics.Bodies
.Where( body => body.Component.IsValid() && body.Component.PhysicsBody.IsValid() )
.ToArray();
if ( bodies.Length == 0 )
return;
// Divide the total impulse across all bones so models with more physics
// bodies do not receive a proportionally stronger launch.
var impulsePerBody = Impulse / bodies.Length;
foreach ( var body in bodies )
body.Component.PhysicsBody.ApplyImpulse( impulsePerBody );
Destroy();
}
}