From 34c721bf89582e1c9e44c0d4093a01cceed104b5 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 10 Sep 2018 13:56:53 +0300 Subject: [PATCH] Hitscan weapons can hit targets outside the sub when firing from the inside and vice versa. Closes #639 --- .../Source/Items/Components/Projectile.cs | 97 +++++++++++++------ 1 file changed, 68 insertions(+), 29 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs index 859969cb4..18ed90922 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs @@ -12,6 +12,22 @@ namespace Barotrauma.Items.Components { 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 const float ContinuousCollisionThreshold = 5.0f; @@ -168,7 +184,7 @@ namespace Barotrauma.Items.Components GameMain.World.RemoveJoint(stickJoint); stickJoint = null; } - + private void DoHitscan(Vector2 dir) { float rotation = item.body.Rotation; @@ -183,39 +199,41 @@ namespace Barotrauma.Items.Components Vector2 rayStart = item.SimPosition; Vector2 rayEnd = item.SimPosition + dir * 1000.0f; - List> hits = new List>(); - GameMain.World.RayCast((fixture, point, normal, fraction) => + List hits = new List(); + + hits.AddRange(DoRayCast(rayStart, rayEnd)); + + if (item.Submarine != null) { - 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; - - /*item.body.SetTransform(point, rotation); - if (OnProjectileCollision(fixture, normal)) + //shooting indoors, do a hitscan outside as well + hits.AddRange(DoRayCast(rayStart + item.Submarine.SimPosition, rayEnd + item.Submarine.SimPosition)); + } + else + { + //shooting outdoors, see if we can hit anything inside a sub + foreach (Submarine submarine in Submarine.Loaded) { - Character.Controlled.AnimController.Teleport(point - Character.Controlled.SimPosition, Vector2.Zero); - hitSomething = true; - return 0; - }*/ + var inSubHits = DoRayCast(rayStart - submarine.SimPosition, rayEnd - submarine.SimPosition); + //transform back to world coordinates + 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,point,normal)); - - return hits.Count<25 ? 1 : 0; - }, rayStart, rayEnd); + hits.AddRange(inSubHits); + } + } bool hitSomething = false; - hits = hits.OrderBy(t => Vector2.DistanceSquared(rayStart, t.Item2)).ToList(); - foreach (Tuple t in hits) + hits = hits.OrderBy(h => h.Fraction).ToList(); + foreach (HitscanResult h in hits) { - Fixture fixture = t.Item1; - Vector2 point = t.Item2; - Vector2 normal = t.Item3; - item.body.SetTransform(point, rotation); - if (OnProjectileCollision(fixture, normal)) + item.body.SetTransform(h.Point, rotation); + if (OnProjectileCollision(h.Fixture, h.Normal)) { hitSomething = true; break; @@ -229,6 +247,27 @@ namespace Barotrauma.Items.Components } } + private List DoRayCast(Vector2 rayStart, Vector2 rayEnd) + { + List hits = new List(); + 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) { ApplyStatusEffects(ActionType.OnActive, deltaTime, null); @@ -309,7 +348,7 @@ namespace Barotrauma.Items.Components item.Move(-submarine.Position); item.Submarine = submarine; item.body.Submarine = submarine; - return true; + return !Hitscan; } Structure structure;