From c1a1990f08a8775e3d87ae0f62f901e9155f6769 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 28 Mar 2016 16:11:55 +0300 Subject: [PATCH] - moving characters out of the way when the sub is teleported to the right position in multiplayer (monsters shouldn't randomly pop up inside the submarine anymore) - taking sub position into account when snapping cursor position to the grid -> new items/structures are aligned with existing ones if editing the sub while a round is running --- Subsurface/Source/Map/Submarine.cs | 12 ++- Subsurface/Source/Map/SubmarineBody.cs | 139 +++++++++++++------------ Subsurface/Source/Utils/MathUtils.cs | 45 ++++++++ 3 files changed, 129 insertions(+), 67 deletions(-) diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 039a8f924..1da1863db 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -24,7 +24,7 @@ namespace Barotrauma //position of the "actual submarine" which is rendered wherever the SubmarineBody is //should be in an unreachable place - public static readonly Vector2 HiddenSubPosition = new Vector2(0.0f, 50032.0f); + public static readonly Vector2 HiddenSubPosition = new Vector2(-50000.0f, 80000.0f); public static List SavedSubmarines = new List(); @@ -249,7 +249,15 @@ namespace Barotrauma Vector2 position = PlayerInput.MousePosition; position = cam.ScreenToWorld(position); - return VectorToWorldGrid(position); + Vector2 worldGridPos = VectorToWorldGrid(position); + + if (loaded != null) + { + worldGridPos.X += loaded.Position.X % GridSize.X; + worldGridPos.Y += loaded.Position.Y % GridSize.Y; + } + + return worldGridPos; } public static Vector2 VectorToWorldGrid(Vector2 position) diff --git a/Subsurface/Source/Map/SubmarineBody.cs b/Subsurface/Source/Map/SubmarineBody.cs index 7246e820e..b2f0faad0 100644 --- a/Subsurface/Source/Map/SubmarineBody.cs +++ b/Subsurface/Source/Map/SubmarineBody.cs @@ -8,6 +8,7 @@ using FarseerPhysics.Factories; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Voronoi2; @@ -16,13 +17,12 @@ namespace Barotrauma class SubmarineBody { public const float DamageDepth = -30000.0f; - const float PressureDamageMultiplier = 0.001f; + private const float PressureDamageMultiplier = 0.001f; - //structure damage = impact * damageMultiplier - const float DamageMultiplier = 50.0f; + private const float DamageMultiplier = 50.0f; + + private const float Friction = 0.2f, Restitution = 0.0f; - const float Friction = 0.2f, Restitution = 0.0f; - public List HullVertices { get; @@ -31,16 +31,13 @@ namespace Barotrauma private float depthDamageTimer; - private Submarine submarine; + private readonly Submarine submarine; - private Body body; + private readonly Body body; private Vector2? targetPosition; - - float mass = 10000.0f; - //private Vector2? lastContactPoint; - //private VoronoiCell lastContactCell; + private float mass = 10000.0f; public Rectangle Borders { @@ -72,12 +69,7 @@ namespace Barotrauma { get { return ConvertUnits.ToDisplayUnits(body.Position); } } - - public Vector2 Center - { - get { return new Vector2(Borders.X + Borders.Width / 2, Borders.Y - Borders.Height / 2); } - } - + public bool AtDamageDepth { get { return Position.Y < DamageDepth; } @@ -167,7 +159,7 @@ namespace Barotrauma { if (!Structure.WallList.Any()) { - return new List() { new Vector2(-1.0f, 1.0f), new Vector2(1.0f, 1.0f), new Vector2(0.0f, -1.0f) }; + return new List { new Vector2(-1.0f, 1.0f), new Vector2(1.0f, 1.0f), new Vector2(0.0f, -1.0f) }; } List points = new List(); @@ -223,35 +215,27 @@ namespace Barotrauma if (targetPosition != null && targetPosition != Position) { float dist = Vector2.Distance((Vector2)targetPosition, Position); - if (dist > 1000.0f) + + if (dist > 1000.0f) //immediately snap the sub to the target position if more than 1000.0f units away { - Vector2 moveAmount = ConvertUnits.ToSimUnits((Vector2)targetPosition) - body.Position; - Vector2 displayMoveAmount = ConvertUnits.ToDisplayUnits(moveAmount); + Vector2 moveAmount = (Vector2)targetPosition - ConvertUnits.ToDisplayUnits(body.Position); - body.SetTransform(body.Position + moveAmount, 0.0f); - if (Character.Controlled != null) Character.Controlled.CursorPosition += displayMoveAmount; + ForceTranslate(moveAmount); - GameMain.GameScreen.Cam.Position += displayMoveAmount; - if (GameMain.GameScreen.Cam.TargetPos!=Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += displayMoveAmount; GameMain.GameScreen.Cam.UpdateTransform(false); submarine.SetPrevTransform(submarine.Position); submarine.UpdateTransform(); targetPosition = null; + + DisplaceCharacters(moveAmount); } - else if (dist > 50.0f) + else if (dist > 50.0f) //lerp the position if (50 < dist < 1000) { Vector2 moveAmount = Vector2.Normalize((Vector2)targetPosition - Position); - moveAmount *= ConvertUnits.ToSimUnits(Math.Min(dist, 100.0f)); - Vector2 displayMoveAmount = ConvertUnits.ToDisplayUnits(moveAmount); + moveAmount *= Math.Min(dist, 100.0f); - body.SetTransform(body.Position + moveAmount * deltaTime, 0.0f); - - GameMain.GameScreen.Cam.Position += displayMoveAmount * deltaTime; - if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += displayMoveAmount; - if (Character.Controlled != null) Character.Controlled.CursorPosition += displayMoveAmount; - - //GameMain.GameScreen.Cam.UpdateTransform(false); + ForceTranslate(moveAmount * deltaTime); } else { @@ -280,7 +264,53 @@ namespace Barotrauma ApplyForce(totalForce); UpdateDepthDamage(deltaTime); + } + + /// + /// Immediately translates the position of the physics body, gamescreen camera and Character.Controlled.CursorPosition + /// + /// Amount to move in display units + private void ForceTranslate(Vector2 amount) + { + body.SetTransform(body.Position + ConvertUnits.ToSimUnits(amount), 0.0f); + if (Character.Controlled != null) Character.Controlled.CursorPosition += amount; + + GameMain.GameScreen.Cam.Position += amount; + if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += amount; + } + + + /// + /// Moves away any character that is inside the bounding box of the sub (but not inside it) + /// + /// The translation that was applied to the sub before doing the displacement + /// (used for determining where to push the characters) + private void DisplaceCharacters(Vector2 subTranslation) + { + Rectangle worldBorders = Borders; + worldBorders.Location += ConvertUnits.ToDisplayUnits(body.Position).ToPoint(); + + Vector2 translateDir = Vector2.Normalize(subTranslation); + + foreach (Character c in Character.CharacterList) + { + if (c.AnimController.CurrentHull != null) continue; + + //if the character isn't inside the bounding box, continue + if (!Submarine.RectContains(worldBorders, c.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(c.WorldPosition, + c.WorldPosition + translateDir*100000.0f, worldBorders); + + //should never be null when casting a line out from inside the bounding box + Debug.Assert(intersection != null); + + c.AnimController.SetPosition(ConvertUnits.ToSimUnits((Vector2)intersection) + translateDir); + //''+ translatedir'' in order to move the character slightly away from the wall + } } private Vector2 CalculateBuoyancy() @@ -363,49 +393,28 @@ namespace Barotrauma if (cell == null) { Limb limb = f2.Body.UserData as Limb; - if (limb != null) + if (limb == null) return true; + + bool collision = HandleLimbCollision(contact, limb); + + if (collision && limb.Mass > 100.0f) { - bool collision = HandleLimbCollision(contact, limb); + Vector2 normal = Vector2.Normalize(body.Position - limb.SimPosition); - if (collision && limb.Mass>100.0f) - { - Vector2 normal = Vector2.Normalize(body.Position - limb.SimPosition); + float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 5.0f); - //normal *= Math.Min(limb.Mass,100)/100.0f; - - float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 5.0f); - - ApplyImpact(impact * Math.Min(limb.Mass/200.0f, 1), -normal, contact); - - //ApplyImpact((-limb.LinearVelocity * Math.Min(limb.Mass, 100)) / 50.0f, contact); - } - - return collision; + ApplyImpact(impact * Math.Min(limb.Mass / 200.0f, 1), -normal, contact); } - return true; + return collision; } var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(body.Position) - cell.Center); - - Vector2 tempNormal; - - FarseerPhysics.Common.FixedArray2 worldPoints; - contact.GetWorldManifold(out tempNormal, out worldPoints); - - Vector2 lastContactPoint = worldPoints[0]; - float wallImpact = Vector2.Dot(Velocity, -collisionNormal); ApplyImpact(wallImpact, -collisionNormal, contact); - - //Vector2 u = Vector2.Dot(Velocity, -normal) * normal; - //Vector2 w = (Velocity + u); - - //speed = ConvertUnits.ToDisplayUnits(w * (1.0f - Friction) + u * Restitution); - return true; } diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index 6f8c5788b..37fc9339f 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -188,6 +188,51 @@ namespace Barotrauma return (r >= 0 && r <= 1) && (s >= 0 && s <= 1); } + // a1 is line1 start, a2 is line1 end, b1 is line2 start, b2 is line2 end + public static Vector2? GetLineIntersection(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2) + { + Vector2 b = a2 - a1; + Vector2 d = b2 - b1; + float bDotDPerp = b.X * d.Y - b.Y * d.X; + + // if b dot d == 0, it means the lines are parallel so have infinite intersection points + if (bDotDPerp == 0) return null; + + Vector2 c = b1 - a1; + float t = (c.X * d.Y - c.Y * d.X) / bDotDPerp; + if (t < 0 || t > 1) return null; + + float u = (c.X * b.Y - c.Y * b.X) / bDotDPerp; + if (u < 0 || u > 1) return null; + + return a1 + t * b; + } + + public static Vector2? GetLineRectangleIntersection(Vector2 a1, Vector2 a2, Rectangle rect) + { + Vector2? intersection = GetLineIntersection(a1, a2, + new Vector2(rect.X, rect.Y), + new Vector2(rect.Right, rect.Y)); + + if (intersection != null) return intersection; + + intersection = GetLineIntersection(a1, a2, + new Vector2(rect.X, rect.Y-rect.Height), + new Vector2(rect.Right, rect.Y-rect.Height)); + + if (intersection != null) return intersection; + + intersection = GetLineIntersection(a1, a2, + new Vector2(rect.X, rect.Y), + new Vector2(rect.X, rect.Y - rect.Height)); + + if (intersection != null) return intersection; + + return GetLineIntersection(a1, a2, + new Vector2(rect.Right, rect.Y), + new Vector2(rect.Right, rect.Y - rect.Height)); + } + public static float LineToPointDistance(Vector2 lineA, Vector2 lineB, Vector2 point) { return (float)(Math.Abs((lineB.X-lineA.X)*(lineA.Y - point.Y) - (lineA.X - point.X)*(lineB.Y-lineA.Y)) /