Add a SubCell field to UIM. Allow UIM to query for units by subcell.

This commit is contained in:
Paul Chote
2011-02-02 21:27:32 +13:00
parent 451e06190f
commit 4b3c6cc62a
16 changed files with 60 additions and 29 deletions

View File

@@ -82,10 +82,20 @@ namespace OpenRA.Traits
int2 PxPosition { get; }
}
public enum SubCell
{
FullCell,
TopLeft,
TopRight,
Center,
BottomLeft,
BottomRight
}
public interface IOccupySpace : IHasLocation
{
int2 TopLeft { get; }
IEnumerable<int2> OccupiedCells();
IEnumerable<Pair<int2, SubCell>> OccupiedCells();
}
public static class IOccupySpaceExts
@@ -96,10 +106,10 @@ namespace OpenRA.Traits
var nearestDistance = int.MaxValue;
foreach( var cell in ios.OccupiedCells() )
{
var dist = ( other - cell ).LengthSquared;
var dist = ( other - cell.First ).LengthSquared;
if( dist < nearestDistance )
{
nearest = cell;
nearest = cell.First;
nearestDistance = dist;
}
}

View File

@@ -136,7 +136,7 @@ namespace OpenRA.Traits
if (ios != null)
{
var cells = ios.OccupiedCells();
if (cells.Any()) return cells;
if (cells.Any()) return cells.Select(c => c.First);
}
return new[] { a.CenterLocation / Game.CellSize };

View File

@@ -26,6 +26,7 @@ namespace OpenRA.Traits
class InfluenceNode
{
public InfluenceNode next;
public SubCell subCell;
public Actor actor;
}
@@ -51,21 +52,32 @@ namespace OpenRA.Traits
public bool AnyUnitsAt(int2 a)
{
return /*map.IsInMap(a) && */influence[ a.X, a.Y ] != null;
return influence[ a.X, a.Y ] != null;
}
public bool AnyUnitsAt(int2 a, SubCell sub)
{
var node = influence[ a.X, a.Y ];
while (node != null)
{
if (node.subCell == sub) return true;
node = node.next;
}
return false;
}
public void Add( Actor self, IOccupySpace unit )
{
if (unit != null)
foreach( var c in unit.OccupiedCells() )
influence[ c.X, c.Y ] = new InfluenceNode { next = influence[ c.X, c.Y ], actor = self };
influence[ c.First.X, c.First.Y ] = new InfluenceNode { next = influence[ c.First.X, c.First.Y ], subCell = c.Second, actor = self };
}
public void Remove( Actor self, IOccupySpace unit )
{
if (unit != null)
foreach (var c in unit.OccupiedCells())
RemoveInner( ref influence[ c.X, c.Y ], self );
RemoveInner( ref influence[ c.First.X, c.First.Y ], self );
}
void RemoveInner( ref InfluenceNode influenceNode, Actor toRemove )

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA.Activities
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if (target.Owner == self.Owner) return NextActivity;
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x == self.Location ) )
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x.First == self.Location ) )
return NextActivity;
// todo: clean this up

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA.Activities
if (IsCanceled) return NextActivity;
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x == self.Location ) )
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x.First == self.Location ) )
return NextActivity;
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(25 * 2,

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.RA.Activities
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if (target.Owner == self.Owner) return NextActivity;
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x == self.Location ) )
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x.First == self.Location ) )
return NextActivity;
foreach (var t in target.TraitsImplementing<IAcceptSpy>())

View File

@@ -39,8 +39,8 @@ namespace OpenRA.Mods.RA.Activities
};
foreach( var cell in target.Trait<IOccupySpace>().OccupiedCells() )
{
ps1.AddInitialCell( cell );
if( ( mobile.toCell - cell ).LengthSquared <= 2 )
ps1.AddInitialCell( cell.First );
if( ( mobile.toCell - cell.First ).LengthSquared <= 2 )
return NextActivity;
}
ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );

View File

@@ -24,7 +24,7 @@ namespace OpenRA.Mods.RA.Activities
{
if (IsCanceled) return NextActivity;
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x == self.Location ) )
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x.First == self.Location ) )
return NextActivity;
var health = target.Trait<Health>();

View File

@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA.Air
{
@@ -135,8 +136,8 @@ namespace OpenRA.Mods.RA.Air
}
}
int2[] noCells = new int2[] { };
public IEnumerable<int2> OccupiedCells() { return noCells; }
Pair<int2, SubCell>[] noCells = new Pair<int2, SubCell>[] { };
public IEnumerable<Pair<int2, SubCell>> OccupiedCells() { return noCells; }
public void TickMove( int speed, int facing )
{

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA
{
if (Space == null)
Space = self.Trait<IOccupySpace>();
return Space.OccupiedCells();
return Space.OccupiedCells().Select(c => c.First);
}
}

View File

@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA.Buildings
{
@@ -110,9 +111,9 @@ namespace OpenRA.Mods.RA.Buildings
get { return topLeft; }
}
public IEnumerable<int2> OccupiedCells()
public IEnumerable<Pair<int2, SubCell>> OccupiedCells()
{
return FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft );
return FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft ).Select(c => Pair.New(c, SubCell.FullCell));
}
public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner)

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.RA
}
public int2 TopLeft { get { return Location; } }
public IEnumerable<int2> OccupiedCells() { return new int2[] { Location }; }
public IEnumerable<Pair<int2, SubCell>> OccupiedCells() { yield return Pair.New( Location, SubCell.FullCell); }
public int2 PxPosition { get; private set; }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA
{
@@ -36,7 +37,7 @@ namespace OpenRA.Mods.RA
public int2 TopLeft { get { return location; } }
public IEnumerable<int2> OccupiedCells() { yield return TopLeft; }
public IEnumerable<Pair<int2, SubCell>> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); }
public int2 PxPosition { get { return Util.CenterOfCell( location ); } }
}
}

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic;
using OpenRA.Mods.RA.Activities;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA
{
@@ -53,7 +54,7 @@ namespace OpenRA.Mods.RA
public int2 TopLeft { get { return location; } }
public IEnumerable<int2> OccupiedCells() { yield return TopLeft; }
public IEnumerable<Pair<int2, SubCell>> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); }
public int2 PxPosition { get { return Util.CenterOfCell( location ); } }
}

View File

@@ -271,13 +271,17 @@ namespace OpenRA.Mods.RA.Move
public int2 TopLeft { get { return toCell; } }
public IEnumerable<int2> OccupiedCells()
public IEnumerable<Pair<int2, SubCell>> OccupiedCells()
{
return (fromCell == toCell)
? new[] { fromCell }
: CanEnterCell(toCell)
? new[] { toCell }
: new[] { fromCell, toCell };
if (fromCell == toCell)
yield return Pair.New(fromCell, SubCell.FullCell);
else if (CanEnterCell(toCell))
yield return Pair.New(toCell, SubCell.FullCell);
else
{
yield return Pair.New(fromCell, SubCell.FullCell);
yield return Pair.New(toCell, SubCell.FullCell);
}
}
public bool CanEnterCell(int2 p)

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
using System.Linq;
namespace OpenRA.Mods.RA
{
@@ -32,7 +33,7 @@ namespace OpenRA.Mods.RA
public bool TargetableBy(Actor self, Actor byActor) { return true; }
public IEnumerable<int2> TargetableCells( Actor self )
{
return self.Trait<Building>().OccupiedCells();
return self.Trait<Building>().OccupiedCells().Select(c => c.First);
}
}
}