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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user