Move FindTilesInCircle from WorldUtils to Map

This commit is contained in:
Pavlos Touboulidis
2014-06-13 14:24:53 +03:00
parent 03b8096807
commit 060d5326ed
11 changed files with 70 additions and 60 deletions

View File

@@ -573,5 +573,38 @@ namespace OpenRA
var y = dir.Y == 0 ? int.MaxValue : ((dir.Y < 0 ? tl.Y : br.Y) - pos.Y) / dir.Y; var y = dir.Y == 0 ? int.MaxValue : ((dir.Y < 0 ? tl.Y : br.Y) - pos.Y) / dir.Y;
return new WRange(Math.Min(x, y) * dir.Length); return new WRange(Math.Min(x, y) * dir.Length);
} }
public const int MaxTilesInCircleRange = 50;
static List<CVec>[] TilesByDistance = InitTilesByDistance(MaxTilesInCircleRange);
static List<CVec>[] InitTilesByDistance(int max)
{
var ts = new List<CVec>[max + 1];
for (var i = 0; i < max + 1; i++)
ts [i] = new List<CVec>();
for (var j = -max; j <= max; j++)
for (var i = -max; i <= max; i++)
if (max * max >= i * i + j * j)
ts [(int)Math.Ceiling(Math.Sqrt(i * i + j * j))].Add(new CVec(i, j));
return ts;
}
public IEnumerable<CPos> FindTilesInCircle(CPos center, int range)
{
if (range >= TilesByDistance.Length)
throw new InvalidOperationException("FindTilesInCircle supports queries for only <= {0}".F(MaxTilesInCircleRange));
for(var i = 0; i <= range; i++)
{
foreach(var offset in TilesByDistance[i])
{
var t = offset + center;
if (Bounds.Contains(t.X, t.Y))
yield return t;
}
}
}
} }
} }

View File

