Replace dynamic Actor.Bounds with the (unchanging) relative rect.

This commit is contained in:
Paul Chote
2013-09-21 17:15:46 +12:00
parent 3f8d75a1ac
commit ad44610e5a
6 changed files with 77 additions and 78 deletions

View File

@@ -24,13 +24,11 @@ namespace OpenRA
public readonly World World;
public readonly uint ActorID;
public Lazy<Rectangle> Bounds;
Lazy<IOccupySpace> occupySpace;
Lazy<IFacing> facing;
public Cached<Rectangle> Bounds;
public Cached<Rectangle> ExtendedBounds;
public IOccupySpace OccupiesSpace { get { return occupySpace.Value; } }
public CPos Location { get { return occupySpace.Value.TopLeft; } }
@@ -76,27 +74,25 @@ namespace OpenRA
facing = Lazy.New(() => TraitOrDefault<IFacing>());
size = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null)
return new int2(si.Bounds[0], si.Bounds[1]);
return TraitsImplementing<IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();
});
applyIRender = (x, wr) => x.Render(this, wr);
applyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m);
Bounds = Cached.New(() => CalculateBounds(false));
ExtendedBounds = Cached.New(() => CalculateBounds(true));
Bounds = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
var size = (si != null && si.Bounds != null) ? new int2(si.Bounds[0], si.Bounds[1]) :
TraitsImplementing<IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();
var offset = -size / 2;
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
offset += new int2(si.Bounds[2], si.Bounds[3]);
return new Rectangle(offset.X, offset.Y, size.X, size.Y);
});
}
public void Tick()
{
Bounds.Invalidate();
ExtendedBounds.Invalidate();
currentActivity = Traits.Util.RunActivity(this, currentActivity);
}
@@ -105,8 +101,6 @@ namespace OpenRA
get { return currentActivity == null; }
}
OpenRA.FileFormats.Lazy<int2> size;
// note: these delegates are cached to avoid massive allocation.
Func<IRender, WorldRenderer, IEnumerable<IRenderable>> applyIRender;
Func<IEnumerable<IRenderable>, IRenderModifier, WorldRenderer, IEnumerable<IRenderable>> applyRenderModifier;
@@ -117,34 +111,6 @@ namespace OpenRA
return mods.Aggregate(sprites, (m, p) => applyRenderModifier(m, p, wr));
}
// When useAltitude = true, the bounding box is extended
// vertically to altitude = 0 to support FindUnitsInCircle queries
// When false, the bounding box is given for the actor
// at its current altitude
Rectangle CalculateBounds(bool useAltitude)
{
var sizeVector = (PVecInt)size.Value;
var loc = CenterLocation - sizeVector / 2;
var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
{
loc += new PVecInt(si.Bounds[2], si.Bounds[3]);
}
var ios = occupySpace.Value;
if (ios != null)
{
var altitude = ios.CenterPosition.Z * Game.CellSize / 1024;
loc -= new PVecInt(0, altitude);
if (useAltitude)
sizeVector = new PVecInt(sizeVector.X, sizeVector.Y + altitude);
}
return new Rectangle(loc.X, loc.Y, sizeVector.X, sizeVector.Y);
}
public bool IsInWorld { get; internal set; }
public void QueueActivity(bool queued, Activity nextActivity)

View File

