//$ Copyright 2015-22, Code Respawn Technologies Pvt Ltd - All Rights Reserved $// using System.Collections.Generic; using UnityEngine; namespace DungeonArchitect.Utils { /// /// Various math utility functions /// public class MathUtils { /// /// Copies the rectangle object /// /// The object to copy /// The copied object public static Rectangle Copy(Rectangle other) { return new Rectangle(other.X, other.Z, other.Width, other.Length); } /// /// Divides two vector3 objects /// /// /// /// The divided vector public static Vector3 Divide(Vector3 a, Vector3 b) { return new Vector3( a.x / b.x, a.y / b.y, a.z / b.z ); } /// /// Converts an IntVector to a Vector3 /// /// the input int vector /// public static Vector3 ToVector3(IntVector v) { return new Vector3(v.x, v.y, v.z); } public static Vector3 ToVector3(Vector3Int v) { return new Vector3(v.x, v.y, v.z); } public static Vector4 ToVector4(Vector3 v, float w) { return new Vector4(v.x, v.y, v.z, w); } /// /// Converts the world coordinates to grid coordinates /// /// The world cooridnate /// The grid cell size /// The resulting grid coordinate public static IntVector WorldToGrid(Vector3 WorldCoord, Vector3 GridCellSize) { return ToIntVector(Divide (WorldCoord, GridCellSize)); } /// /// Converts the grid coordinate to world coordinate /// /// The grid cell size /// The input grid coordinate /// The resulting world coordinate public static Vector3 GridToWorld(Vector3 GridCellSize, IntVector v) { return GridToWorld(GridCellSize, ToVector3(v)); } /// /// Converts the grid coordinate to world coordinate /// /// The grid cell size /// The input grid coordinate /// The resulting world coordinate public static Vector3 GridToWorld(Vector3 GridCellSize, Vector3 v) { return Vector3.Scale (GridCellSize, v); } /// /// Converts an IntVector to a Vector3, with the XYZ components floored /// /// The input Vector3 to convert /// The corresponding IntVector, floored in each component public static IntVector ToIntVector(Vector3 v) { return new IntVector( Mathf.FloorToInt(v.x), Mathf.FloorToInt(v.y), Mathf.FloorToInt(v.z) ); } public static Vector3Int FloorToVector3Int(Vector3 v) { return new Vector3Int( Mathf.FloorToInt(v.x), Mathf.FloorToInt(v.y), Mathf.FloorToInt(v.z) ); } public static Vector3Int RoundToVector3Int(Vector3 v) { return new Vector3Int( Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y), Mathf.RoundToInt(v.z) ); } public static Vector2Int RoundToVector2Int(Vector3 v) { return new Vector2Int( Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y) ); } public static Vector3 V3FloorToInt(Vector3 v) { return new Vector3( Mathf.FloorToInt(v.x), Mathf.FloorToInt(v.y), Mathf.FloorToInt(v.z)); } public static Vector3 V3RoundToInt(Vector3 v) { return new Vector3( Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y), Mathf.RoundToInt(v.z)); } public static Vector3 ComponentMin(Vector3 a, Vector3 b) { return new Vector3( Mathf.Min(a.x, b.x), Mathf.Min(a.y, b.y), Mathf.Min(a.z, b.z) ); } public static Vector3 ComponentMax(Vector3 a, Vector3 b) { return new Vector3( Mathf.Max(a.x, b.x), Mathf.Max(a.y, b.y), Mathf.Max(a.z, b.z) ); } /// /// Rounds to an IntVector, with the XYZ components rounded to the nearest int /// /// The input Vector3 to convert /// The rounded IntVector public static IntVector RoundToIntVector(Vector3 v) { return new IntVector( Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y), Mathf.RoundToInt(v.z) ); } /// /// Snaps the position to the nearest grid cell location /// /// The position to snap /// The size of the grid cell /// The snapped position public static Vector3 SnapToGrid(Vector3 position, Vector3 gridCellSize) { return SnapToGrid(position, gridCellSize, true); } /// /// Snaps the position to the nearest grid cell location /// /// The position to snap /// The size of the grid cell /// Flag to indicate if rounding is to be used. Uses floor if false /// The snapped position public static Vector3 SnapToGrid(Vector3 position, Vector3 gridCellSize, bool useRounding) { Vector3 gridPosition; if (useRounding) { gridPosition = new Vector3( Mathf.RoundToInt(position.x / gridCellSize.x), Mathf.RoundToInt(position.y / gridCellSize.y), Mathf.RoundToInt(position.z / gridCellSize.z)); } else { gridPosition = new Vector3( Mathf.FloorToInt(position.x / gridCellSize.x), Mathf.FloorToInt(position.y / gridCellSize.y), Mathf.FloorToInt(position.z / gridCellSize.z)); //gridPosition += Vector3.one; } return Vector3.Scale(gridPosition, gridCellSize); } /// /// Checks if the two rectangles intersect /// /// The outer rect /// The inner rect /// True if they intersect, false otherwise public static bool Intersects(Rect a, Rect b) { bool notIntersecting = (a.xMin > b.xMax || a.xMax < b.xMin || a.yMin > b.yMax || a.yMax < b.yMin); return !notIntersecting; } public static Vector2 ClosestPointOnRect(Rect rect, Vector2 p) { var result = new Vector2(); result.x = Mathf.Clamp(p.x, rect.xMin, rect.xMax); result.y = Mathf.Clamp(p.y, rect.yMin, rect.yMax); return result; } public static Rect ExpandRect(Rect bounds, float amount) { var rect = new Rect(bounds); rect.x -= amount; rect.y -= amount; rect.width += amount * 2; rect.height += amount * 2; return rect; } public static Vector2 ClampToRect(Vector2 position, Rect bounds) { var result = position; result.x = Mathf.Clamp(result.x, bounds.x, bounds.x + bounds.width); result.y = Mathf.Clamp(result.y, bounds.y, bounds.y + bounds.height); return result; } /// /// Flips the coordinates for 2D mode /// /// Bounds. public static void FlipYZ(ref Bounds bounds) { bounds.size = FlipYZ (bounds.size); var center = FlipYZ (bounds.center); center.y = 0; bounds.center = center; } /// /// Flips the coordinates for 2D mode /// /// The Y. /// Bounds. public static Vector3 FlipYZ(Vector3 bounds) { var z = bounds.z; bounds.z = bounds.y; bounds.y = z; return bounds; } /// /// Flips the coordinates for 2D mode /// /// The Y. /// Bounds. public static IntVector FlipYZ(IntVector bounds) { var z = bounds.z; bounds.z = bounds.y; bounds.y = z; return bounds; } public static void Abs(ref Vector3 v) { v.x = Mathf.Abs(v.x); v.y = Mathf.Abs(v.y); v.z = Mathf.Abs(v.z); } /// /// Flag to indicate an invalid location /// public static readonly int INVALID_LOCATION = -1000000; public static void Swap(ref T a, ref T b) { T t = a; a = b; b = t; } public static void Shuffle(List Array, System.Random Random) { int Count = Array.Count; for (int i = 0; i < Count; i++) { int j = Random.Range(0, Count - 1); T Temp = Array[i]; Array[i] = Array[j]; Array[j] = Temp; } } public static void Shuffle(T[] Array, System.Random Random) { int Count = Array.Length; for (int i = 0; i < Count; i++) { int j = Random.Range(0, Count - 1); T Temp = Array[i]; Array[i] = Array[j]; Array[j] = Temp; } } public static int[] GetShuffledIndices(int Count, System.Random Random) { var Indices = new List(); for (int i = 0; i < Count; i++) { Indices.Add(i); } Shuffle(Indices, Random); return Indices.ToArray(); } public static Bounds TransformBounds(Matrix4x4 transform, Bounds bounds) { var vertices = new Vector3[8]; var center = bounds.center; var extents = bounds.extents; vertices[0] = center + new Vector3(extents.x, extents.y, extents.z); vertices[1] = center + new Vector3(extents.x, extents.y, -extents.z); vertices[2] = center + new Vector3(extents.x, -extents.y, extents.z); vertices[3] = center + new Vector3(extents.x, -extents.y, -extents.z); vertices[4] = center + new Vector3(-extents.x, extents.y, extents.z); vertices[5] = center + new Vector3(-extents.x, extents.y, -extents.z); vertices[6] = center + new Vector3(-extents.x, -extents.y, extents.z); vertices[7] = center + new Vector3(-extents.x, -extents.y, -extents.z); for (int i = 0; i < 8; i++) { vertices[i] = transform.MultiplyPoint3x4(vertices[i]); } var newBounds = new Bounds(vertices[0], Vector3.zero); for (int i = 1; i < 8; i++) { newBounds.Encapsulate(vertices[i]); } return newBounds; } public static Bounds TransformBoundsX(Matrix4x4 transform, Bounds localBounds) { var center = transform * localBounds.center; // transform the local extents' axes var extents = localBounds.extents; var axisX = transform * new Vector3(extents.x, 0, 0); var axisY = transform * new Vector3(0, extents.y, 0); var axisZ = transform * new Vector3(0, 0, extents.z); // sum their absolute value to get the world extents extents.x = Mathf.Abs(axisX.x) + Mathf.Abs(axisY.x) + Mathf.Abs(axisZ.x); extents.y = Mathf.Abs(axisX.y) + Mathf.Abs(axisY.y) + Mathf.Abs(axisZ.y); extents.z = Mathf.Abs(axisX.z) + Mathf.Abs(axisY.z) + Mathf.Abs(axisZ.z); return new Bounds { center = center, extents = extents }; } public static bool V3Equals(Vector3 a, Vector3 b) { return V3Equals(a, b, 1e-6f); } public static bool V3Equals(Vector3 a, Vector3 b, float threshold) { return Vector3.Magnitude(a - b) < threshold; } public static byte ToByte(float value01) { return (byte)Mathf.RoundToInt(Mathf.Clamp01(value01) * 255); } public static Vector3 ReflectVector(Vector3 direction, Vector3 normal) { return direction - 2 * Vector3.Dot(direction, normal) * normal; } } }