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

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

View File

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

View File

@@ -26,9 +26,10 @@ namespace OpenRA.Traits
class InfluenceNode class InfluenceNode
{ {
public InfluenceNode next; public InfluenceNode next;
public SubCell subCell;
public Actor actor; public Actor actor;
} }
InfluenceNode[,] influence; InfluenceNode[,] influence;
Map map; Map map;
@@ -51,21 +52,32 @@ namespace OpenRA.Traits
public bool AnyUnitsAt(int2 a) 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 ) public void Add( Actor self, IOccupySpace unit )
{ {
if (unit != null) if (unit != null)
foreach( var c in unit.OccupiedCells() ) 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 ) public void Remove( Actor self, IOccupySpace unit )
{ {
if (unit != null) if (unit != null)
foreach (var c in unit.OccupiedCells()) 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 ) 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 == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if (target.Owner == self.Owner) 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; return NextActivity;
// todo: clean this up // todo: clean this up

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA.Activities
if (IsCanceled) return NextActivity; if (IsCanceled) return NextActivity;
if (target == null || !target.IsInWorld || target.IsDead()) 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; return NextActivity;
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(25 * 2, 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 == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if (target.Owner == self.Owner) 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; return NextActivity;
foreach (var t in target.TraitsImplementing<IAcceptSpy>()) 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() ) foreach( var cell in target.Trait<IOccupySpace>().OccupiedCells() )
{ {
ps1.AddInitialCell( cell ); ps1.AddInitialCell( cell.First );
if( ( mobile.toCell - cell ).LengthSquared <= 2 ) if( ( mobile.toCell - cell.First ).LengthSquared <= 2 )
return NextActivity; return NextActivity;
} }
ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell ); ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );

View File

@@ -24,7 +24,7 @@ namespace OpenRA.Mods.RA.Activities
{ {
if (IsCanceled) return NextActivity; if (IsCanceled) return NextActivity;
if (target == null || !target.IsInWorld || target.IsDead()) 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; return NextActivity;
var health = target.Trait<Health>(); var health = target.Trait<Health>();

View File

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

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA
{ {
if (Space == null) if (Space == null)
Space = self.Trait<IOccupySpace>(); 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.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA.Buildings namespace OpenRA.Mods.RA.Buildings
{ {
@@ -110,9 +111,9 @@ namespace OpenRA.Mods.RA.Buildings
get { return topLeft; } 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) 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 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; } public int2 PxPosition { get; private set; }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {
@@ -36,7 +37,7 @@ namespace OpenRA.Mods.RA
public int2 TopLeft { get { return location; } } 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 ); } } public int2 PxPosition { get { return Util.CenterOfCell( location ); } }
} }
} }

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {
@@ -53,7 +54,7 @@ namespace OpenRA.Mods.RA
public int2 TopLeft { get { return location; } } 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 ); } } 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 int2 TopLeft { get { return toCell; } }
public IEnumerable<int2> OccupiedCells() public IEnumerable<Pair<int2, SubCell>> OccupiedCells()
{ {
return (fromCell == toCell) if (fromCell == toCell)
? new[] { fromCell } yield return Pair.New(fromCell, SubCell.FullCell);
: CanEnterCell(toCell) else if (CanEnterCell(toCell))
? new[] { toCell } yield return Pair.New(toCell, SubCell.FullCell);
: new[] { fromCell, toCell }; else
{
yield return Pair.New(fromCell, SubCell.FullCell);
yield return Pair.New(toCell, SubCell.FullCell);
}
} }
public bool CanEnterCell(int2 p) public bool CanEnterCell(int2 p)

View File

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