/// <summary> /// Sets connection data to a span contained in a neighboring cell. /// </summary> /// <param name="dir">The direction of the cell.</param> /// <param name="i">The index of the span in the neighboring cell.</param> /// <param name="s">The <see cref="CompactSpan"/> to set the data for.</param> public static void SetConnection(Direction dir, int i, ref CompactSpan s) { if (i >= NotConnected) { throw new ArgumentOutOfRangeException("Index of connecting span is too high to be stored. Try increasing cell height.", "i"); } switch (dir) { case Direction.West: s.ConnectionWest = (byte)i; break; case Direction.North: s.ConnectionNorth = (byte)i; break; case Direction.East: s.ConnectionEast = (byte)i; break; case Direction.South: s.ConnectionSouth = (byte)i; break; default: throw new ArgumentException("dir isn't a valid Direction."); } }
public void AddCompactSpan_NoUpperLimit_Success() { CompactSpan cs = new CompactSpan(10, int.MaxValue); Assert.IsFalse(cs.HasUpperBound); Assert.AreEqual(cs.ConnectionCount, 0); }
public void AddCompactSpan_SetConnection_Success() { CompactSpan cs = new CompactSpan(10, int.MaxValue); CompactSpan.SetConnection((Direction)1, 1, ref cs); Assert.AreEqual(cs.ConnectionCount, 1); }
public void AddCompactSpan_GetConnection_Success() { CompactSpan cs = new CompactSpan(10, int.MaxValue); CompactSpan.SetConnection((Direction)1, 50, ref cs); Assert.AreEqual(CompactSpan.GetConnection(ref cs, (Direction)1), 50); Assert.AreEqual(cs.GetConnection((Direction)1), 50); }
public void AddCompactSpan_IsConnected_Success() { CompactSpan cs = new CompactSpan(10, int.MaxValue); CompactSpan.SetConnection(Direction.East, 1, ref cs); Assert.IsTrue(cs.IsConnected(Direction.East)); Assert.IsFalse(cs.IsConnected(Direction.West)); }
/// <summary> /// Creates a <see cref="CompactSpan"/> from a minimum boundary and a maximum boundary. /// </summary> /// <param name="min">The minimum.</param> /// <param name="max">The maximum.</param> /// <param name="span">A <see cref="CompactSpan"/>.</param> public static void FromMinMax(int min, int max, out CompactSpan span) { span.Minimum = min; span.Height = max - min; span.ConnectionWest = NotConnected; span.ConnectionNorth = NotConnected; span.ConnectionEast = NotConnected; span.ConnectionSouth = NotConnected; span.Region = RegionId.Null; }
/// <summary> /// Gets the connection data for a neighboring cell in a specified direction. /// </summary> /// <param name="s">The <see cref="CompactSpan"/> to get the connection data from.</param> /// <param name="dir">The direction.</param> /// <returns>The index of the span in the neighboring cell.</returns> public static int GetConnection(ref CompactSpan s, Direction dir) { switch (dir) { case Direction.West: return(s.ConnectionWest); case Direction.North: return(s.ConnectionNorth); case Direction.East: return(s.ConnectionEast); case Direction.South: return(s.ConnectionSouth); default: throw new ArgumentException("dir isn't a valid Direction."); } }
/// <summary> /// If two CompactSpans overlap, find the maximum of the new overlapping CompactSpans. /// </summary> /// <param name="left">The first CompactSpan</param> /// <param name="right">The second CompactSpan</param> /// <param name="max">The maximum of the overlapping CompactSpans</param> public static void OverlapMax(ref CompactSpan left, ref CompactSpan right, out int max) { if (left.Height == int.MaxValue) { if (right.Height == int.MaxValue) { max = int.MaxValue; } else { max = right.Minimum + right.Height; } } else if (right.Height == int.MaxValue) { max = left.Minimum + left.Height; } else { max = Math.Min(left.Minimum + left.Height, right.Minimum + right.Height); } }
/// <summary> /// Un-sets connection data from a neighboring cell. /// </summary> /// <param name="dir">The direction of the cell.</param> /// <param name="s">The <see cref="CompactSpan"/> to set the data for.</param> public static void UnsetConnection(Direction dir, ref CompactSpan s) { switch (dir) { case Direction.West: s.ConnectionWest = NotConnected; break; case Direction.North: s.ConnectionNorth = NotConnected; break; case Direction.East: s.ConnectionEast = NotConnected; break; case Direction.South: s.ConnectionSouth = NotConnected; break; default: throw new ArgumentException("dir isn't a valid Direction."); } }
/// <summary> /// Sets connection data to a span contained in a neighboring cell. /// </summary> /// <param name="dir">The direction of the cell.</param> /// <param name="i">The index of the span in the neighboring cell.</param> /// <param name="s">The <see cref="CompactSpan"/> to set the data for.</param> public static void SetConnection(Direction dir, int i, ref CompactSpan s) { if (i >= NotConnected) throw new ArgumentOutOfRangeException("Index of connecting span is too high to be stored. Try increasing cell height.", "i"); switch (dir) { case Direction.West: s.ConnectionWest = (byte)i; break; case Direction.North: s.ConnectionNorth = (byte)i; break; case Direction.East: s.ConnectionEast = (byte)i; break; case Direction.South: s.ConnectionSouth = (byte)i; break; default: throw new ArgumentException("dir isn't a valid Direction."); } }
/// <summary> /// If two CompactSpans overlap, find the maximum of the new overlapping CompactSpans. /// </summary> /// <param name="left">The first CompactSpan</param> /// <param name="right">The second CompactSpan</param> /// <param name="max">The maximum of the overlapping CompactSpans</param> public static void OverlapMax(ref CompactSpan left, ref CompactSpan right, out int max) { if (left.Height == int.MaxValue) { if (right.Height == int.MaxValue) max = int.MaxValue; else max = right.Minimum + right.Height; } else if (right.Height == int.MaxValue) max = left.Minimum + left.Height; else max = Math.Min(left.Minimum + left.Height, right.Minimum + right.Height); }
/// <summary> /// If two CompactSpans overlap, find the minimum of the new overlapping CompactSpans. /// </summary> /// <param name="left">The first CompactSpan</param> /// <param name="right">The second CompactSpan</param> /// <param name="min">The minimum of the overlapping ComapctSpans</param> public static void OverlapMin(ref CompactSpan left, ref CompactSpan right, out int min) { min = Math.Max(left.Minimum, right.Minimum); }
public void SetConnection_InvalidDirection_Success() { CompactSpan cs = new CompactSpan(10, int.MaxValue); Assert.Throws<ArgumentException>(() => CompactSpan.SetConnection((Direction)(-1), 1, ref cs)); }
public void SetConnection_TooHigh_Success() { CompactSpan cs = new CompactSpan(10, int.MaxValue); Assert.Throws<ArgumentOutOfRangeException>(() => CompactSpan.SetConnection((Direction)2, 300, ref cs)); }
/// <summary> /// Gets the connection data for a neighboring cell in a specified direction. /// </summary> /// <param name="s">The <see cref="CompactSpan"/> to get the connection data from.</param> /// <param name="dir">The direction.</param> /// <returns>The index of the span in the neighboring cell.</returns> public static int GetConnection(ref CompactSpan s, Direction dir) { switch (dir) { case Direction.West: return s.ConnectionWest; case Direction.North: return s.ConnectionNorth; case Direction.East: return s.ConnectionEast; case Direction.South: return s.ConnectionSouth; default: throw new ArgumentException("dir isn't a valid Direction."); } }
/// <summary> /// Initializes a new instance of the <see cref="CompactHeightfield"/> class. /// </summary> /// <param name="field">A <see cref="Heightfield"/> to build from.</param> /// <param name="walkableHeight">The maximum difference in height to filter.</param> /// <param name="walkableClimb">The maximum difference in slope to filter.</param> public CompactHeightfield(Heightfield field, int walkableHeight, int walkableClimb) { this.bounds = field.Bounds; this.width = field.Width; this.height = field.Height; this.length = field.Length; this.cellSize = field.CellSizeXZ; this.cellHeight = field.CellHeight; int spanCount = field.SpanCount; cells = new CompactCell[width * length]; spans = new CompactSpan[spanCount]; areas = new Area[spanCount]; //iterate over the Heightfield's cells int spanIndex = 0; for (int i = 0; i < cells.Length; i++) { //get the heightfield span list, skip if empty var fs = field[i].Spans; if (fs.Count == 0) continue; CompactCell c = new CompactCell(spanIndex, 0); //convert the closed spans to open spans int lastInd = fs.Count - 1; for (int j = 0; j < lastInd; j++) { var s = fs[j]; if (s.Area.IsWalkable) { CompactSpan.FromMinMax(s.Maximum, fs[j + 1].Minimum, out spans[spanIndex]); areas[spanIndex] = s.Area; spanIndex++; c.Count++; } } //the last closed span that has an "infinite" height var lastS = fs[lastInd]; if (lastS.Area.IsWalkable) { spans[spanIndex] = new CompactSpan(fs[lastInd].Maximum, int.MaxValue); areas[spanIndex] = lastS.Area; spanIndex++; c.Count++; } cells[i] = c; } //set neighbor connections for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++) { CompactCell c = cells[z * width + x]; for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++) { CompactSpan s = spans[i]; for (var dir = Direction.West; dir <= Direction.South; dir++) { int dx = x + dir.GetHorizontalOffset(); int dz = z + dir.GetVerticalOffset(); if (dx < 0 || dz < 0 || dx >= width || dz >= length) continue; CompactCell dc = cells[dz * width + dx]; for (int j = dc.StartIndex, cellEnd = dc.StartIndex + dc.Count; j < cellEnd; j++) { CompactSpan ds = spans[j]; int overlapBottom, overlapTop; CompactSpan.OverlapMin(ref s, ref ds, out overlapBottom); CompactSpan.OverlapMax(ref s, ref ds, out overlapTop); //Make sure that the agent can walk to the next span and that the span isn't a huge drop or climb if ((overlapTop - overlapBottom) >= walkableHeight && Math.Abs(ds.Minimum - s.Minimum) <= walkableClimb) { int con = j - dc.StartIndex; CompactSpan.SetConnection(dir, con, ref spans[i]); break; } } } } } } }