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"/>
|
<Containable name="chem"/>
|
||||||
</ItemContainer>
|
</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"/>
|
<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" >
|
<StatusEffect type="OnImpact" target="Contained, Character" Condition="-50.0" disabledeltatime="true" >
|
||||||
<sound file="Content/Items/Medical/syringe.ogg" range="500"/>
|
<sound file="Content/Items/Medical/syringe.ogg" range="500"/>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<Body width="64" height="5" density="20"/>
|
<Body width="64" height="5" density="20"/>
|
||||||
|
|
||||||
<Pickable slots="Any"/>
|
<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"/>
|
<Attack damage="20" bleedingdamage="2" structuredamage="50" damagetype="Blunt" stun="0.2" targetforce="50"/>
|
||||||
</Projectile>
|
</Projectile>
|
||||||
</Item>
|
</Item>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
<Body width="8" height="3" density="40"/>
|
<Body width="8" height="3" density="40"/>
|
||||||
|
|
||||||
<Pickable slots="Any"/>
|
<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"/>
|
<Attack damage="40" bleedingdamage="3" structuredamage="100" damagetype="Blunt" stun="0.5" targetforce="50"/>
|
||||||
</Projectile>
|
</Projectile>
|
||||||
</Item>
|
</Item>
|
||||||
|
|||||||
@@ -12,9 +12,14 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
class Projectile : ItemComponent
|
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 PrismaticJoint stickJoint;
|
||||||
private Body stickTarget;
|
private Body stickTarget;
|
||||||
|
|
||||||
@@ -24,6 +29,8 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public Character User;
|
public Character User;
|
||||||
|
|
||||||
|
private float persistentStickJointTimer;
|
||||||
|
|
||||||
[Serialize(10.0f, false)]
|
[Serialize(10.0f, false)]
|
||||||
public float LaunchImpulse
|
public float LaunchImpulse
|
||||||
{
|
{
|
||||||
@@ -39,10 +46,32 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serialize(false, false)]
|
[Serialize(false, false)]
|
||||||
|
//backwards compatibility, can stick to anything
|
||||||
public bool DoesStick
|
public bool DoesStick
|
||||||
{
|
{
|
||||||
get { return doesStick; }
|
get;
|
||||||
set { doesStick = value; }
|
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)]
|
[Serialize(false, false)]
|
||||||
@@ -106,7 +135,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
IsActive = true;
|
IsActive = true;
|
||||||
|
|
||||||
if (stickJoint == null || !doesStick) return;
|
if (stickJoint == null) return;
|
||||||
|
|
||||||
if (stickTarget != null)
|
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
|
//the raycast didn't hit anything -> the projectile flew somewhere outside the level and is permanently lost
|
||||||
if (!hitSomething)
|
if (!hitSomething)
|
||||||
{
|
{
|
||||||
Item.Spawner.AddToRemoveQueue(item);
|
Entity.Spawner.AddToRemoveQueue(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +219,23 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||||
|
|
||||||
if (stickJoint != null &&
|
if (item.body != null && item.body.FarseerBody.IsBullet)
|
||||||
(stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f))
|
{
|
||||||
|
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)
|
if (stickTarget != null)
|
||||||
{
|
{
|
||||||
@@ -218,7 +262,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
stickJoint = null;
|
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.OnUse, 1.0f, character);
|
||||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, character);
|
ApplyStatusEffects(ActionType.OnImpact, 1.0f, character);
|
||||||
|
|
||||||
IsActive = false;
|
|
||||||
|
|
||||||
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
|
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
|
||||||
|
|
||||||
item.body.FarseerBody.IsBullet = false;
|
|
||||||
item.body.CollisionCategories = Physics.CollisionItem;
|
item.body.CollisionCategories = Physics.CollisionItem;
|
||||||
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
|
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
|
||||||
|
|
||||||
@@ -283,17 +324,20 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
item.body.LinearVelocity *= 0.1f;
|
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(
|
Vector2 dir = new Vector2(
|
||||||
(float)Math.Cos(item.body.Rotation),
|
(float)Math.Cos(item.body.Rotation),
|
||||||
(float)Math.Sin(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)
|
return Hitscan;
|
||||||
{
|
|
||||||
StickToTarget(target.Body, dir);
|
|
||||||
return Hitscan;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -336,6 +380,8 @@ namespace Barotrauma.Items.Components
|
|||||||
stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * 0.3f);
|
stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * 0.3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
persistentStickJointTimer = PersistentStickJointDuration;
|
||||||
|
|
||||||
item.body.FarseerBody.IgnoreCollisionWith(targetBody);
|
item.body.FarseerBody.IgnoreCollisionWith(targetBody);
|
||||||
stickTarget = targetBody;
|
stickTarget = targetBody;
|
||||||
GameMain.World.AddJoint(stickJoint);
|
GameMain.World.AddJoint(stickJoint);
|
||||||
|
|||||||
Reference in New Issue
Block a user