@@ -150,14 +150,15 @@ namespace OpenRA.Graphics
Game.Renderer.Flush();
}
public void DrawSelectionBox(Actor selectedUnit, Color c)
public void DrawSelectionBox(Actor a, Color c)
{
var bounds = selectedUnit.Bounds.Value;
var pos = ScreenPxPosition(a.CenterPosition);
var bounds = a.Bounds.Value;
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
var xY = new float2(bounds.Left, bounds.Bottom);
var XY = new float2(bounds.Right, bounds.Bottom);
var xy = pos + new float2(bounds.Left, bounds.Top);
var Xy = pos + new float2(bounds.Right, bounds.Top);
var xY = pos + new float2(bounds.Left, bounds.Bottom);
var XY = pos + new float2(bounds.Right, bounds.Bottom);
var wlr = Game.Renderer.WorldLineRenderer;
wlr.DrawLine(xy, xy + new float2(4, 0), c, c);

View File

@@ -40,7 +40,9 @@ namespace OpenRA.Traits
if (!Info.Selectable)
return;
var pos = wr.ScreenPxPosition(self.CenterPosition);
var bounds = self.Bounds.Value;
bounds.Offset(pos.X, pos.Y);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
@@ -56,7 +58,9 @@ namespace OpenRA.Traits
if (!Info.Selectable)
return;
var pos = wr.ScreenPxPosition(self.CenterPosition);
var bounds = self.Bounds.Value;
bounds.Offset(pos.X, pos.Y);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);

View File

@@ -34,7 +34,10 @@ namespace OpenRA.Traits
if (self.World.FogObscures(self))
return;
var pos = wr.ScreenPxPosition(self.CenterPosition);
var bounds = self.Bounds.Value;
bounds.Offset(pos.X, pos.Y);
var xy = new float2(bounds.Left, bounds.Top);
var xY = new float2(bounds.Left, bounds.Bottom);

View File

