using NativeEngine;
namespace Sandbox
{
///
/// Represents a set of PhysicsBody objects. Think ragdoll.
///
[Expose, ActionGraphIgnore]
public sealed class PhysicsGroup : IHandle
{
#region IHandle
//
// A pointer to the actual native object
//
internal IPhysAggregateInstance native;
//
// IHandle implementation
//
internal int HandleValue { get; set; }
void IHandle.HandleInit( IntPtr ptr )
{
native = ptr;
}
void IHandle.HandleDestroy()
{
native = IntPtr.Zero;
}
bool IHandle.HandleValid() => !native.IsNull;
#endregion
internal PhysicsGroup() { }
internal PhysicsGroup( HandleCreationData _ ) { }
///
/// The world in which this group belongs
///
[ActionGraphInclude]
public PhysicsWorld World => native.GetWorld();
///
/// Returns position of the first physics body of this group, or zero vector if it has none.
///
///
/// TODO: How useful is this in its current form? Should it be removed, or at least renamed to Position?
///
public Vector3 Pos
{
get => native.GetOrigin();
}
///
/// Returns the center of mass for this group of physics bodies.
///
[ActionGraphInclude]
public Vector3 MassCenter
{
get => native.GetMassCenter();
}
///
/// Adds given amount of velocity () to all physics bodies in this group.
///
/// How much linear force to add?
[ActionGraphInclude]
public void AddVelocity( Vector3 vel )
{
native.AddVelocity( vel );
}
///
/// Adds given amount of angular velocity to all physics bodies in this group.
///
/// How much angular force to add?
[ActionGraphInclude]
public void AddAngularVelocity( Vector3 vel )
{
native.AddAngularVelocity( vel );
}
///
/// Adds given amount of linear impulse () to all physics bodies in this group.
///
/// Velocity to apply.
/// Whether to multiply the velocity by mass of the on a per-body basis.
[ActionGraphInclude]
public void ApplyImpulse( Vector3 vel, bool withMass = false )
{
for ( int i = 0; i < BodyCount; ++i )
{
var body = GetBody( i );
if ( !body.IsValid() )
continue;
if ( withMass )
{
body.ApplyImpulse( vel * body.Mass );
}
else
{
body.ApplyImpulse( vel );
}
}
}
///
/// Adds given amount of angular linear impulse () to all physics bodies in this group.
///
/// Angular velocity to apply.
/// Whether to multiply the velocity by mass of the on a per-body basis.
[ActionGraphInclude]
public void ApplyAngularImpulse( Vector3 vel, bool withMass = false )
{
for ( int i = 0; i < BodyCount; ++i )
{
var body = GetBody( i );
if ( !body.IsValid() )
continue;
if ( withMass )
{
body.ApplyAngularImpulse( vel * body.Mass );
}
else
{
body.ApplyAngularImpulse( vel );
}
}
}
///
/// Sets on all bodies of this group.
///
[ActionGraphInclude]
public Vector3 Velocity
{
set => native.SetVelocity( value );
}
///
/// Sets on all bodies of this group.
///
[ActionGraphInclude]
public Vector3 AngularVelocity
{
set => native.SetAngularVelocity( value );
}
///
/// Physics bodies automatically go to sleep after a certain amount of time of inactivity to save on performance.
/// You can use this to wake the body up, or prematurely send it to sleep.
///
[ActionGraphInclude]
public bool Sleeping
{
get => native.IsAsleep();
set
{
if ( value ) native.PutToSleep();
else native.WakeUp();
}
}
///
/// Calls on all bodies of this group.
///
public void RebuildMass()
{
for ( int i = 0; i < BodyCount; ++i )
{
var body = GetBody( i );
if ( !body.IsValid() )
continue;
body.RebuildMass();
}
}
///
/// The total mass of all the dynamic PhysicsBodies in this group.
/// When setting the total mass, it will be set on each body proportionally to each of their old masses,
/// i.e. if a body had 25% of previous total mass, it will have 25% of new total mass.
///
[ActionGraphInclude]
public float Mass
{
get => native.GetTotalMass();
set => native.SetTotalMass( value );
}
///
/// Sets on all bodies in this group.
///
[ActionGraphInclude]
public float LinearDamping
{
set => native.SetLinearDamping( value );
}
///
/// Sets on all bodies in this group.
///
[ActionGraphInclude]
public float AngularDamping
{
set => native.SetAngularDamping( value );
}
///
/// Returns all physics bodies that belong to this physics group.
///
[ActionGraphInclude]
public IEnumerable Bodies
{
get
{
var bodyCount = BodyCount;
for ( int i = 0; i < bodyCount; ++i )
yield return GetBody( i );
}
}
///
/// Returns amount of physics bodies that belong to this physics group.
///
[ActionGraphInclude]
public int BodyCount => native.GetBodyCount();
///
/// Gets a at given index within this physics group. See .
///
/// Index for the body to look up, in range from 0 to .
[ActionGraphInclude, Pure]
public PhysicsBody GetBody( int groupIndex ) => native.GetBodyHandle( groupIndex ); // Throw on OOB
///
/// Returns a by its within this group.
///
/// Name of the physics body to look up.
/// The physics body, or null if body with given name is not found.
[ActionGraphInclude, Pure]
public PhysicsBody GetBody( string groupName ) => native.FindBodyByName( groupName );
///
/// Any and all joints that are attached to any body in this group.
///
[ActionGraphInclude]
public IEnumerable Joints
{
get
{
var jointCount = native.GetJointCount();
for ( int i = 0; i < jointCount; ++i )
yield return native.GetJointHandle( i );
}
}
internal void RemoveJoint( PhysicsJoint joint )
{
if ( joint.IsValid() )
{
native.RemoveJoint( joint );
}
}
///
/// Sets the physical properties of each PhysicsShape of this group.
///
[ActionGraphInclude]
public void SetSurface( string name )
{
native.SetSurfaceProperties( name );
}
///
/// Delete this group, and all of its bodies
///
public void Remove()
{
var physicsWorld = native.GetWorld();
if ( physicsWorld is null ) return;
physicsWorld.native.DestroyAggregateInstance( this );
}
}
}