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
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
<Containable name="chem"/>
|
||||
</ItemContainer>
|
||||
|
||||
<Projectile launchimpulse="10.0" doesstick="true">
|
||||
<Projectile launchimpulse="20.0" sticktocharacters="true">
|
||||
<Attack damage="5" bleedingdamage="0.2" structuredamage="1" damagetype="Blunt" stun="0.1" targetforce="5"/>
|
||||
<StatusEffect type="OnImpact" target="Contained, Character" Condition="-50.0" disabledeltatime="true" >
|
||||
<sound file="Content/Items/Medical/syringe.ogg" range="500"/>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<Body width="64" height="5" density="20"/>
|
||||
|
||||
<Pickable slots="Any"/>
|
||||
<Projectile launchimpulse="20.0" doesstick="true">
|
||||
<Projectile launchimpulse="20.0" sticktocharacters="true">
|
||||
<Attack damage="20" bleedingdamage="2" structuredamage="50" damagetype="Blunt" stun="0.2" targetforce="50"/>
|
||||
</Projectile>
|
||||
</Item>
|
||||
@@ -100,7 +100,7 @@
|
||||
<Body width="8" height="3" density="40"/>
|
||||
|
||||
<Pickable slots="Any"/>
|
||||
<Projectile hitscan="true" doesstick="false" removeonhit="true" >
|
||||
<Projectile hitscan="true" removeonhit="true" >
|
||||
<Attack damage="40" bleedingdamage="3" structuredamage="100" damagetype="Blunt" stun="0.5" targetforce="50"/>
|
||||
</Projectile>
|
||||
</Item>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user