Introduce a new type for representing map coordinates.

To resolve the ambiguity introduced when the introduction of isometric maps meant that cell and map coordinates were no longer equivalent, a new type has been introduced so they can each be represented separately.
This commit is contained in:
RoosterDragon
2014-12-22 19:07:20 +00:00
parent 40c9d0a47d
commit 7cfece6dc0
21 changed files with 257 additions and 232 deletions

View File

@@ -48,14 +48,13 @@ namespace OpenRA
// Resolve an array index from cell coordinates
int Index(CPos cell)
{
var uv = Map.CellToMap(Shape, cell);
return Index(uv.X, uv.Y);
return Index(cell.ToMPos(Shape));
}
// Resolve an array index from map coordinates
int Index(int u, int v)
int Index(MPos uv)
{
return v * Size.Width + u;
return uv.V * Size.Width + uv.U;
}
/// <summary>Gets or sets the <see cref="OpenRA.CellLayer"/> using cell coordinates</summary>
@@ -76,19 +75,19 @@ namespace OpenRA
}
/// <summary>Gets or sets the layer contents using raw map coordinates (not CPos!)</summary>
public T this[int u, int v]
public T this[MPos uv]
{
get
{
return entries[Index(u, v)];
return entries[Index(uv)];
}
set
{
entries[Index(u, v)] = value;
entries[Index(uv)] = value;
if (CellEntryChanged != null)
CellEntryChanged(Map.MapToCell(Shape, new CPos(u, v)));
CellEntryChanged(uv.ToCPos(Shape));
}
}
@@ -123,7 +122,7 @@ namespace OpenRA
result.Clear(defaultValue);
for (var j = 0; j < height; j++)
for (var i = 0; i < width; i++)
result[i, j] = layer[i, j];
result[new MPos(i, j)] = layer[new MPos(i, j)];
return result;
}

View File

@@ -26,8 +26,8 @@ namespace OpenRA
// Corners in map coordinates
// These will only equal TopLeft and BottomRight for TileShape.Rectangular
readonly CPos mapTopLeft;
readonly CPos mapBottomRight;
readonly MPos mapTopLeft;
readonly MPos mapBottomRight;
public CellRegion(TileShape shape, CPos topLeft, CPos bottomRight)
{
@@ -35,17 +35,15 @@ namespace OpenRA
TopLeft = topLeft;
BottomRight = bottomRight;
mapTopLeft = Map.CellToMap(shape, TopLeft);
mapBottomRight = Map.CellToMap(shape, BottomRight);
mapTopLeft = TopLeft.ToMPos(shape);
mapBottomRight = BottomRight.ToMPos(shape);
}
/// <summary>Expand the specified region with an additional cordon. This may expand the region outside the map borders.</summary>
public static CellRegion Expand(CellRegion region, int cordon)
{
var offset = new CVec(cordon, cordon);
var tl = Map.MapToCell(region.shape, Map.CellToMap(region.shape, region.TopLeft) - offset);
var br = Map.MapToCell(region.shape, Map.CellToMap(region.shape, region.BottomRight) + offset);
var tl = new MPos(region.mapTopLeft.U - cordon, region.mapTopLeft.V - cordon).ToCPos(region.shape);
var br = new MPos(region.mapBottomRight.U + cordon, region.mapBottomRight.V + cordon).ToCPos(region.shape);
return new CellRegion(region.shape, tl, br);
}
@@ -83,8 +81,8 @@ namespace OpenRA
public bool Contains(CPos cell)
{
var uv = Map.CellToMap(shape, cell);
return uv.X >= mapTopLeft.X && uv.X <= mapBottomRight.X && uv.Y >= mapTopLeft.Y && uv.Y <= mapBottomRight.Y;
var uv = cell.ToMPos(shape);
return uv.U >= mapTopLeft.U && uv.U <= mapBottomRight.U && uv.V >= mapTopLeft.V && uv.V <= mapBottomRight.V;
}
public MapCoordsRegion MapCoords
@@ -128,25 +126,25 @@ namespace OpenRA
u += 1;
// Check for column overflow
if (u > r.mapBottomRight.X)
if (u > r.mapBottomRight.U)
{
v += 1;
u = r.mapTopLeft.X;
u = r.mapTopLeft.U;
// Check for row overflow
if (v > r.mapBottomRight.Y)
if (v > r.mapBottomRight.V)
return false;
}
current = Map.MapToCell(r.shape, new CPos(u, v));
current = new MPos(u, v).ToCPos(r.shape);
return true;
}
public void Reset()
{
// Enumerator starts *before* the first element in the sequence.
u = r.mapTopLeft.X - 1;
v = r.mapTopLeft.Y;
u = r.mapTopLeft.U - 1;
v = r.mapTopLeft.V;
}
public CPos Current { get { return current; } }
@@ -154,12 +152,12 @@ namespace OpenRA
public void Dispose() { }
}
public struct MapCoordsRegion : IEnumerable<CPos>
public struct MapCoordsRegion : IEnumerable<MPos>
{
public struct MapCoordsEnumerator : IEnumerator<CPos>
public struct MapCoordsEnumerator : IEnumerator<MPos>
{
readonly CellRegion r;
CPos current;
MPos current;
public MapCoordsEnumerator(CellRegion region)
: this()
@@ -170,30 +168,30 @@ namespace OpenRA
public bool MoveNext()
{
var u = current.X + 1;
var v = current.Y;
var u = current.U + 1;
var v = current.V;
// Check for column overflow
if (u > r.mapBottomRight.X)
if (u > r.mapBottomRight.U)
{
v += 1;
u = r.mapTopLeft.X;
u = r.mapTopLeft.U;
// Check for row overflow
if (v > r.mapBottomRight.Y)
if (v > r.mapBottomRight.V)
return false;
}
current = new CPos(u, v);
current = new MPos(u, v);
return true;
}
public void Reset()
{
current = new CPos(r.mapTopLeft.X - 1, r.mapTopLeft.Y);
current = new MPos(r.mapTopLeft.U - 1, r.mapTopLeft.V);
}
public CPos Current { get { return current; } }
public MPos Current { get { return current; } }
object IEnumerator.Current { get { return Current; } }
public void Dispose() { }
}
@@ -210,7 +208,7 @@ namespace OpenRA
return new MapCoordsEnumerator(r);
}
IEnumerator<CPos> IEnumerable<CPos>.GetEnumerator()
IEnumerator<MPos> IEnumerable<MPos>.GetEnumerator()
{
return GetEnumerator();
}