@@ -26,11 +26,12 @@ namespace OpenRA.Traits
public object Create(ActorInitializer init) { return new ScreenMap(init.world, this); }
}
public class ScreenMap
public class ScreenMap : IWorldLoaded
{
ScreenMapInfo info;
Cache<Player, List<FrozenActor>[]> frozen;
List<Actor>[] actors;
WorldRenderer worldRenderer;
Cache<Player, Dictionary<FrozenActor, Rectangle>[]> frozen;
Dictionary<Actor, Rectangle>[] actors;
int rows, cols;
public ScreenMap(World world, ScreenMapInfo info)
@@ -39,33 +40,39 @@ namespace OpenRA.Traits
cols = world.Map.MapSize.X * Game.CellSize / info.BinSize + 1;
rows = world.Map.MapSize.Y * Game.CellSize / info.BinSize + 1;
frozen = new Cache<Player, List<FrozenActor>[]>(InitializeFrozenActors);
actors = new List<Actor>[rows * cols];
frozen = new Cache<Player, Dictionary<FrozenActor, Rectangle>[]>(InitializeFrozenActors);
actors = new Dictionary<Actor, Rectangle>[rows * cols];
for (var j = 0; j < rows; j++)
for (var i = 0; i < cols; i++)
actors[j * cols + i] = new List<Actor>();
actors[j * cols + i] = new Dictionary<Actor, Rectangle>();
}
List<FrozenActor>[] InitializeFrozenActors(Player p)
public void WorldLoaded(World w, WorldRenderer wr) { worldRenderer = wr; }
Dictionary<FrozenActor, Rectangle>[] InitializeFrozenActors(Player p)
{
var f = new List<FrozenActor>[rows * cols];
var f = new Dictionary<FrozenActor, Rectangle>[rows * cols];
for (var j = 0; j < rows; j++)
for (var i = 0; i < cols; i++)
f[j * cols + i] = new List<FrozenActor>();
f[j * cols + i] = new Dictionary<FrozenActor, Rectangle>();
return f;
}
public void Add(Player viewer, FrozenActor fa)
{
var top = Math.Max(0, fa.Bounds.Top / info.BinSize);
var left = Math.Max(0, fa.Bounds.Left / info.BinSize);
var bottom = Math.Min(rows - 1, fa.Bounds.Bottom / info.BinSize);
var right = Math.Min(cols - 1, fa.Bounds.Right / info.BinSize);
var pos = worldRenderer.ScreenPxPosition(fa.CenterPosition);
var bounds = fa.Bounds;
bounds.Offset(pos.X, pos.Y);
var top = Math.Max(0, bounds.Top / info.BinSize);
var left = Math.Max(0, bounds.Left / info.BinSize);
var bottom = Math.Min(rows - 1, bounds.Bottom / info.BinSize);
var right = Math.Min(cols - 1, bounds.Right / info.BinSize);
for (var j = top; j <= bottom; j++)
for (var i = left; i <= right; i++)
frozen[viewer][j*cols + i].Add(fa);
frozen[viewer][j*cols + i].Add(fa, bounds);
}
public void Remove(Player viewer, FrozenActor fa)
@@ -76,15 +83,18 @@ namespace OpenRA.Traits
public void Add(Actor a)
{
var b = a.Bounds.Value;
var top = Math.Max(0, b.Top / info.BinSize);
var left = Math.Max(0, b.Left / info.BinSize);
var bottom = Math.Min(rows - 1, b.Bottom / info.BinSize);
var right = Math.Min(cols - 1, b.Right / info.BinSize);
var pos = worldRenderer.ScreenPxPosition(a.CenterPosition);
var bounds = a.Bounds.Value;
bounds.Offset(pos.X, pos.Y);
var top = Math.Max(0, bounds.Top / info.BinSize);
var left = Math.Max(0, bounds.Left / info.BinSize);
var bottom = Math.Min(rows - 1, bounds.Bottom / info.BinSize);
var right = Math.Min(cols - 1, bounds.Right / info.BinSize);
for (var j = top; j <= bottom; j++)
for (var i = left; i <= right; i++)
actors[j * cols + i].Add(a);
actors[j * cols + i].Add(a, bounds);
}
public void Remove(Actor a)
@@ -103,14 +113,18 @@ namespace OpenRA.Traits
{
var i = (pxPos.X / info.BinSize).Clamp(0, cols - 1);
var j = (pxPos.Y / info.BinSize).Clamp(0, rows - 1);
return frozen[viewer][j*cols + i].Where(fa => fa.Bounds.Contains(pxPos) && fa.IsValid);
return frozen[viewer][j*cols + i]
.Where(kv => kv.Key.IsValid && kv.Value.Contains(pxPos))
.Select(kv => kv.Key);
}
public IEnumerable<Actor> ActorsAt(int2 pxPos)
{
var i = (pxPos.X / info.BinSize).Clamp(0, cols - 1);
var j = (pxPos.Y / info.BinSize).Clamp(0, rows - 1);
return actors[j*cols + i].Where(a => a.Bounds.Value.Contains(pxPos) && a.IsInWorld);
return actors[j * cols + i]
.Where(kv => kv.Key.IsInWorld && kv.Value.Contains(pxPos))
.Select(kv => kv.Key);
}
// Legacy fallback
@@ -129,9 +143,17 @@ namespace OpenRA.Traits
var bottom = (r.Bottom / info.BinSize).Clamp(0, rows - 1);
for (var j = top; j <= bottom; j++)
{
for (var i = left; i <= right; i++)
foreach (var a in actors[j*cols + i].Where(b => b.Bounds.Value.IntersectsWith(r) && b.IsInWorld))
{
var ret = actors[j * cols + i]
.Where(kv => kv.Key.IsInWorld && kv.Value.IntersectsWith(r))
.Select(kv => kv.Key);
foreach (var a in ret)
yield return a;
}
}
}
}
}

View File

@@ -117,9 +117,12 @@ namespace OpenRA.Mods.RA
if (self.World.FogObscures(self))
yield break;
var pos = wr.ScreenPxPosition(self.CenterPosition);
var bounds = self.Bounds.Value;
var pos = new PPos(bounds.Right, bounds.Bottom - 2).ToWPos(0);
yield return new SpriteRenderable(RankAnim.Image, pos, WVec.Zero, 0, wr.Palette("effect"), 1f, true);
bounds.Offset(pos.X, pos.Y);
var effectPos = new PPos(bounds.Right, bounds.Bottom - 2).ToWPos(0);
yield return new SpriteRenderable(RankAnim.Image, effectPos, WVec.Zero, 0, wr.Palette("effect"), 1f, true);
}
}