Split Actor.Bounds into RenderBounds and SelectableBounds

Additionally, internally renamed VisualBounds to SelectionOverlayBounds to avoid confusion with RenderBounds.

This step was necessary to prevent actors with selectable area smaller than their graphics to be removed too early from ScreenMap even though part of the graphics should still be visible.
RA cruisers were a prime example, but to a lesser extent several other actors were affected as well.

This separation also serves as preparation to determine the final RenderBounds from multiple source bounds later, to fix the remaining ScreenMap issues (building 'bibs', aircraft shadows).
This commit is contained in:
reaperrr
2017-08-25 13:18:09 +02:00
committed by Pavel Penev
parent ca1448c7ba
commit be290cfabd
15 changed files with 52 additions and 33 deletions

View File

@@ -47,8 +47,9 @@ namespace OpenRA
public int Generation;
public Rectangle Bounds { get; private set; }
public Rectangle VisualBounds { get; private set; }
public Rectangle RenderBounds { get; private set; }
public Rectangle SelectableBounds { get; private set; }
public Rectangle SelectionOverlayBounds { get; private set; }
public IEffectiveOwner EffectiveOwner { get; private set; }
public IOccupySpace OccupiesSpace { get; private set; }
public ITargetable[] Targetables { get; private set; }
@@ -110,8 +111,14 @@ namespace OpenRA
// PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
// actor that allows us to provide some fast implementations of commonly used methods that are relied on by
// performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
Bounds = DetermineBounds();
VisualBounds = DetermineVisualBounds();
// RenderBounds are used for ScreenMap binning
// SelectableBounds define the selectable area of the actor
// SelectionOverlayBounds are used to draw the selection box and determine offsets for other selection overlays
RenderBounds = DetermineRenderBounds();
SelectableBounds = DetermineSelectableBounds();
SelectionOverlayBounds = DetermineSelectionOverlayBounds();
EffectiveOwner = TraitOrDefault<IEffectiveOwner>();
facing = TraitOrDefault<IFacing>();
health = TraitOrDefault<IHealth>();
@@ -129,24 +136,34 @@ namespace OpenRA
.Select(pair => new SyncHash(pair.First, pair.Second(pair.First)));
}
Rectangle DetermineBounds()
Rectangle DetermineRenderBounds()
{
var size = TraitsImplementing<IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();
var offset = -size / 2;
return new Rectangle(offset.X, offset.Y, size.X, size.Y);
}
Rectangle DetermineSelectableBounds()
{
var si = Info.TraitInfoOrDefault<SelectableInfo>();
var size = (si != null && si.Bounds != null) ? new int2(si.Bounds[0], si.Bounds[1]) :
TraitsImplementing<IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();
if (si == null || si.Bounds == null)
return RenderBounds;
var size = new int2(si.Bounds[0], si.Bounds[1]);
var offset = -size / 2;
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
if (si.Bounds.Length > 2)
offset += new int2(si.Bounds[2], si.Bounds[3]);
return new Rectangle(offset.X, offset.Y, size.X, size.Y);
}
Rectangle DetermineVisualBounds()
Rectangle DetermineSelectionOverlayBounds()
{
var sd = Info.TraitInfoOrDefault<ISelectionDecorationsInfo>();
if (sd == null || sd.SelectionBoxBounds == null)
return Bounds;
return SelectableBounds;
var size = new int2(sd.SelectionBoxBounds[0], sd.SelectionBoxBounds[1]);

View File

@@ -149,7 +149,7 @@ namespace OpenRA.Graphics
var health = actor.TraitOrDefault<IHealth>();
var screenPos = wr.Screen3DPxPosition(pos);
var bounds = actor.VisualBounds;
var bounds = actor.SelectionOverlayBounds;
bounds.Offset((int)screenPos.X, (int)screenPos.Y);
var start = new float3(bounds.Left + 1, bounds.Top, screenPos.Z);

View File

@@ -47,12 +47,12 @@ namespace OpenRA.Traits
public static Actor WithHighestSelectionPriority(this IEnumerable<Actor> actors, int2 selectionPixel)
{
return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.Bounds, selectionPixel));
return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.SelectableBounds, selectionPixel));
}
public static FrozenActor WithHighestSelectionPriority(this IEnumerable<FrozenActor> actors, int2 selectionPixel)
{
return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.Bounds, selectionPixel));
return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.SelectableBounds, selectionPixel));
}
static long CalculateActorSelectionPriority(ActorInfo info, Rectangle bounds, int2 selectionPixel)

View File

@@ -31,7 +31,8 @@ namespace OpenRA.Traits
{
public readonly PPos[] Footprint;
public readonly WPos CenterPosition;
public readonly Rectangle Bounds;
public readonly Rectangle RenderBounds;
public readonly Rectangle SelectableBounds;
public readonly HashSet<string> TargetTypes;
readonly Actor actor;
readonly Shroud shroud;
@@ -77,7 +78,8 @@ namespace OpenRA.Traits
footprint.Select(p => shroud.Contains(p).ToString()).JoinWith("|")));
CenterPosition = self.CenterPosition;
Bounds = self.Bounds;
RenderBounds = self.RenderBounds;
SelectableBounds = self.SelectableBounds;
TargetTypes = self.GetEnabledTargetTypes().ToHashSet();
tooltips = self.TraitsImplementing<ITooltip>().ToArray();

View File

@@ -53,7 +53,7 @@ namespace OpenRA.Traits
Rectangle FrozenActorBounds(FrozenActor fa)
{
var pos = worldRenderer.ScreenPxPosition(fa.CenterPosition);
var bounds = fa.Bounds;
var bounds = fa.RenderBounds;
bounds.Offset(pos.X, pos.Y);
return bounds;
}
@@ -61,7 +61,7 @@ namespace OpenRA.Traits
Rectangle ActorBounds(Actor a)
{
var pos = worldRenderer.ScreenPxPosition(a.CenterPosition);
var bounds = a.Bounds;
var bounds = a.RenderBounds;
bounds.Offset(pos.X, pos.Y);
return bounds;
}

View File

@@ -192,7 +192,7 @@ namespace OpenRA
ActorMap.AddInfluence(self, ios);
ActorMap.AddPosition(self, ios);
if (!self.Bounds.Size.IsEmpty)
if (!self.RenderBounds.Size.IsEmpty)
ScreenMap.Add(self);
}
@@ -201,7 +201,7 @@ namespace OpenRA
if (!self.IsInWorld)
return;
if (!self.Bounds.Size.IsEmpty)
if (!self.RenderBounds.Size.IsEmpty)
ScreenMap.Update(self);
ActorMap.UpdatePosition(self, ios);
@@ -212,7 +212,7 @@ namespace OpenRA
ActorMap.RemoveInfluence(self, ios);
ActorMap.RemovePosition(self, ios);
if (!self.Bounds.Size.IsEmpty)
if (!self.RenderBounds.Size.IsEmpty)
ScreenMap.Remove(self);
}