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 ); } } }