Hitscan weapons can hit targets outside the sub when firing from the inside and vice versa. Closes #639

This commit is contained in:
Joonas Rikkonen
2018-09-10 13:56:53 +03:00
parent 57c9e5a731
commit 34c721bf89
@@ -12,6 +12,22 @@ namespace Barotrauma.Items.Components
{ {
class Projectile : ItemComponent class Projectile : ItemComponent
{ {
struct HitscanResult
{
public Fixture Fixture;
public Vector2 Point;
public Vector2 Normal;
public float Fraction;
public HitscanResult(Fixture fixture, Vector2 point, Vector2 normal, float fraction)
{
Fixture = fixture;
Point = point;
Normal = normal;
Fraction = fraction;
}
}
//continuous collision detection is used while the projectile is moving faster than this //continuous collision detection is used while the projectile is moving faster than this
const float ContinuousCollisionThreshold = 5.0f; const float ContinuousCollisionThreshold = 5.0f;
@@ -168,7 +184,7 @@ namespace Barotrauma.Items.Components
GameMain.World.RemoveJoint(stickJoint); GameMain.World.RemoveJoint(stickJoint);
stickJoint = null; stickJoint = null;
} }
private void DoHitscan(Vector2 dir) private void DoHitscan(Vector2 dir)
{ {
float rotation = item.body.Rotation; float rotation = item.body.Rotation;
@@ -183,39 +199,41 @@ namespace Barotrauma.Items.Components
Vector2 rayStart = item.SimPosition; Vector2 rayStart = item.SimPosition;
Vector2 rayEnd = item.SimPosition + dir * 1000.0f; Vector2 rayEnd = item.SimPosition + dir * 1000.0f;
List<Tuple<Fixture, Vector2, Vector2>> hits = new List<Tuple<Fixture, Vector2, Vector2>>(); List<HitscanResult> hits = new List<HitscanResult>();
GameMain.World.RayCast((fixture, point, normal, fraction) =>
hits.AddRange(DoRayCast(rayStart, rayEnd));
if (item.Submarine != null)
{ {
if (fixture == null || fixture.IsSensor) return -1; //shooting indoors, do a hitscan outside as well
hits.AddRange(DoRayCast(rayStart + item.Submarine.SimPosition, rayEnd + item.Submarine.SimPosition));
if (fixture.UserData is Item) return -1; }
else
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) && {
!fixture.CollisionCategories.HasFlag(Physics.CollisionWall) && //shooting outdoors, see if we can hit anything inside a sub
!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) return -1; foreach (Submarine submarine in Submarine.Loaded)
/*item.body.SetTransform(point, rotation);
if (OnProjectileCollision(fixture, normal))
{ {
Character.Controlled.AnimController.Teleport(point - Character.Controlled.SimPosition, Vector2.Zero); var inSubHits = DoRayCast(rayStart - submarine.SimPosition, rayEnd - submarine.SimPosition);
hitSomething = true; //transform back to world coordinates
return 0; for (int i = 0; i < inSubHits.Count; i++)
}*/ {
inSubHits[i] = new HitscanResult(
inSubHits[i].Fixture,
inSubHits[i].Point + submarine.SimPosition,
inSubHits[i].Normal,
inSubHits[i].Fraction);
}
hits.Add(new Tuple<Fixture, Vector2, Vector2>(fixture,point,normal)); hits.AddRange(inSubHits);
}
return hits.Count<25 ? 1 : 0; }
}, rayStart, rayEnd);
bool hitSomething = false; bool hitSomething = false;
hits = hits.OrderBy(t => Vector2.DistanceSquared(rayStart, t.Item2)).ToList(); hits = hits.OrderBy(h => h.Fraction).ToList();
foreach (Tuple<Fixture, Vector2, Vector2> t in hits) foreach (HitscanResult h in hits)
{ {
Fixture fixture = t.Item1; item.body.SetTransform(h.Point, rotation);
Vector2 point = t.Item2; if (OnProjectileCollision(h.Fixture, h.Normal))
Vector2 normal = t.Item3;
item.body.SetTransform(point, rotation);
if (OnProjectileCollision(fixture, normal))
{ {
hitSomething = true; hitSomething = true;
break; break;
@@ -229,6 +247,27 @@ namespace Barotrauma.Items.Components
} }
} }
private List<HitscanResult> DoRayCast(Vector2 rayStart, Vector2 rayEnd)
{
List<HitscanResult> hits = new List<HitscanResult>();
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
if (fixture == null || fixture.IsSensor) return -1;
if (fixture.UserData is Item) return -1;
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) return -1;
hits.Add(new HitscanResult(fixture, point, normal, fraction));
return hits.Count < 25 ? 1 : 0;
}, rayStart, rayEnd);
return hits;
}
public override void Update(float deltaTime, Camera cam) public override void Update(float deltaTime, Camera cam)
{ {
ApplyStatusEffects(ActionType.OnActive, deltaTime, null); ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
@@ -309,7 +348,7 @@ namespace Barotrauma.Items.Components
item.Move(-submarine.Position); item.Move(-submarine.Position);
item.Submarine = submarine; item.Submarine = submarine;
item.body.Submarine = submarine; item.body.Submarine = submarine;
return true; return !Hitscan;
} }
Structure structure; Structure structure;