Fix collision detection for Missiles and Bullets.

This commit is contained in:
Paul Chote
2015-12-19 13:03:35 +00:00
parent a580aa1f27
commit 871d328c35
2 changed files with 38 additions and 8 deletions

View File

@@ -50,6 +50,12 @@ namespace OpenRA.Mods.Common.Effects
[Desc("Is this blocked by actors with BlocksProjectiles trait.")] [Desc("Is this blocked by actors with BlocksProjectiles trait.")]
public readonly bool Blockable = true; public readonly bool Blockable = true;
[Desc("Width of projectile (used for finding blocking actors).")]
public readonly WDist Width = new WDist(1);
[Desc("Extra search radius beyond path for blocking actors.")]
public readonly WDist TargetExtraSearchRadius = new WDist(2048);
[Desc("Arc in WAngles, two values indicate variable arc.")] [Desc("Arc in WAngles, two values indicate variable arc.")]
public readonly WAngle[] Angle = { WAngle.Zero }; public readonly WAngle[] Angle = { WAngle.Zero };
@@ -156,8 +162,19 @@ namespace OpenRA.Mods.Common.Effects
if (anim != null) if (anim != null)
anim.Tick(); anim.Tick();
var lastPos = pos;
pos = WPos.LerpQuadratic(args.Source, target, angle, ticks, length); pos = WPos.LerpQuadratic(args.Source, target, angle, ticks, length);
// Check for walls or other blocking obstacles
var shouldExplode = false;
WPos blockedPos;
if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width,
info.TargetExtraSearchRadius, out blockedPos))
{
pos = blockedPos;
shouldExplode = true;
}
if (!string.IsNullOrEmpty(info.Trail) && --smokeTicks < 0) if (!string.IsNullOrEmpty(info.Trail) && --smokeTicks < 0)
{ {
var delayedPos = WPos.LerpQuadratic(args.Source, target, angle, ticks - info.TrailDelay, length); var delayedPos = WPos.LerpQuadratic(args.Source, target, angle, ticks - info.TrailDelay, length);
@@ -168,8 +185,8 @@ namespace OpenRA.Mods.Common.Effects
if (info.ContrailLength > 0) if (info.ContrailLength > 0)
contrail.Update(pos); contrail.Update(pos);
var shouldExplode = ticks++ >= length // Flight length reached/exceeded // Flight length reached / exceeded
|| (info.Blockable && BlocksProjectiles.AnyBlockingActorAt(world, pos)); // Hit a wall or other blocking obstacle shouldExplode |= ticks++ >= length;
if (shouldExplode) if (shouldExplode)
Explode(world); Explode(world);

View File

@@ -58,6 +58,12 @@ namespace OpenRA.Mods.Common.Effects
[Desc("Is the missile blocked by actors with BlocksProjectiles: trait.")] [Desc("Is the missile blocked by actors with BlocksProjectiles: trait.")]
public readonly bool Blockable = true; public readonly bool Blockable = true;
[Desc("Width of projectile (used for finding blocking actors).")]
public readonly WDist Width = new WDist(1);
[Desc("Extra search radius beyond path for blocking actors.")]
public readonly WDist TargetExtraSearchRadius = new WDist(2048);
[Desc("Maximum offset at the maximum range")] [Desc("Maximum offset at the maximum range")]
public readonly WDist Inaccuracy = WDist.Zero; public readonly WDist Inaccuracy = WDist.Zero;
@@ -773,8 +779,19 @@ namespace OpenRA.Mods.Common.Effects
renderFacing = WAngle.ArcTan(move.Z - move.Y, move.X).Angle / 4 - 64; renderFacing = WAngle.ArcTan(move.Z - move.Y, move.X).Angle / 4 - 64;
// Move the missile // Move the missile
var lastPos = pos;
pos += move; pos += move;
// Check for walls or other blocking obstacles
var shouldExplode = false;
WPos blockedPos;
if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width,
info.TargetExtraSearchRadius, out blockedPos))
{
pos = blockedPos;
shouldExplode = true;
}
// Create the smoke trail effect // Create the smoke trail effect
if (!string.IsNullOrEmpty(info.TrailImage) && --ticksToNextSmoke < 0 && (state != States.Freefall || info.TrailWhenDeactivated)) if (!string.IsNullOrEmpty(info.TrailImage) && --ticksToNextSmoke < 0 && (state != States.Freefall || info.TrailWhenDeactivated))
{ {
@@ -786,14 +803,10 @@ namespace OpenRA.Mods.Common.Effects
contrail.Update(pos); contrail.Update(pos);
var cell = world.Map.CellContaining(pos); var cell = world.Map.CellContaining(pos);
// NOTE: High speeds might cause the missile to miss the target or fly through obstacles
// In that case, big moves should probably be decomposed into multiple smaller ones with hit checks
var height = world.Map.DistanceAboveTerrain(pos); var height = world.Map.DistanceAboveTerrain(pos);
var shouldExplode = (height.Length < 0) // Hit the ground shouldExplode |= height.Length < 0 // Hit the ground
|| (relTarDist < info.CloseEnough.Length) // Within range || relTarDist < info.CloseEnough.Length // Within range
|| (info.ExplodeWhenEmpty && info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel || (info.ExplodeWhenEmpty && info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel
|| (info.Blockable && BlocksProjectiles.AnyBlockingActorAt(world, pos)) // Hit a wall or other blocking obstacle
|| !world.Map.Contains(cell) // This also avoids an IndexOutOfRangeException in GetTerrainInfo below. || !world.Map.Contains(cell) // This also avoids an IndexOutOfRangeException in GetTerrainInfo below.
|| (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.Map.GetTerrainInfo(cell).Type != info.BoundToTerrainType) // Hit incompatible terrain || (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.Map.GetTerrainInfo(cell).Type != info.BoundToTerrainType) // Hit incompatible terrain
|| (height.Length < info.AirburstAltitude.Length && relTarHorDist < info.CloseEnough.Length); // Airburst || (height.Length < info.AirburstAltitude.Length && relTarHorDist < info.CloseEnough.Length); // Airburst