Replace dynamic Actor.Bounds with the (unchanging) relative rect.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user