View File

@@ -367,13 +367,13 @@ namespace OpenRA
cachedTileSet = Exts.Lazy(() => Rules.TileSets[Tileset]);
var tl = Map.MapToCell(TileShape, new CPos(Bounds.Left, Bounds.Top));
var br = Map.MapToCell(TileShape, new CPos(Bounds.Right - 1, Bounds.Bottom - 1));
var tl = new MPos(Bounds.Left, Bounds.Top).ToCPos(this);
var br = new MPos(Bounds.Right - 1, Bounds.Bottom - 1).ToCPos(this);
Cells = new CellRegion(TileShape, tl, br);
CustomTerrain = new CellLayer<byte>(this);
foreach (var uv in Cells.MapCoords)
CustomTerrain[uv.X, uv.Y] = byte.MaxValue;
CustomTerrain[uv] = byte.MaxValue;
}
public Ruleset PreloadRules()
@@ -485,7 +485,7 @@ namespace OpenRA
if (index == byte.MaxValue)
index = (byte)(i % 4 + (j % 4) * 4);
tiles[i, j] = new TerrainTile(tile, index);
tiles[new MPos(i, j)] = new TerrainTile(tile, index);
}
}
}
@@ -506,7 +506,7 @@ namespace OpenRA
s.Position = header.HeightsOffset;
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
tiles[i, j] = s.ReadUInt8().Clamp((byte)0, maxHeight);
tiles[new MPos(i, j)] = s.ReadUInt8().Clamp((byte)0, maxHeight);
}
}
@@ -529,7 +529,7 @@ namespace OpenRA
{
var type = s.ReadUInt8();
var density = s.ReadUInt8();
resources[i, j] = new ResourceTile(type, density);
resources[new MPos(i, j)] = new ResourceTile(type, density);
}
}
}
@@ -566,7 +566,7 @@ namespace OpenRA
{
for (var j = 0; j < MapSize.Y; j++)
{
var tile = MapTiles.Value[i, j];
var tile = MapTiles.Value[new MPos(i, j)];
writer.Write(tile.Type);
writer.Write(tile.Index);
}
@@ -577,7 +577,7 @@ namespace OpenRA
if (heightsOffset != 0)
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
writer.Write(MapHeight.Value[i, j]);
writer.Write(MapHeight.Value[new MPos(i, j)]);
// Resource data
if (resourcesOffset != 0)
@@ -586,7 +586,7 @@ namespace OpenRA
{
for (var j = 0; j < MapSize.Y; j++)
{
var tile = MapResources.Value[i, j];
var tile = MapResources.Value[new MPos(i, j)];
writer.Write(tile.Type);
writer.Write(tile.Index);
}
@@ -599,13 +599,12 @@ namespace OpenRA
public bool Contains(CPos cell)
{
var uv = CellToMap(TileShape, cell);
return Contains(uv.X, uv.Y);
return Contains(cell.ToMPos(this));
}
public bool Contains(int u, int v)
public bool Contains(MPos uv)
{
return Bounds.Contains(u, v);
return Bounds.Contains(uv.U, uv.V);
}
public WPos CenterOfCell(CPos cell)
@@ -648,46 +647,6 @@ namespace OpenRA
return new CPos(u, v);
}
public static CPos MapToCell(TileShape shape, CPos map)
{
if (shape == TileShape.Rectangle)
return map;
// Convert from rectangular map position to diamond cell position
// - The staggered rows make this fiddly (hint: draw a diagram!)
// (a) Consider the relationships:
// - +1u (even -> odd) adds (1, -1) to (x, y)
// - +1v (even -> odd) adds (1, 0) to (x, y)
// - +1v (odd -> even) adds (0, 1) to (x, y)
// (b) Therefore:
// - au + 2bv adds (a + b) to (x, y)
// - a correction factor is added if v is odd
var offset = (map.Y & 1) == 1 ? 1 : 0;
var y = (map.Y - offset) / 2 - map.X;
var x = map.Y - y;
return new CPos(x, y);
}
public static CPos CellToMap(TileShape shape, CPos cell)
{
if (shape == TileShape.Rectangle)
return cell;
// Convert from diamond cell (x, y) position to rectangular map position (u, v)
// - The staggered rows make this fiddly (hint: draw a diagram!)
// (a) Consider the relationships:
// - +1x (even -> odd) adds (0, 1) to (u, v)
// - +1x (odd -> even) adds (1, 1) to (u, v)
// - +1y (even -> odd) adds (-1, 1) to (u, v)
// - +1y (odd -> even) adds (0, 1) to (u, v)
// (b) Therefore:
// - ax + by adds (a - b)/2 to u (only even increments count)
// - ax + by adds a + b to v
var u = (cell.X - cell.Y) / 2;
var v = cell.X + cell.Y;
return new CPos(u, v);
}
public int FacingBetween(CPos cell, CPos towards, int fallbackfacing)
{
return Traits.Util.GetFacing(CenterOfCell(towards) - CenterOfCell(cell), fallbackfacing);
@@ -700,9 +659,9 @@ namespace OpenRA
var oldMapHeight = MapHeight.Value;
var newSize = new Size(width, height);
MapTiles = Exts.Lazy(() => CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[0, 0]));
MapResources = Exts.Lazy(() => CellLayer.Resize(oldMapResources, newSize, oldMapResources[0, 0]));
MapHeight = Exts.Lazy(() => CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[0, 0]));
MapTiles = Exts.Lazy(() => CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]));
MapResources = Exts.Lazy(() => CellLayer.Resize(oldMapResources, newSize, oldMapResources[MPos.Zero]));
MapHeight = Exts.Lazy(() => CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]));
MapSize = new int2(newSize);
}
@@ -710,8 +669,8 @@ namespace OpenRA
{
Bounds = Rectangle.FromLTRB(left, top, right, bottom);
var tl = Map.MapToCell(TileShape, new CPos(Bounds.Left, Bounds.Top));
var br = Map.MapToCell(TileShape, new CPos(Bounds.Right - 1, Bounds.Bottom - 1));
var tl = new MPos(Bounds.Left, Bounds.Top).ToCPos(this);
var br = new MPos(Bounds.Right - 1, Bounds.Bottom - 1).ToCPos(this);
Cells = new CellRegion(TileShape, tl, br);
}
@@ -781,8 +740,8 @@ namespace OpenRA
{
for (var i = Bounds.Left; i < Bounds.Right; i++)
{
var type = MapTiles.Value[i, j].Type;
var index = MapTiles.Value[i, j].Index;
var type = MapTiles.Value[new MPos(i, j)].Type;
var index = MapTiles.Value[new MPos(i, j)].Index;
if (!tileset.Templates.ContainsKey(type))
{
Console.WriteLine("Unknown Tile ID {0}".F(type));
@@ -794,18 +753,16 @@ namespace OpenRA
continue;
index = (byte)r.Next(0, template.TilesCount);
MapTiles.Value[i, j] = new TerrainTile(type, index);
MapTiles.Value[new MPos(i, j)] = new TerrainTile(type, index);
}
}
}
public byte GetTerrainIndex(CPos cell)
{
var uv = Map.CellToMap(TileShape, cell);
var u = uv.X;
var v = uv.Y;
var custom = CustomTerrain[u, v];
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[u, v]);
var uv = cell.ToMPos(this);
var custom = CustomTerrain[uv];
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]);
}
public TerrainTypeInfo GetTerrainInfo(CPos cell)
@@ -816,7 +773,7 @@ namespace OpenRA
public CPos Clamp(CPos cell)
{
var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1);
return MapToCell(TileShape, CellToMap(TileShape, cell).Clamp(bounds));
return cell.ToMPos(this).Clamp(bounds).ToCPos(this);
}
public CPos ChooseRandomCell(MersenneTwister rand)
@@ -824,7 +781,7 @@ namespace OpenRA
var x = rand.Next(Bounds.Left, Bounds.Right);
var y = rand.Next(Bounds.Top, Bounds.Bottom);
return MapToCell(TileShape, new CPos(x, y));
return new MPos(x, y).ToCPos(this);
}
public CPos ChooseRandomEdgeCell(MersenneTwister rand)
@@ -835,7 +792,7 @@ namespace OpenRA
var x = isX ? rand.Next(Bounds.Left, Bounds.Right) : (edge ? Bounds.Left : Bounds.Right);
var y = !isX ? rand.Next(Bounds.Top, Bounds.Bottom) : (edge ? Bounds.Top : Bounds.Bottom);
return MapToCell(TileShape, new CPos(x, y));
return new MPos(x, y).ToCPos(this);
}
public WRange DistanceToEdge(WPos pos, WVec dir)