38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -3,6 +3,7 @@ using FarseerPhysics.Collision;
|
||||
using FarseerPhysics.Common;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using FarseerPhysics.Factories;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
@@ -15,6 +16,12 @@ namespace Barotrauma
|
||||
{
|
||||
class SubmarineBody
|
||||
{
|
||||
public const float NeutralBallastPercentage = 0.07f;
|
||||
|
||||
const float HorizontalDrag = 0.01f;
|
||||
const float VerticalDrag = 0.05f;
|
||||
const float MaxDrag = 0.1f;
|
||||
|
||||
public const float DamageDepth = -30000.0f;
|
||||
private const float ImpactDamageMultiplier = 10.0f;
|
||||
|
||||
@@ -65,43 +72,36 @@ namespace Barotrauma
|
||||
get { return Position.Y < DamageDepth; }
|
||||
}
|
||||
|
||||
public SubmarineBody(Submarine sub)
|
||||
public Submarine Submarine
|
||||
{
|
||||
get { return submarine; }
|
||||
}
|
||||
|
||||
public SubmarineBody(Submarine sub, bool showWarningMessages = true)
|
||||
{
|
||||
this.submarine = sub;
|
||||
|
||||
Body farseerBody = null;
|
||||
|
||||
if (!Hull.hullList.Any())
|
||||
{
|
||||
Body = new PhysicsBody(1,1,1,1);
|
||||
farseerBody = Body.FarseerBody;
|
||||
DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed.");
|
||||
farseerBody = BodyFactory.CreateRectangle(GameMain.World, 1.0f, 1.0f, 1.0f);
|
||||
if (showWarningMessages)
|
||||
{
|
||||
DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Vector2> convexHull = GenerateConvexHull();
|
||||
HullVertices = convexHull;
|
||||
|
||||
for (int i = 0; i < convexHull.Count; i++)
|
||||
{
|
||||
convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]);
|
||||
}
|
||||
|
||||
convexHull.Reverse();
|
||||
|
||||
//get farseer 'vertices' from vectors
|
||||
Vertices shapevertices = new Vertices(convexHull);
|
||||
|
||||
AABB hullAABB = shapevertices.GetAABB();
|
||||
|
||||
Borders = new Rectangle(
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X),
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y),
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f),
|
||||
(int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f));
|
||||
Vector2 minExtents = Vector2.Zero, maxExtents = Vector2.Zero;
|
||||
|
||||
farseerBody = BodyFactory.CreateBody(GameMain.World, this);
|
||||
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
{
|
||||
if (wall.Submarine != submarine) continue;
|
||||
@@ -109,11 +109,17 @@ namespace Barotrauma
|
||||
Rectangle rect = wall.Rect;
|
||||
|
||||
FixtureFactory.AttachRectangle(
|
||||
ConvertUnits.ToSimUnits(rect.Width),
|
||||
ConvertUnits.ToSimUnits(rect.Height),
|
||||
ConvertUnits.ToSimUnits(wall.BodyWidth),
|
||||
ConvertUnits.ToSimUnits(wall.BodyHeight),
|
||||
50.0f,
|
||||
-wall.BodyRotation,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)),
|
||||
farseerBody, this);
|
||||
|
||||
minExtents.X = Math.Min(rect.X, minExtents.X);
|
||||
minExtents.Y = Math.Min(rect.Y - rect.Height, minExtents.Y);
|
||||
maxExtents.X = Math.Max(rect.Right, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(rect.Y, maxExtents.Y);
|
||||
}
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
@@ -127,39 +133,68 @@ namespace Barotrauma
|
||||
5.0f,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)),
|
||||
farseerBody, this);
|
||||
|
||||
minExtents.X = Math.Min(rect.X, minExtents.X);
|
||||
minExtents.Y = Math.Min(rect.Y - rect.Height, minExtents.Y);
|
||||
maxExtents.X = Math.Max(rect.Right, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(rect.Y, maxExtents.Y);
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.StaticBodyConfig == null) continue;
|
||||
if (item.StaticBodyConfig == null || item.Submarine != submarine) continue;
|
||||
|
||||
float radius = ConvertUnits.ToSimUnits(item.StaticBodyConfig.GetAttributeFloat("radius", 0.0f));
|
||||
float width = ConvertUnits.ToSimUnits(item.StaticBodyConfig.GetAttributeFloat("width", 0.0f));
|
||||
float height = ConvertUnits.ToSimUnits(item.StaticBodyConfig.GetAttributeFloat("height", 0.0f));
|
||||
float radius = item.StaticBodyConfig.GetAttributeFloat("radius", 0.0f) * item.Scale;
|
||||
float width = item.StaticBodyConfig.GetAttributeFloat("width", 0.0f) * item.Scale;
|
||||
float height = item.StaticBodyConfig.GetAttributeFloat("height", 0.0f) * item.Scale;
|
||||
|
||||
if (width != 0.0f && height != 0.0f)
|
||||
Vector2 simPos = ConvertUnits.ToSimUnits(item.Position);
|
||||
float simRadius = ConvertUnits.ToSimUnits(radius);
|
||||
float simWidth = ConvertUnits.ToSimUnits(width);
|
||||
float simHeight = ConvertUnits.ToSimUnits(height);
|
||||
|
||||
if (width > 0.0f && height > 0.0f)
|
||||
{
|
||||
FixtureFactory.AttachRectangle(width, height, 5.0f, ConvertUnits.ToSimUnits(item.Position), farseerBody, this).UserData = item;
|
||||
FixtureFactory.AttachRectangle(simWidth, simHeight, 5.0f, simPos, farseerBody, this).UserData = item;
|
||||
|
||||
minExtents.X = Math.Min(item.Position.X - width / 2, minExtents.X);
|
||||
minExtents.Y = Math.Min(item.Position.Y - height / 2, minExtents.Y);
|
||||
maxExtents.X = Math.Max(item.Position.X + width / 2, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(item.Position.Y + height / 2, maxExtents.Y);
|
||||
}
|
||||
else if (radius != 0.0f && width != 0.0f)
|
||||
else if (radius > 0.0f && width > 0.0f)
|
||||
{
|
||||
FixtureFactory.AttachRectangle(width, radius * 2, 5.0f, ConvertUnits.ToSimUnits(item.Position), farseerBody, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(radius, 5.0f, farseerBody, ConvertUnits.ToSimUnits(item.Position) - Vector2.UnitX * width / 2, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(radius, 5.0f, farseerBody, ConvertUnits.ToSimUnits(item.Position) + Vector2.UnitX * width / 2, this).UserData = item;
|
||||
FixtureFactory.AttachRectangle(simWidth, simRadius * 2, 5.0f, simPos, farseerBody, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos - Vector2.UnitX * simWidth / 2, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos + Vector2.UnitX * simWidth / 2, this).UserData = item;
|
||||
minExtents.X = Math.Min(item.Position.X - width / 2 - radius, minExtents.X);
|
||||
minExtents.Y = Math.Min(item.Position.Y - radius, minExtents.Y);
|
||||
maxExtents.X = Math.Max(item.Position.X + width / 2 + radius, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(item.Position.Y + radius, maxExtents.Y);
|
||||
}
|
||||
else if (radius != 0.0f && height != 0.0f)
|
||||
else if (radius > 0.0f && height > 0.0f)
|
||||
{
|
||||
FixtureFactory.AttachRectangle(radius * 2, height, 5.0f, ConvertUnits.ToSimUnits(item.Position), farseerBody, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(radius, 5.0f, farseerBody, ConvertUnits.ToSimUnits(item.Position) - Vector2.UnitY * height / 2, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(radius, 5.0f, farseerBody, ConvertUnits.ToSimUnits(item.Position) + Vector2.UnitX * height / 2, this).UserData = item;
|
||||
FixtureFactory.AttachRectangle(simRadius * 2, height, 5.0f, simPos, farseerBody, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos - Vector2.UnitY * simHeight / 2, this).UserData = item;
|
||||
FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos + Vector2.UnitX * simHeight / 2, this).UserData = item;
|
||||
minExtents.X = Math.Min(item.Position.X - radius, minExtents.X);
|
||||
minExtents.Y = Math.Min(item.Position.Y - height / 2 - radius, minExtents.Y);
|
||||
maxExtents.X = Math.Max(item.Position.X + radius, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(item.Position.Y + height / 2 + radius, maxExtents.Y);
|
||||
}
|
||||
else if (radius != 0.0f)
|
||||
else if (radius > 0.0f)
|
||||
{
|
||||
FixtureFactory.AttachCircle(radius, 5.0f, farseerBody, ConvertUnits.ToSimUnits(item.Position), this).UserData = item;
|
||||
FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos, this).UserData = item;
|
||||
minExtents.X = Math.Min(item.Position.X - radius, minExtents.X);
|
||||
minExtents.Y = Math.Min(item.Position.Y - radius, minExtents.Y);
|
||||
maxExtents.X = Math.Max(item.Position.X + radius, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(item.Position.Y + radius, maxExtents.Y);
|
||||
}
|
||||
}
|
||||
|
||||
Borders = new Rectangle((int)minExtents.X, (int)maxExtents.Y, (int)(maxExtents.X - minExtents.X), (int)(maxExtents.Y - minExtents.Y));
|
||||
}
|
||||
|
||||
|
||||
farseerBody.BodyType = BodyType.Dynamic;
|
||||
farseerBody.CollisionCategories = Physics.CollisionWall;
|
||||
farseerBody.CollidesWith =
|
||||
@@ -209,6 +244,8 @@ namespace Barotrauma
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (Body.FarseerBody.IsStatic) { return; }
|
||||
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
if (memPos.Count == 0) return;
|
||||
@@ -286,15 +323,25 @@ namespace Barotrauma
|
||||
//-------------------------
|
||||
|
||||
Vector2 totalForce = CalculateBuoyancy();
|
||||
|
||||
if (Body.LinearVelocity.LengthSquared() > 0.0001f)
|
||||
{
|
||||
float dragCoefficient = 0.01f;
|
||||
//TODO: sync current drag with clients?
|
||||
float attachedMass = 0.0f;
|
||||
JointEdge jointEdge = Body.FarseerBody.JointList;
|
||||
while (jointEdge != null)
|
||||
{
|
||||
Body otherBody = jointEdge.Joint.BodyA == Body.FarseerBody ? jointEdge.Joint.BodyB : jointEdge.Joint.BodyA;
|
||||
Character character = (otherBody.UserData as Limb)?.character;
|
||||
if (character != null) attachedMass += character.Mass;
|
||||
|
||||
float speedLength = (Body.LinearVelocity == Vector2.Zero) ? 0.0f : Body.LinearVelocity.Length();
|
||||
float drag = speedLength * speedLength * dragCoefficient * Body.Mass;
|
||||
|
||||
totalForce += -Vector2.Normalize(Body.LinearVelocity) * drag;
|
||||
jointEdge = jointEdge.Next;
|
||||
}
|
||||
|
||||
float horizontalDragCoefficient = MathHelper.Clamp(HorizontalDrag + attachedMass / 5000.0f, 0.0f, MaxDrag);
|
||||
totalForce.X -= Math.Sign(Body.LinearVelocity.X) * Body.LinearVelocity.X * Body.LinearVelocity.X * horizontalDragCoefficient * Body.Mass;
|
||||
|
||||
float verticalDragCoefficient = MathHelper.Clamp(VerticalDrag + attachedMass / 5000.0f, 0.0f, MaxDrag);
|
||||
totalForce.Y -= Math.Sign(Body.LinearVelocity.Y) * Body.LinearVelocity.Y * Body.LinearVelocity.Y * verticalDragCoefficient * Body.Mass;
|
||||
}
|
||||
|
||||
ApplyForce(totalForce);
|
||||
@@ -323,20 +370,23 @@ namespace Barotrauma
|
||||
{
|
||||
//if the character isn't inside the bounding box, continue
|
||||
if (!Submarine.RectContains(worldBorders, limb.WorldPosition)) continue;
|
||||
|
||||
|
||||
//cast a line from the position of the character to the same direction as the translation of the sub
|
||||
//and see where it intersects with the bounding box
|
||||
Vector2? intersection = MathUtils.GetLineRectangleIntersection(limb.WorldPosition,
|
||||
limb.WorldPosition + translateDir*100000.0f, worldBorders);
|
||||
if (!MathUtils.GetLineRectangleIntersection(limb.WorldPosition,
|
||||
limb.WorldPosition + translateDir * 100000.0f, worldBorders, out Vector2 intersection))
|
||||
{
|
||||
//should never happen when casting a line out from inside the bounding box
|
||||
Debug.Assert(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
//should never be null when casting a line out from inside the bounding box
|
||||
Debug.Assert(intersection != null);
|
||||
|
||||
//"+ translatedir" in order to move the character slightly away from the wall
|
||||
c.AnimController.SetPosition(ConvertUnits.ToSimUnits(c.WorldPosition + ((Vector2)intersection - limb.WorldPosition)) + translateDir);
|
||||
c.AnimController.SetPosition(ConvertUnits.ToSimUnits(c.WorldPosition + (intersection - limb.WorldPosition)) + translateDir);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -354,12 +404,13 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float waterPercentage = volume <= 0.0f ? 0.0f : waterVolume / volume;
|
||||
|
||||
float buoyancy = NeutralBallastPercentage - waterPercentage;
|
||||
|
||||
float neutralPercentage = 0.07f;
|
||||
|
||||
float buoyancy = neutralPercentage - waterPercentage;
|
||||
|
||||
if (buoyancy > 0.0f) buoyancy *= 2.0f;
|
||||
if (buoyancy > 0.0f)
|
||||
buoyancy *= 2.0f;
|
||||
else
|
||||
buoyancy = Math.Max(buoyancy, -0.5f);
|
||||
|
||||
return new Vector2(0.0f, buoyancy * Body.Mass * 10.0f);
|
||||
}
|
||||
@@ -406,26 +457,29 @@ namespace Barotrauma
|
||||
{
|
||||
if (f2.Body.UserData is Limb limb)
|
||||
{
|
||||
bool collision = CheckLimbCollision(contact, limb);
|
||||
bool collision = CheckCharacterCollision(contact, limb.character);
|
||||
if (collision) HandleLimbCollision(contact, limb);
|
||||
return collision;
|
||||
}
|
||||
if (f2.Body.UserData is Character character)
|
||||
{
|
||||
return CheckCharacterCollision(contact, character);
|
||||
}
|
||||
|
||||
contact.GetWorldManifold(out Vector2 normal, out FixedArray2<Vector2> points);
|
||||
if (contact.FixtureA.Body == f1.Body)
|
||||
{
|
||||
normal = -normal;
|
||||
}
|
||||
|
||||
if (f2.UserData is VoronoiCell cell)
|
||||
{
|
||||
Vector2 collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center);
|
||||
if (!MathUtils.IsValid(collisionNormal)) collisionNormal = Rand.Vector(1.0f);
|
||||
HandleLevelCollision(contact, collisionNormal);
|
||||
HandleLevelCollision(contact, normal);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (f2.Body.UserData is Structure structure)
|
||||
{
|
||||
contact.GetWorldManifold(out Vector2 normal, out FixedArray2<Vector2> points);
|
||||
if (contact.FixtureA.Body == f1.Body)
|
||||
{
|
||||
normal = -normal;
|
||||
}
|
||||
|
||||
HandleLevelCollision(contact, normal);
|
||||
return true;
|
||||
@@ -440,16 +494,16 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CheckLimbCollision(Contact contact, Limb limb)
|
||||
private bool CheckCharacterCollision(Contact contact, Character character)
|
||||
{
|
||||
if (limb.character.Submarine != null) return false;
|
||||
//characters that can't enter the sub always collide regardless of gaps
|
||||
if (!character.AnimController.CanEnterSubmarine) return true;
|
||||
if (character.Submarine != null) return false;
|
||||
|
||||
Vector2 contactNormal;
|
||||
FixedArray2<Vector2> points;
|
||||
contact.GetWorldManifold(out contactNormal, out points);
|
||||
contact.GetWorldManifold(out Vector2 contactNormal, out FixedArray2<Vector2> points);
|
||||
|
||||
Vector2 normalizedVel = limb.character.AnimController.Collider.LinearVelocity == Vector2.Zero ?
|
||||
Vector2.Zero : Vector2.Normalize(limb.character.AnimController.Collider.LinearVelocity);
|
||||
Vector2 normalizedVel = character.AnimController.Collider.LinearVelocity == Vector2.Zero ?
|
||||
Vector2.Zero : Vector2.Normalize(character.AnimController.Collider.LinearVelocity);
|
||||
|
||||
Vector2 targetPos = ConvertUnits.ToDisplayUnits(points[0] - contactNormal);
|
||||
Hull newHull = Hull.FindHull(targetPos, null);
|
||||
@@ -458,16 +512,17 @@ namespace Barotrauma
|
||||
{
|
||||
targetPos = ConvertUnits.ToDisplayUnits(points[0] + normalizedVel);
|
||||
newHull = Hull.FindHull(targetPos, null);
|
||||
if (newHull == null) return true;
|
||||
}
|
||||
|
||||
var gaps = newHull.ConnectedGaps;
|
||||
targetPos = limb.character.WorldPosition;
|
||||
var gaps = newHull?.ConnectedGaps ?? Gap.GapList.Where(g => g.Submarine == submarine);
|
||||
targetPos = character.WorldPosition;
|
||||
Gap adjacentGap = Gap.FindAdjacent(gaps, targetPos, 200.0f);
|
||||
if (adjacentGap == null) return true;
|
||||
|
||||
var ragdoll = limb.character.AnimController;
|
||||
ragdoll.FindHull(newHull.WorldPosition, true);
|
||||
if (newHull != null)
|
||||
{
|
||||
character.AnimController.FindHull(newHull.WorldPosition, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -508,8 +563,6 @@ namespace Barotrauma
|
||||
//if the limb is in contact with the level, apply an artifical impact to prevent the sub from bouncing on top of it
|
||||
//not a very realistic way to handle the collisions (makes it seem as if the characters were made of reinforced concrete),
|
||||
//but more realistic than bouncing and prevents using characters as "bumpers" that prevent all collision damage
|
||||
|
||||
//TODO: apply impact damage and/or gib the character that got crushed between the sub and the level?
|
||||
Vector2 avgContactNormal = Vector2.Zero;
|
||||
foreach (Contact levelContact in levelContacts)
|
||||
{
|
||||
@@ -556,7 +609,9 @@ namespace Barotrauma
|
||||
Vector2 n;
|
||||
FixedArray2<Vector2> contactPos;
|
||||
contact.GetWorldManifold(out n, out contactPos);
|
||||
limb.character.DamageLimb(ConvertUnits.ToDisplayUnits(contactPos[0]), limb, DamageType.Blunt, damageAmount, 0.0f, 0.0f, true, 0.0f);
|
||||
limb.character.LastDamageSource = submarine;
|
||||
limb.character.DamageLimb(ConvertUnits.ToDisplayUnits(contactPos[0]), limb,
|
||||
new List<Affliction>() { AfflictionPrefab.InternalDamage.Instantiate(damageAmount) }, 0.0f, true, 0.0f);
|
||||
|
||||
if (limb.character.IsDead)
|
||||
{
|
||||
@@ -685,19 +740,23 @@ namespace Barotrauma
|
||||
{
|
||||
if (impact < 3.0f) return;
|
||||
|
||||
Vector2 tempNormal;
|
||||
FixedArray2<Vector2> worldPoints;
|
||||
contact.GetWorldManifold(out tempNormal, out worldPoints);
|
||||
|
||||
contact.GetWorldManifold(out Vector2 tempNormal, out FixedArray2<Vector2> worldPoints);
|
||||
Vector2 lastContactPoint = worldPoints[0];
|
||||
|
||||
Vector2 impulse = direction * impact * 0.5f;
|
||||
impulse = impulse.ClampLength(5.0f);
|
||||
|
||||
#if CLIENT
|
||||
if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
|
||||
{
|
||||
GameMain.GameScreen.Cam.Shake = impact * 2.0f;
|
||||
float angularVelocity =
|
||||
(lastContactPoint.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y
|
||||
- (lastContactPoint.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X;
|
||||
GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
Vector2 impulse = direction * impact * 0.5f;
|
||||
impulse = impulse.ClampLength(5.0f);
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.Submarine != submarine) continue;
|
||||
@@ -739,7 +798,7 @@ namespace Barotrauma
|
||||
"StructureBlunt",
|
||||
impact * 10.0f,
|
||||
ConvertUnits.ToDisplayUnits(lastContactPoint),
|
||||
MathHelper.Clamp(maxDamage * 4.0f, 1000.0f, 4000.0f),
|
||||
MathHelper.Clamp(maxDamage * 4.0f, 2000.0f, 10000.0f),
|
||||
maxDamageStructure.Tags);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user