Fix (or a workaround) to characters teleporting inside/through colliders when leaving a sub (see #552). Gaps do a raycast out from the sub to see if there are obstacles outside, and if so, ragdolls place a collider at the corresponding position inside the sub. The collider is simply a straight axis-aligned line atm, so it doesn't work accurately with sloped ice/submarine walls, but does prevent the ragdoll from ending up inside the obstacles. TODO: use a few edges to approximate the shape of the obstacles more closely?
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -13,6 +14,8 @@ namespace Barotrauma
|
||||
|
||||
public static bool ShowGaps = true;
|
||||
|
||||
const float OutsideColliderRaycastInterval = 0.1f;
|
||||
|
||||
public readonly bool IsHorizontal;
|
||||
|
||||
//a value between 0.0f-1.0f (0.0 = closed, 1.0f = open)
|
||||
@@ -26,12 +29,18 @@ namespace Barotrauma
|
||||
private float lowerSurface;
|
||||
|
||||
private Vector2 lerpedFlowForce;
|
||||
|
||||
|
||||
//if set to true, hull connections of this gap won't be updated when changes are being done to hulls
|
||||
public bool DisableHullRechecks;
|
||||
|
||||
//can ambient light get through the gap even if it's not open
|
||||
public bool PassAmbientLight;
|
||||
|
||||
//position of a collider outside the gap (for example an ice wall next to the sub)
|
||||
//used by ragdolls to prevent them from ending up inside colliders when teleporting out of the sub
|
||||
private Vector2? outsideColliderPos;
|
||||
private Vector2? outsideColliderNormal;
|
||||
private float outsideColliderRaycastTimer;
|
||||
|
||||
public float Open
|
||||
{
|
||||
@@ -191,6 +200,8 @@ namespace Barotrauma
|
||||
{
|
||||
flowForce = Vector2.Zero;
|
||||
|
||||
outsideColliderRaycastTimer -= deltaTime;
|
||||
|
||||
if (open == 0.0f || linkedTo.Count == 0)
|
||||
{
|
||||
lerpedFlowForce = Vector2.Zero;
|
||||
@@ -505,7 +516,51 @@ namespace Barotrauma
|
||||
hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetOutsideCollider(out Vector2? simPosition, out Vector2? normal)
|
||||
{
|
||||
simPosition = null;
|
||||
normal = null;
|
||||
|
||||
if (IsRoomToRoom || Submarine == null || open <= 0.0f) return false;
|
||||
|
||||
if (outsideColliderRaycastTimer <= 0.0f)
|
||||
{
|
||||
UpdateOutsideColliderPos((Hull)linkedTo[0]);
|
||||
outsideColliderRaycastTimer = OutsideColliderRaycastInterval;
|
||||
}
|
||||
|
||||
simPosition = outsideColliderPos;
|
||||
normal = outsideColliderNormal;
|
||||
return simPosition != null;
|
||||
}
|
||||
|
||||
private void UpdateOutsideColliderPos(Hull hull)
|
||||
{
|
||||
outsideColliderNormal = null;
|
||||
outsideColliderPos = null;
|
||||
|
||||
if (Submarine == null) return;
|
||||
|
||||
Vector2 rayDir;
|
||||
if (IsHorizontal)
|
||||
{
|
||||
rayDir = new Vector2(Math.Sign(rect.Center.X - hull.Rect.Center.X), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rayDir = new Vector2(0, Math.Sign((rect.Y - rect.Height / 2) - (hull.Rect.Y - hull.Rect.Height / 2)));
|
||||
}
|
||||
|
||||
Vector2 rayStart = ConvertUnits.ToSimUnits(WorldPosition);
|
||||
Vector2 rayEnd = rayStart + rayDir * 500.0f;
|
||||
|
||||
if (Submarine.CheckVisibility(rayStart, rayEnd) != null)
|
||||
{
|
||||
outsideColliderNormal = -rayDir;
|
||||
outsideColliderPos = Submarine.LastPickedPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOxygen()
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace Barotrauma
|
||||
|
||||
private static Vector2 lastPickedPosition;
|
||||
private static float lastPickedFraction;
|
||||
private static Vector2 lastPickedNormal;
|
||||
|
||||
private Md5Hash hash;
|
||||
|
||||
@@ -120,6 +121,11 @@ namespace Barotrauma
|
||||
get { return lastPickedFraction; }
|
||||
}
|
||||
|
||||
public static Vector2 LastPickedNormal
|
||||
{
|
||||
get { return lastPickedNormal; }
|
||||
}
|
||||
|
||||
public bool Loading
|
||||
{
|
||||
get;
|
||||
@@ -593,6 +599,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float closestFraction = 1.0f;
|
||||
Vector2 closestNormal = Vector2.Zero;
|
||||
Body closestBody = null;
|
||||
GameMain.World.RayCast((fixture, point, normal, fraction) =>
|
||||
{
|
||||
@@ -616,6 +623,7 @@ namespace Barotrauma
|
||||
if (fraction < closestFraction)
|
||||
{
|
||||
closestFraction = fraction;
|
||||
closestNormal = normal;
|
||||
if (fixture.Body != null) closestBody = fixture.Body;
|
||||
}
|
||||
return fraction;
|
||||
@@ -624,6 +632,7 @@ namespace Barotrauma
|
||||
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFraction = closestFraction;
|
||||
lastPickedNormal = closestNormal;
|
||||
|
||||
return closestBody;
|
||||
}
|
||||
@@ -636,6 +645,7 @@ namespace Barotrauma
|
||||
{
|
||||
Body closestBody = null;
|
||||
float closestFraction = 1.0f;
|
||||
Vector2 closestNormal = Vector2.Zero;
|
||||
|
||||
if (Vector2.Distance(rayStart, rayEnd) < 0.01f)
|
||||
{
|
||||
@@ -664,6 +674,7 @@ namespace Barotrauma
|
||||
{
|
||||
closestBody = fixture.Body;
|
||||
closestFraction = fraction;
|
||||
closestNormal = normal;
|
||||
}
|
||||
return closestFraction;
|
||||
}
|
||||
@@ -672,6 +683,7 @@ namespace Barotrauma
|
||||
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFraction = closestFraction;
|
||||
lastPickedNormal = closestNormal;
|
||||
return closestBody;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user