WorkInProgress/BobbleJoint.cs
using Sandbox.Physics;
/// <summary>
/// A joint which creates a "bobble head" type movement
/// </summary>
public sealed class BobbleJoint : Joint
{
private Sandbox.Physics.BallSocketJoint ballJoint;
private Sandbox.Physics.SpringJoint springJoint;
private float springDistance;
[Property, Range( 0, 10 )]
public float Springiness
{
get;
set
{
if ( field == value ) return;
field = value;
UpdateBallJoint();
UpdateSpringJoint();
}
} = 1.0f;
[Property, Range( 0, 50 )]
public float SpringFrequency
{
get;
set
{
if ( field == value ) return;
field = value;
UpdateBallJoint();
UpdateSpringJoint();
}
} = 5.0f;
[Property, Range( 0, 5 )]
public float Damping
{
get;
set
{
if ( field == value ) return;
field = value;
UpdateBallJoint();
UpdateSpringJoint();
}
} = 1.0f;
protected override PhysicsJoint CreateJoint( PhysicsPoint point1, PhysicsPoint point2 )
{
var originPoint = WorldPosition;
var springDir = (point1.Body.Transform.Position - originPoint);
if ( springDir.Length < 10.0f ) springDir = springDir.Normal * 10.0f;
if ( springDir.Length > 100.0f ) springDir = springDir.Normal * 100.0f;
// Join them at the origin point
point1.LocalRotation = point1.Body.Transform.RotationToLocal( Rotation.LookAt( springDir ) );
point2.LocalRotation = point2.Body.Transform.RotationToLocal( Rotation.LookAt( springDir ) );
point1.LocalPosition = point1.Body.Transform.PointToLocal( originPoint );
point2.LocalPosition = point2.Body.Transform.PointToLocal( originPoint );
ballJoint = PhysicsJoint.CreateBallSocket( point1, point2 );
point1.LocalPosition = point1.Body.Transform.PointToLocal( originPoint + springDir * 0.5f );
point2.LocalPosition = point2.Body.Transform.PointToLocal( originPoint + springDir * -0.5f );
springDistance = point1.Transform.Position.Distance( point2.Transform.Position );
springJoint = PhysicsJoint.CreateSpring( point1, point2, springDistance, springDistance );
springJoint.SpringLinear = new PhysicsSpring { Damping = 0, Frequency = 3 };
UpdateBallJoint();
UpdateSpringJoint();
return ballJoint;
}
void UpdateBallJoint()
{
if ( !ballJoint.IsValid() )
return;
ballJoint.Friction = Damping;
ballJoint.SwingLimitEnabled = true;
ballJoint.SwingLimit = 80;
ballJoint.TwistLimitEnabled = false;
ballJoint.TwistLimit = new Vector2( -10, 10 );
}
void UpdateSpringJoint()
{
if ( !springJoint.IsValid() )
return;
springJoint.SpringLinear = new PhysicsSpring { Damping = Damping, Frequency = Springiness };
springJoint.MinLength = springDistance + springDistance * Springiness;
springJoint.MaxLength = springDistance + springDistance * Springiness;
}
protected override void DestroyJoint()
{
base.DestroyJoint();
springJoint?.Remove();
springJoint = null;
}
}