mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-04 20:38:24 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
285 lines
7.6 KiB
C#
285 lines
7.6 KiB
C#
|
|
namespace Sandbox;
|
|
|
|
public sealed partial class ModelPhysics
|
|
{
|
|
/// <summary>
|
|
/// Create all the bodies, colliders and joints.
|
|
/// </summary>
|
|
private void CreatePhysics()
|
|
{
|
|
if ( !Active ) return;
|
|
if ( IsProxy ) return;
|
|
if ( PhysicsWereCreated ) return;
|
|
|
|
DestroyPhysics();
|
|
|
|
if ( !Model.IsValid() ) return;
|
|
|
|
var physics = Model.Physics;
|
|
if ( physics is null || physics.Parts.Count == 0 )
|
|
return;
|
|
|
|
PhysicsRebuildCount++;
|
|
|
|
var componentFlags = ComponentFlags.None;
|
|
|
|
if ( Scene.IsEditor )
|
|
{
|
|
componentFlags |= ComponentFlags.NotEditable;
|
|
}
|
|
|
|
var world = WorldTransform;
|
|
|
|
CreateParts( physics, world, componentFlags );
|
|
CreateJoints( physics, componentFlags );
|
|
|
|
foreach ( var body in Bodies )
|
|
{
|
|
body.Component.Enabled = true;
|
|
Network?.Refresh( body.Component );
|
|
}
|
|
|
|
foreach ( var joint in Joints )
|
|
{
|
|
joint.Component.Enabled = true;
|
|
Network?.Refresh( joint.Component );
|
|
}
|
|
|
|
PhysicsWereCreated = true;
|
|
}
|
|
|
|
private void CreateJoints( PhysicsGroupDescription physics, ComponentFlags componentFlags )
|
|
{
|
|
var jointFlags = componentFlags;
|
|
|
|
foreach ( var jointDesc in physics.Joints )
|
|
{
|
|
var body1 = Bodies[jointDesc.Body1];
|
|
var body2 = Bodies[jointDesc.Body2];
|
|
|
|
var localFrame1 = jointDesc.Frame1;
|
|
var localFrame2 = jointDesc.Frame2;
|
|
|
|
Sandbox.Joint joint = null;
|
|
|
|
if ( jointDesc.Type == PhysicsGroupDescription.JointType.Hinge )
|
|
{
|
|
var hingeJoint = body1.Component.AddComponent<HingeJoint>( false );
|
|
|
|
if ( jointDesc.EnableTwistLimit )
|
|
{
|
|
hingeJoint.MinAngle = jointDesc.TwistMin;
|
|
hingeJoint.MaxAngle = jointDesc.TwistMax;
|
|
}
|
|
|
|
if ( jointDesc.EnableAngularMotor )
|
|
{
|
|
var worldFrame1 = body1.Component.WorldTransform.ToWorld( localFrame1 );
|
|
var hingeAxis = worldFrame1.Rotation.Up;
|
|
var targetVelocity = hingeAxis.Dot( jointDesc.AngularTargetVelocity );
|
|
|
|
hingeJoint.Motor = HingeJoint.MotorMode.TargetVelocity;
|
|
hingeJoint.TargetVelocity = targetVelocity.RadianToDegree();
|
|
hingeJoint.MaxTorque = jointDesc.MaxTorque;
|
|
}
|
|
|
|
joint = hingeJoint;
|
|
}
|
|
else if ( jointDesc.Type == PhysicsGroupDescription.JointType.Ball )
|
|
{
|
|
var ballJoint = body1.Component.AddComponent<BallJoint>( false );
|
|
|
|
if ( jointDesc.EnableSwingLimit )
|
|
{
|
|
ballJoint.SwingLimitEnabled = true;
|
|
ballJoint.SwingLimit = new Vector2( jointDesc.SwingMin, jointDesc.SwingMax );
|
|
}
|
|
|
|
if ( jointDesc.EnableTwistLimit )
|
|
{
|
|
ballJoint.TwistLimitEnabled = true;
|
|
ballJoint.TwistLimit = new Vector2( jointDesc.TwistMin, jointDesc.TwistMax );
|
|
}
|
|
|
|
joint = ballJoint;
|
|
}
|
|
else if ( jointDesc.Type == PhysicsGroupDescription.JointType.Fixed )
|
|
{
|
|
var fixedJoint = body1.Component.AddComponent<FixedJoint>( false );
|
|
fixedJoint.LinearFrequency = jointDesc.LinearFrequency;
|
|
fixedJoint.LinearDamping = jointDesc.LinearDampingRatio;
|
|
fixedJoint.AngularFrequency = jointDesc.AngularFrequency;
|
|
fixedJoint.AngularDamping = jointDesc.AngularDampingRatio;
|
|
|
|
joint = fixedJoint;
|
|
}
|
|
else if ( jointDesc.Type == PhysicsGroupDescription.JointType.Slider )
|
|
{
|
|
var sliderJoint = body1.Component.AddComponent<SliderJoint>( false );
|
|
|
|
if ( jointDesc.EnableLinearLimit )
|
|
{
|
|
sliderJoint.MinLength = jointDesc.LinearMin;
|
|
sliderJoint.MaxLength = jointDesc.LinearMax;
|
|
}
|
|
|
|
var rot = Rotation.FromPitch( -90 );
|
|
localFrame1 = localFrame1.WithRotation( rot * localFrame1.Rotation );
|
|
localFrame2 = localFrame2.WithRotation( rot * localFrame2.Rotation );
|
|
|
|
joint = sliderJoint;
|
|
}
|
|
|
|
if ( joint.IsValid() )
|
|
{
|
|
joint.Flags |= jointFlags;
|
|
joint.Body = body2.Component.GameObject;
|
|
joint.Attachment = Sandbox.Joint.AttachmentMode.LocalFrames;
|
|
joint.LocalFrame1 = localFrame1.WithPosition( jointDesc.Frame1.Position * body1.Component.WorldScale );
|
|
joint.LocalFrame2 = localFrame2.WithPosition( jointDesc.Frame2.Position * body2.Component.WorldScale );
|
|
joint.EnableCollision = jointDesc.EnableCollision;
|
|
joint.BreakForce = jointDesc.LinearStrength;
|
|
joint.BreakTorque = jointDesc.AngularStrength;
|
|
|
|
Joints.Add( new Joint( joint, body1, body2, localFrame1, localFrame2 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateParts( PhysicsGroupDescription physics, Transform world, ComponentFlags componentFlags )
|
|
{
|
|
var boneObjects = Model.CreateBoneObjects( GameObject );
|
|
var bones = Model.Bones;
|
|
var bodyFlags = componentFlags;
|
|
var colliderFlags = componentFlags;
|
|
|
|
foreach ( var part in physics.Parts )
|
|
{
|
|
var bone = bones.GetBone( part.BoneName );
|
|
if ( !boneObjects.TryGetValue( bone, out var go ) )
|
|
continue;
|
|
|
|
if ( !go.Flags.Contains( GameObjectFlags.Absolute | GameObjectFlags.PhysicsBone ) )
|
|
{
|
|
go.Flags |= GameObjectFlags.Absolute | GameObjectFlags.PhysicsBone;
|
|
|
|
if ( !Renderer.IsValid() || !Renderer.TryGetBoneTransform( bone, out var boneWorld ) )
|
|
{
|
|
// There's no renderer bones, use physics bind pose
|
|
boneWorld = world.ToWorld( part.Transform );
|
|
}
|
|
|
|
go.WorldTransform = boneWorld;
|
|
}
|
|
|
|
var body = go.AddComponent<Rigidbody>( false );
|
|
body.Flags |= bodyFlags;
|
|
body.RigidbodyFlags = RigidbodyFlags;
|
|
body.Locking = Locking;
|
|
body.MotionEnabled = MotionEnabled;
|
|
body.LinearDamping = part.LinearDamping;
|
|
body.AngularDamping = part.AngularDamping;
|
|
body.StartAsleep = StartAsleep;
|
|
body.MassOverride = part.Mass;
|
|
body.OverrideMassCenter = part.OverrideMassCenter;
|
|
body.MassCenterOverride = part.MassCenterOverride;
|
|
body.GameObjectSource = GameObject;
|
|
|
|
var bodyTransform = body.WorldTransform;
|
|
|
|
BodyTransforms.Set( Bodies.Count, bodyTransform );
|
|
Bodies.Add( new Body( body, bone.Index, WorldTransform.ToLocal( bodyTransform ) ) );
|
|
|
|
foreach ( var sphere in part.Spheres )
|
|
{
|
|
var collider = go.AddComponent<SphereCollider>();
|
|
collider.Flags |= colliderFlags;
|
|
collider.Center = sphere.Sphere.Center;
|
|
collider.Radius = sphere.Sphere.Radius;
|
|
collider.Surface = sphere.Surface;
|
|
}
|
|
|
|
foreach ( var capsule in part.Capsules )
|
|
{
|
|
var collider = go.AddComponent<CapsuleCollider>();
|
|
collider.Flags |= colliderFlags;
|
|
collider.Start = capsule.Capsule.CenterA;
|
|
collider.End = capsule.Capsule.CenterB;
|
|
collider.Radius = capsule.Capsule.Radius;
|
|
collider.Surface = capsule.Surface;
|
|
}
|
|
|
|
foreach ( var hull in part.Hulls )
|
|
{
|
|
var collider = go.AddComponent<HullCollider>();
|
|
collider.Flags |= colliderFlags;
|
|
collider.Type = HullCollider.PrimitiveType.Points;
|
|
collider.Points = hull.GetPoints().ToList();
|
|
collider.Surface = hull.Surface;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Destroy all the bodies, colliders and joints.
|
|
/// </summary>
|
|
private void DestroyPhysics()
|
|
{
|
|
if ( Renderer.IsValid() )
|
|
{
|
|
Renderer.ClearPhysicsBones();
|
|
}
|
|
|
|
BodyTransforms.Clear();
|
|
|
|
if ( !PhysicsWereCreated )
|
|
return;
|
|
|
|
PhysicsDestroyCount++;
|
|
|
|
foreach ( var joint in Joints )
|
|
{
|
|
if ( !joint.Component.IsValid() )
|
|
continue;
|
|
|
|
joint.Component.Destroy();
|
|
|
|
Network?.Refresh( joint.Component );
|
|
}
|
|
|
|
foreach ( var collider in GetComponentsInChildren<Collider>( true ) )
|
|
{
|
|
if ( !collider.IsValid() ) continue;
|
|
if ( !collider.GameObject.Flags.Contains( GameObjectFlags.PhysicsBone ) ) continue;
|
|
|
|
collider.Destroy();
|
|
|
|
Network?.Refresh( collider );
|
|
}
|
|
|
|
foreach ( var body in Bodies )
|
|
{
|
|
if ( !body.Component.IsValid() )
|
|
continue;
|
|
|
|
body.Component.GameObject.Flags &= ~GameObjectFlags.Absolute;
|
|
body.Component.GameObject.Flags &= ~GameObjectFlags.PhysicsBone;
|
|
body.Component.Destroy();
|
|
|
|
Network?.Refresh( body.Component );
|
|
}
|
|
|
|
Bodies.Clear();
|
|
Joints.Clear();
|
|
|
|
PhysicsWereCreated = false;
|
|
}
|
|
|
|
internal void OnModelReloaded()
|
|
{
|
|
DestroyPhysics();
|
|
CreatePhysics();
|
|
}
|
|
}
|