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

View File

@@ -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<Tuple<Fixture, Vector2, Vector2>> hits = new List<Tuple<Fixture, Vector2, Vector2>>();
GameMain.World.RayCast((fixture, point, normal, fraction) =>
List<HitscanResult> hits = new List<HitscanResult>();
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, Vector2, Vector2>(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<Fixture, Vector2, Vector2> 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<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)
{
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;