137 lines
5.1 KiB
C#
137 lines
5.1 KiB
C#
/* Original source Farseer Physics Engine:
|
|
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
|
|
* Microsoft Permissive License (Ms-PL) v1.1
|
|
*/
|
|
|
|
using System.Collections.Generic;
|
|
using Microsoft.Xna.Framework;
|
|
using FarseerPhysics.Collision;
|
|
using FarseerPhysics.Collision.Shapes;
|
|
using FarseerPhysics.Common.PhysicsLogic;
|
|
using FarseerPhysics.Dynamics;
|
|
|
|
namespace FarseerPhysics.Controllers
|
|
{
|
|
public sealed class BuoyancyController : Controller
|
|
{
|
|
/// <summary>
|
|
/// Controls the rotational drag that the fluid exerts on the bodies within it. Use higher values will simulate thick fluid, like honey, lower values to
|
|
/// simulate water-like fluids.
|
|
/// </summary>
|
|
public float AngularDragCoefficient;
|
|
|
|
/// <summary>
|
|
/// Density of the fluid. Higher values will make things more buoyant, lower values will cause things to sink.
|
|
/// </summary>
|
|
public float Density;
|
|
|
|
/// <summary>
|
|
/// Controls the linear drag that the fluid exerts on the bodies within it. Use higher values will simulate thick fluid, like honey, lower values to
|
|
/// simulate water-like fluids.
|
|
/// </summary>
|
|
public float LinearDragCoefficient;
|
|
|
|
/// <summary>
|
|
/// Acts like waterflow. Defaults to 0,0.
|
|
/// </summary>
|
|
public Vector2 Velocity;
|
|
|
|
private AABB _container;
|
|
|
|
private Vector2 _gravity;
|
|
private Vector2 _normal;
|
|
private float _offset;
|
|
private ICollection<Body> _uniqueBodies = new List<Body>();
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="BuoyancyController"/> class.
|
|
/// </summary>
|
|
/// <param name="container">Only bodies inside this AABB will be influenced by the controller</param>
|
|
/// <param name="density">Density of the fluid</param>
|
|
/// <param name="linearDragCoefficient">Linear drag coefficient of the fluid</param>
|
|
/// <param name="rotationalDragCoefficient">Rotational drag coefficient of the fluid</param>
|
|
/// <param name="gravity">The direction gravity acts. Buoyancy force will act in opposite direction of gravity.</param>
|
|
public BuoyancyController(AABB container, float density, float linearDragCoefficient, float rotationalDragCoefficient, Vector2 gravity)
|
|
{
|
|
Container = container;
|
|
_normal = new Vector2(0, 1);
|
|
Density = density;
|
|
LinearDragCoefficient = linearDragCoefficient;
|
|
AngularDragCoefficient = rotationalDragCoefficient;
|
|
_gravity = gravity;
|
|
}
|
|
|
|
public AABB Container
|
|
{
|
|
get { return _container; }
|
|
set
|
|
{
|
|
_container = value;
|
|
_offset = _container.UpperBound.Y;
|
|
}
|
|
}
|
|
|
|
public override void Update(float dt)
|
|
{
|
|
_uniqueBodies.Clear();
|
|
World.QueryAABB(fixture =>
|
|
{
|
|
if (fixture.Body.BodyType == BodyType.Static || !fixture.Body.Awake)
|
|
return true;
|
|
|
|
if (!_uniqueBodies.Contains(fixture.Body))
|
|
_uniqueBodies.Add(fixture.Body);
|
|
|
|
return true;
|
|
}, ref _container);
|
|
|
|
foreach (Body body in _uniqueBodies)
|
|
{
|
|
Vector2 areac = Vector2.Zero;
|
|
Vector2 massc = Vector2.Zero;
|
|
float area = 0;
|
|
float mass = 0;
|
|
|
|
for (int j = 0; j < body.FixtureList.Count; j++)
|
|
{
|
|
Fixture fixture = body.FixtureList[j];
|
|
|
|
if (fixture.Shape.ShapeType != ShapeType.Polygon && fixture.Shape.ShapeType != ShapeType.Circle)
|
|
continue;
|
|
|
|
Shape shape = fixture.Shape;
|
|
|
|
Vector2 sc;
|
|
float sarea = shape.ComputeSubmergedArea(ref _normal, _offset, ref body._xf, out sc);
|
|
area += sarea;
|
|
areac.X += sarea * sc.X;
|
|
areac.Y += sarea * sc.Y;
|
|
|
|
mass += sarea * shape.Density;
|
|
massc.X += sarea * sc.X * shape.Density;
|
|
massc.Y += sarea * sc.Y * shape.Density;
|
|
}
|
|
|
|
areac.X /= area;
|
|
areac.Y /= area;
|
|
massc.X /= mass;
|
|
massc.Y /= mass;
|
|
|
|
if (area < Settings.Epsilon)
|
|
continue;
|
|
|
|
//Buoyancy
|
|
Vector2 buoyancyForce = -Density * area * _gravity;
|
|
body.ApplyForce(buoyancyForce, massc);
|
|
|
|
//Linear drag
|
|
Vector2 dragForce = body.GetLinearVelocityFromWorldPoint(areac) - Velocity;
|
|
dragForce *= -LinearDragCoefficient * area;
|
|
body.ApplyForce(dragForce, areac);
|
|
|
|
//Angular drag
|
|
body.ApplyTorque(-body.Inertia / body.Mass * area * body.AngularVelocity * AngularDragCoefficient);
|
|
}
|
|
}
|
|
}
|
|
} |