// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE // ReSharper disable once CheckNamespace namespace WallstopStudios.UnityHelpers.Core.Extension { using System.Collections.Generic; using UnityEngine; using WallstopStudios.UnityHelpers.Core.DataStructure.Adapters; /// /// Grid traversal and BoundsInt utility helpers that operate on discretized space. /// public static partial class UnityExtensions { /// /// Creates a new BoundsInt with additional padding in the X and Y directions. /// /// The source bounds to add padding to. /// The padding to add to both left and right sides. /// The padding to add to both top and bottom sides. /// A new BoundsInt expanded by the specified padding amounts. /// /// Thread Safety: Thread-safe, no Unity API calls. /// Null Handling: Not applicable for value types. /// Performance: O(1) - Simple arithmetic. /// Allocations: None - returns value type. /// Unity Behavior: Z dimension remains unchanged. /// Edge Cases: Negative padding shrinks the bounds. Size increases by 2*padding in each direction. /// public static BoundsInt WithPadding(this BoundsInt bounds, int xPadding, int yPadding) { Vector3Int size = bounds.size; return new BoundsInt( bounds.xMin - xPadding, bounds.yMin - yPadding, bounds.zMin, size.x + 2 * xPadding, size.y + 2 * yPadding, size.z ); } /// /// Enumerates all FastVector3Int positions within the bounds. /// /// The bounds to enumerate positions within. /// An enumerable of all FastVector3Int positions within the bounds. /// /// Thread Safety: Thread-safe, no Unity API calls. /// Null Handling: Not applicable for value types. /// Performance: O(volume) where volume is the number of cells in the bounds. /// Allocations: Uses yield return, allocates enumerator. Each FastVector3Int is a value type. /// Unity Behavior: Uses half-open interval [min, max) consistent with BoundsInt. /// Edge Cases: Zero or negative size bounds yield no positions. /// Iteration order is X (innermost), then Y, then Z (outermost). /// public static IEnumerable AllFastPositionsWithin(this BoundsInt bounds) { Vector3Int min = bounds.min; Vector3Int max = bounds.max; for (int x = min.x; x < max.x; ++x) { for (int y = min.y; y < max.y; ++y) { for (int z = min.z; z < max.z; ++z) { yield return new FastVector3Int(x, y, z); } } } } /// /// Fills a list with all FastVector3Int positions within the bounds. /// /// The bounds to get positions from. /// The list to clear and fill with positions. /// The buffer list containing all positions. /// /// Thread Safety: Thread-safe if buffer is not accessed concurrently. /// Null Handling: Throws NullReferenceException if buffer is null. /// Performance: O(volume) where volume is the number of cells in the bounds. /// Allocations: May allocate if buffer capacity is insufficient. Clears buffer first. /// Unity Behavior: Uses half-open interval [min, max) consistent with BoundsInt. /// Edge Cases: Zero or negative size bounds result in an empty buffer. /// Iteration order is X (innermost), then Y, then Z (outermost). /// public static List AllFastPositionsWithin( this BoundsInt bounds, List buffer ) { buffer.Clear(); Vector3Int min = bounds.min; Vector3Int max = bounds.max; for (int x = min.x; x < max.x; ++x) { for (int y = min.y; y < max.y; ++y) { for (int z = min.z; z < max.z; ++z) { FastVector3Int position = new(x, y, z); buffer.Add(position); } } } return buffer; } /// /// Determines if a BoundsInt contains a FastVector3Int position. /// /// The bounds to test containment in. /// The position to test. /// True if the position is within the bounds; otherwise, false. /// /// Thread Safety: Thread-safe, no Unity API calls. /// Null Handling: Not applicable for value types. /// Performance: O(1) - Delegates to BoundsInt.Contains via implicit conversion. /// Allocations: None. /// Unity Behavior: Uses half-open interval [min, max) for containment test. /// Edge Cases: Points on the max boundary are NOT contained. /// public static bool Contains(this BoundsInt bounds, FastVector3Int position) { return bounds.Contains(position); } /// /// Determines if a FastVector3Int position is on the 2D edge of a BoundsInt (ignores Z axis). /// /// The position to test. /// The bounds to test against. /// True if the position is on the 2D boundary of the bounds; otherwise, false. /// /// Thread Safety: Thread-safe, no Unity API calls. /// Null Handling: Not applicable for value types. /// Performance: O(1) - Simple comparisons. /// Allocations: None. /// Unity Behavior: Tests if position is on the min or max-1 boundary in X or Y. /// Edge Cases: Position must be within bounds AND on an edge to return true. /// Uses max-1 because BoundsInt uses half-open intervals. Z axis is ignored. /// public static bool IsOnEdge2D(this FastVector3Int position, BoundsInt bounds) { if (bounds.xMin == position.x || bounds.xMax - 1 == position.x) { return bounds.yMin <= position.y && position.y < bounds.yMax; } if (bounds.yMin == position.y || bounds.yMax - 1 == position.y) { return bounds.xMin <= position.x && position.x < bounds.xMax; } return false; } } }