From 58e98977df1fe2ff27f484ea6a935d93c96d5d59 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 14 Dec 2017 19:25:31 +0200 Subject: [PATCH] Fixes to projectiles going through walls: - Continuous collision detection (body.IsBullet) is disabled when the body is moving slow enough, not immediately when it hits something. - The prismatic joint that sticks projectiles to walls/characters stays active for a minimum of 1 s to prevent the projectile from immediately overshooting the joint limits and falling off (usually at the wrong side of a wall/door it hit). - Separate properties for determining which types of bodies the projectile can stick to (character/structure/item). - Spears and syringes only stick to characters. - Increased syringe launch impulse. Closes #122 --- .../Content/Items/Medical/medical.xml | 2 +- .../Content/Items/Weapons/weapons.xml | 4 +- .../Source/Items/Components/Projectile.cs | 84 ++++++++++++++----- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml b/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml index e09b4a293..e7e20a0a4 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml @@ -26,7 +26,7 @@ - + diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml b/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml index 7a04b23a5..130d19aba 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml @@ -16,7 +16,7 @@ - + @@ -100,7 +100,7 @@ - + diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs index 6eb8cd2ab..c5c079d2e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs @@ -12,9 +12,14 @@ namespace Barotrauma.Items.Components { class Projectile : ItemComponent { - private float launchImpulse; + //continuous collision detection is used while the projectile is moving faster than this + const float ContinuousCollisionThreshold = 5.0f; - private bool doesStick; + //a duration during which the projectile won't drop from the body it's stuck to + private const float PersistentStickJointDuration = 1.0f; + + private float launchImpulse; + private PrismaticJoint stickJoint; private Body stickTarget; @@ -24,6 +29,8 @@ namespace Barotrauma.Items.Components public Character User; + private float persistentStickJointTimer; + [Serialize(10.0f, false)] public float LaunchImpulse { @@ -39,10 +46,32 @@ namespace Barotrauma.Items.Components } [Serialize(false, false)] + //backwards compatibility, can stick to anything public bool DoesStick { - get { return doesStick; } - set { doesStick = value; } + get; + set; + } + + [Serialize(false, false)] + public bool StickToCharacters + { + get; + set; + } + + [Serialize(false, false)] + public bool StickToStructures + { + get; + set; + } + + [Serialize(false, false)] + public bool StickToItems + { + get; + set; } [Serialize(false, false)] @@ -106,7 +135,7 @@ namespace Barotrauma.Items.Components IsActive = true; - if (stickJoint == null || !doesStick) return; + if (stickJoint == null) return; if (stickTarget != null) { @@ -182,7 +211,7 @@ namespace Barotrauma.Items.Components //the raycast didn't hit anything -> the projectile flew somewhere outside the level and is permanently lost if (!hitSomething) { - Item.Spawner.AddToRemoveQueue(item); + Entity.Spawner.AddToRemoveQueue(item); } } @@ -190,8 +219,23 @@ namespace Barotrauma.Items.Components { ApplyStatusEffects(ActionType.OnActive, deltaTime, null); - if (stickJoint != null && - (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)) + if (item.body != null && item.body.FarseerBody.IsBullet) + { + if (item.body.LinearVelocity.LengthSquared() < ContinuousCollisionThreshold * ContinuousCollisionThreshold) + { + item.body.FarseerBody.IsBullet = false; + } + } + + if (stickJoint == null) return; + + if (persistentStickJointTimer > 0.0f) + { + persistentStickJointTimer -= deltaTime; + return; + } + + if (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f) { if (stickTarget != null) { @@ -218,7 +262,7 @@ namespace Barotrauma.Items.Components stickJoint = null; - IsActive = false; + if (!item.body.FarseerBody.IsBullet) IsActive = false; } } @@ -265,12 +309,9 @@ namespace Barotrauma.Items.Components ApplyStatusEffects(ActionType.OnUse, 1.0f, character); ApplyStatusEffects(ActionType.OnImpact, 1.0f, character); - - IsActive = false; - + item.body.FarseerBody.OnCollision -= OnProjectileCollision; - item.body.FarseerBody.IsBullet = false; item.body.CollisionCategories = Physics.CollisionItem; item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel; @@ -283,17 +324,20 @@ namespace Barotrauma.Items.Components { item.body.LinearVelocity *= 0.1f; } - else if (doesStick) + else if (Vector2.Dot(item.body.LinearVelocity, collisionNormal) < 0.0f && + (DoesStick || + (StickToCharacters && target.Body.UserData is Limb) || + (StickToStructures && target.Body.UserData is Structure) || + (StickToItems && target.Body.UserData is Item))) { Vector2 dir = new Vector2( (float)Math.Cos(item.body.Rotation), (float)Math.Sin(item.body.Rotation)); + + StickToTarget(target.Body, dir); + item.body.LinearVelocity *= 0.5f; - if (Vector2.Dot(item.body.LinearVelocity, collisionNormal) < 0.0f) - { - StickToTarget(target.Body, dir); - return Hitscan; - } + return Hitscan; } else { @@ -336,6 +380,8 @@ namespace Barotrauma.Items.Components stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * 0.3f); } + persistentStickJointTimer = PersistentStickJointDuration; + item.body.FarseerBody.IgnoreCollisionWith(targetBody); stickTarget = targetBody; GameMain.World.AddJoint(stickJoint);