@@ -55,39 +55,6 @@ namespace OpenRA
} }
} }
public static IEnumerable<CPos> FindTilesInCircle(this World world, CPos a, int r)
{
if (r >= TilesByDistance.Length)
throw new InvalidOperationException("FindTilesInCircle supports queries for only <= {0}".F(MaxRange));
for(var i = 0; i <= r; i++)
{
foreach(var offset in TilesByDistance[i])
{
var t = offset + a;
if (world.Map.Bounds.Contains(t.X, t.Y))
yield return t;
}
}
}
static List<CVec>[] InitTilesByDistance(int max)
{
var ts = new List<CVec>[max+1];
for (var i = 0; i < max+1; i++)
ts[i] = new List<CVec>();
for (var j = -max; j <= max; j++)
for (var i = -max; i <= max; i++)
if (max * max >= i * i + j * j)
ts[(int)Math.Ceiling(Math.Sqrt(i*i + j*j))].Add(new CVec(i,j));
return ts;
}
public const int MaxRange = 50;
static List<CVec>[] TilesByDistance = InitTilesByDistance(MaxRange);
public static CPos ChooseRandomEdgeCell(this World w) public static CPos ChooseRandomEdgeCell(this World w)
{ {
var isX = w.SharedRandom.Next(2) == 0; var isX = w.SharedRandom.Next(2) == 0;

View File

@@ -345,7 +345,7 @@ namespace OpenRA.Mods.RA.AI
{ {
for (var k = MaxBaseDistance; k >= 0; k--) for (var k = MaxBaseDistance; k >= 0; k--)
{ {
var tlist = world.FindTilesInCircle(center, k) var tlist = Map.FindTilesInCircle(center, k)
.OrderBy(a => (a.CenterPosition - pos).LengthSquared); .OrderBy(a => (a.CenterPosition - pos).LengthSquared);
foreach (var t in tlist) foreach (var t in tlist)
@@ -365,7 +365,7 @@ namespace OpenRA.Mods.RA.AI
return enemyBase != null ? findPos(enemyBase.CenterPosition, defenseCenter) : null; return enemyBase != null ? findPos(enemyBase.CenterPosition, defenseCenter) : null;
case BuildingType.Refinery: case BuildingType.Refinery:
var tilesPos = world.FindTilesInCircle(baseCenter, MaxBaseDistance) var tilesPos = Map.FindTilesInCircle(baseCenter, MaxBaseDistance)
.Where(a => resourceTypeIndices.Contains(Map.GetTerrainIndex(new CPos(a.X, a.Y)))); .Where(a => resourceTypeIndices.Contains(Map.GetTerrainIndex(new CPos(a.X, a.Y))));
if (tilesPos.Any()) if (tilesPos.Any())
{ {
@@ -377,7 +377,7 @@ namespace OpenRA.Mods.RA.AI
case BuildingType.Building: case BuildingType.Building:
for (var k = 0; k < maxBaseDistance; k++) for (var k = 0; k < maxBaseDistance; k++)
{ {
foreach (var t in world.FindTilesInCircle(baseCenter, k)) foreach (var t in Map.FindTilesInCircle(baseCenter, k))
{ {
if (world.CanPlaceBuilding(actorType, bi, t, null)) if (world.CanPlaceBuilding(actorType, bi, t, null))
{ {
@@ -696,7 +696,7 @@ namespace OpenRA.Mods.RA.AI
// Won't work for shipyards... // Won't work for shipyards...
CPos ChooseRallyLocationNear(CPos startPos) CPos ChooseRallyLocationNear(CPos startPos)
{ {
var possibleRallyPoints = world.FindTilesInCircle(startPos, Info.RallyPointScanRadius) var possibleRallyPoints = Map.FindTilesInCircle(startPos, Info.RallyPointScanRadius)
.Where(IsRallyPointValid); .Where(IsRallyPointValid);
if (!possibleRallyPoints.Any()) if (!possibleRallyPoints.Any())

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.RA.Activities
bool screenFlash; bool screenFlash;
string sound; string sound;
const int maxCellSearchRange = WorldUtils.MaxRange; const int maxCellSearchRange = Map.MaxTilesInCircleRange;
public Teleport(Actor chronosphere, CPos destination, int? maximumDistance, bool killCargo, bool screenFlash, string sound) public Teleport(Actor chronosphere, CPos destination, int? maximumDistance, bool killCargo, bool screenFlash, string sound)
{ {
@@ -90,7 +90,7 @@ namespace OpenRA.Mods.RA.Activities
CPos? ChooseBestDestinationCell(Actor self, CPos destination) CPos? ChooseBestDestinationCell(Actor self, CPos destination)
{ {
var restrictTo = maximumDistance == null ? null : self.World.FindTilesInCircle(self.Location, maximumDistance.Value); var restrictTo = maximumDistance == null ? null : self.World.Map.FindTilesInCircle(self.Location, maximumDistance.Value);
if (maximumDistance != null) if (maximumDistance != null)
destination = restrictTo.MinBy(x => (x - destination).LengthSquared); destination = restrictTo.MinBy(x => (x - destination).LengthSquared);
@@ -102,7 +102,7 @@ namespace OpenRA.Mods.RA.Activities
var searched = new List<CPos>(); var searched = new List<CPos>();
for (int r = 1; r <= maxCellSearchRange || (maximumDistance != null && r <= maximumDistance); r++) for (int r = 1; r <= maxCellSearchRange || (maximumDistance != null && r <= maximumDistance); r++)
{ {
foreach (var tile in self.World.FindTilesInCircle(destination, r).Except(searched)) foreach (var tile in self.World.Map.FindTilesInCircle(destination, r).Except(searched))
{ {
if (self.Owner.Shroud.IsExplored(tile) if (self.Owner.Shroud.IsExplored(tile)
&& (restrictTo == null || (restrictTo != null && restrictTo.Contains(tile))) && (restrictTo == null || (restrictTo != null && restrictTo.Contains(tile)))

View File

@@ -53,12 +53,12 @@ namespace OpenRA.Mods.RA
if (warhead.Size[0] > 0) if (warhead.Size[0] > 0)
{ {
var resLayer = world.WorldActor.Trait<ResourceLayer>(); var resLayer = world.WorldActor.Trait<ResourceLayer>();
var allCells = world.FindTilesInCircle(targetTile, warhead.Size[0]).ToList(); var allCells = world.Map.FindTilesInCircle(targetTile, warhead.Size[0]).ToList();
// `smudgeCells` might want to just be an outer shell of the cells: // `smudgeCells` might want to just be an outer shell of the cells:
IEnumerable<CPos> smudgeCells = allCells; IEnumerable<CPos> smudgeCells = allCells;
if (warhead.Size.Length == 2) if (warhead.Size.Length == 2)
smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1])); smudgeCells = smudgeCells.Except(world.Map.FindTilesInCircle(targetTile, warhead.Size[1]));
// Draw the smudges: // Draw the smudges:
foreach (var sc in smudgeCells) foreach (var sc in smudgeCells)
@@ -110,17 +110,21 @@ namespace OpenRA.Mods.RA
var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, true); var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, true);
victim.InflictDamage(firedBy, damage, warhead); victim.InflictDamage(firedBy, damage, warhead);
} }
} break; }
break;
case DamageModel.PerCell: case DamageModel.PerCell:
{ {
foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) foreach (var t in world.Map.FindTilesInCircle(targetTile, warhead.Size[0]))
{
foreach (var unit in world.ActorMap.GetUnitsAt(t)) foreach (var unit in world.ActorMap.GetUnitsAt(t))
{ {
var damage = (int)GetDamageToInflict(pos, unit, warhead, weapon, firepowerModifier, false); var damage = (int)GetDamageToInflict(pos, unit, warhead, weapon, firepowerModifier, false);
unit.InflictDamage(firedBy, damage, warhead); unit.InflictDamage(firedBy, damage, warhead);
} }
} break; }
}
break;
case DamageModel.HealthPercentage: case DamageModel.HealthPercentage:
{ {
@@ -135,9 +139,11 @@ namespace OpenRA.Mods.RA
var healthInfo = victim.Info.Traits.Get<HealthInfo>(); var healthInfo = victim.Info.Traits.Get<HealthInfo>();
damage = (float)(damage / 100 * healthInfo.HP); damage = (float)(damage / 100 * healthInfo.HP);
} }
victim.InflictDamage(firedBy, (int)damage, warhead); victim.InflictDamage(firedBy, (int)damage, warhead);
} }
} break; }
break;
} }
} }

View File

@@ -324,13 +324,15 @@ namespace OpenRA.Mods.RA.Move
var searched = new List<CPos>(); var searched = new List<CPos>();
// Limit search to a radius of 10 tiles // Limit search to a radius of 10 tiles
for (int r = minRange; r < maxRange; r++) for (int r = minRange; r < maxRange; r++)
foreach (var tile in self.World.FindTilesInCircle(target, r).Except(searched)) {
foreach (var tile in self.World.Map.FindTilesInCircle(target, r).Except(searched))
{ {
if (CanEnterCell(tile)) if (CanEnterCell(tile))
return tile; return tile;
searched.Add(tile); searched.Add(tile);
} }
}
// Couldn't find a cell // Couldn't find a cell
return target; return target;
@@ -343,13 +345,15 @@ namespace OpenRA.Mods.RA.Move
var searched = new List<CPos>(); var searched = new List<CPos>();
for (int r = minRange; r < maxRange; r++) for (int r = minRange; r < maxRange; r++)
foreach (var tile in self.World.FindTilesInCircle(target, r).Except(searched)) {
foreach (var tile in self.World.Map.FindTilesInCircle(target, r).Except(searched))
{ {
if (check(tile)) if (check(tile))
return tile; return tile;
searched.Add(tile); searched.Add(tile);
} }
}
// Couldn't find a cell // Couldn't find a cell
return target; return target;

View File

@@ -92,7 +92,7 @@ namespace OpenRA.Mods.RA.Move
// Select only the tiles that are within range from the requested SubCell // Select only the tiles that are within range from the requested SubCell
// This assumes that the SubCell does not change during the path traversal // This assumes that the SubCell does not change during the path traversal
var tilesInRange = world.FindTilesInCircle(targetCell, range.Range / 1024 + 1) var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Range / 1024 + 1)
.Where(t => (t.CenterPosition - target).LengthSquared <= rangeSquared .Where(t => (t.CenterPosition - target).LengthSquared <= rangeSquared
&& mi.CanEnterCell(self.World, self, t, null, true, true)); && mi.CanEnterCell(self.World, self, t, null, true, true));

View File

@@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA
var total = (double)world.Map.Bounds.Width * world.Map.Bounds.Height; var total = (double)world.Map.Bounds.Width * world.Map.Bounds.Height;
MapControl = world.Actors MapControl = world.Actors
.Where(a => !a.IsDead() && a.IsInWorld && a.Owner == player && a.HasTrait<RevealsShroud>()) .Where(a => !a.IsDead() && a.IsInWorld && a.Owner == player && a.HasTrait<RevealsShroud>())
.SelectMany(a => world.FindTilesInCircle(a.Location, a.Trait<RevealsShroud>().Range.Clamp(WRange.Zero, WRange.FromCells(50)).Range / 1024)) .SelectMany(a => world.Map.FindTilesInCircle(a.Location, a.Trait<RevealsShroud>().Range.Clamp(WRange.Zero, WRange.FromCells(50)).Range / 1024))
.Distinct() .Distinct()
.Count() / total; .Count() / total;
} }

View File

@@ -52,8 +52,8 @@ namespace OpenRA.Mods.RA
return; return;
// Spawn support units in an annulus around the base actor // Spawn support units in an annulus around the base actor
var supportSpawnCells = w.FindTilesInCircle(sp, unitGroup.OuterSupportRadius) var supportSpawnCells = w.Map.FindTilesInCircle(sp, unitGroup.OuterSupportRadius)
.Except(w.FindTilesInCircle(sp, unitGroup.InnerSupportRadius)); .Except(w.Map.FindTilesInCircle(sp, unitGroup.InnerSupportRadius));
foreach (var s in unitGroup.SupportActors) foreach (var s in unitGroup.SupportActors)
{ {

View File

@@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA
public IEnumerable<Actor> UnitsInRange(CPos xy) public IEnumerable<Actor> UnitsInRange(CPos xy)
{ {
var range = ((ChronoshiftPowerInfo)Info).Range; var range = ((ChronoshiftPowerInfo)Info).Range;
var tiles = self.World.FindTilesInCircle(xy, range); var tiles = self.World.Map.FindTilesInCircle(xy, range);
var units = new List<Actor>(); var units = new List<Actor>();
foreach (var t in tiles) foreach (var t in tiles)
units.AddRange(self.World.ActorMap.GetUnitsAt(t)); units.AddRange(self.World.ActorMap.GetUnitsAt(t));
@@ -69,8 +69,8 @@ namespace OpenRA.Mods.RA
return false; return false;
var range = ((ChronoshiftPowerInfo)Info).Range; var range = ((ChronoshiftPowerInfo)Info).Range;
var sourceTiles = self.World.FindTilesInCircle(xy, range); var sourceTiles = self.World.Map.FindTilesInCircle(xy, range);
var destTiles = self.World.FindTilesInCircle(sourceLocation, range); var destTiles = self.World.Map.FindTilesInCircle(sourceLocation, range);
using (var se = sourceTiles.GetEnumerator()) using (var se = sourceTiles.GetEnumerator())
using (var de = destTiles.GetEnumerator()) using (var de = destTiles.GetEnumerator())
@@ -134,7 +134,7 @@ namespace OpenRA.Mods.RA
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) public IEnumerable<IRenderable> Render(WorldRenderer wr, World world)
{ {
var xy = wr.Position(wr.Viewport.ViewToWorldPx(Viewport.LastMousePos)).ToCPos(); var xy = wr.Position(wr.Viewport.ViewToWorldPx(Viewport.LastMousePos)).ToCPos();
var tiles = world.FindTilesInCircle(xy, range); var tiles = world.Map.FindTilesInCircle(xy, range);
var pal = wr.Palette("terrain"); var pal = wr.Palette("terrain");
foreach (var t in tiles) foreach (var t in tiles)
yield return new SpriteRenderable(tile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true); yield return new SpriteRenderable(tile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true);
@@ -216,11 +216,11 @@ namespace OpenRA.Mods.RA
var pal = wr.Palette("terrain"); var pal = wr.Palette("terrain");
// Source tiles // Source tiles
foreach (var t in world.FindTilesInCircle(sourceLocation, range)) foreach (var t in world.Map.FindTilesInCircle(sourceLocation, range))
yield return new SpriteRenderable(sourceTile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true); yield return new SpriteRenderable(sourceTile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true);
// Destination tiles // Destination tiles
foreach (var t in world.FindTilesInCircle(xy, range)) foreach (var t in world.Map.FindTilesInCircle(xy, range))
yield return new SpriteRenderable(sourceTile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true); yield return new SpriteRenderable(sourceTile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true);
// Unit previews // Unit previews

View File

@@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA
public IEnumerable<Actor> UnitsInRange(CPos xy) public IEnumerable<Actor> UnitsInRange(CPos xy)
{ {
int range = ((IronCurtainPowerInfo)Info).Range; int range = ((IronCurtainPowerInfo)Info).Range;
var tiles = self.World.FindTilesInCircle(xy, range); var tiles = self.World.Map.FindTilesInCircle(xy, range);
var units = new List<Actor>(); var units = new List<Actor>();
foreach (var t in tiles) foreach (var t in tiles)
units.AddRange(self.World.ActorMap.GetUnitsAt(t)); units.AddRange(self.World.ActorMap.GetUnitsAt(t));
@@ -110,7 +110,7 @@ namespace OpenRA.Mods.RA
{ {
var xy = wr.Position(wr.Viewport.ViewToWorldPx(Viewport.LastMousePos)).ToCPos(); var xy = wr.Position(wr.Viewport.ViewToWorldPx(Viewport.LastMousePos)).ToCPos();
var pal = wr.Palette("terrain"); var pal = wr.Palette("terrain");
foreach (var t in world.FindTilesInCircle(xy, range)) foreach (var t in world.Map.FindTilesInCircle(xy, range))
yield return new SpriteRenderable(tile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true); yield return new SpriteRenderable(tile, t.CenterPosition, WVec.Zero, -511, pal, 1f, true);
} }