/// <summary> /// Calculates the location in grid (Column/Row) of the vector position (X/Z). /// </summary> /// <param name="vector"> /// The reference vector that is to be converted into grid location. /// </param> /// <returns> /// Returns a <see cref="Vector2"/> type representing the Column and Row where the mouse of positioned over. /// </returns> public Point GetGridPosition(Vector3 vector) { #if PERFORMANCE var performance = PerformanceTesting<PerformanceID>.Instance; performance.Start(PerformanceID.GetGridPosition); #endif // get reference to the grid map component var map = (GridMap)this.target; // calculate column and row location from mouse hit location var position = new Vector3(vector.X / map.CellWidth, map.transform.position.y, vector.Z / map.CellHeight); // round the numbers to the nearest whole number using 5 decimal place precision position = new Vector3((int)Math.Round(position.X, 5, MidpointRounding.ToEven), 0, (int)Math.Round(position.Z, 5, MidpointRounding.ToEven)); // do a check to ensure that the row and column are with the bounds of the grid map var col = (int)position.X; var row = (int)position.Z; row = row < 0 ? 0 : row; row = row > map.Rows - 1 ? map.Rows - 1 : row; col = col < 0 ? 0 : col; col = col > map.Columns - 1 ? map.Columns - 1 : col; #if PERFORMANCE performance.Stop(PerformanceID.GetGridPosition); #endif // return the column and row values return new Point(col, row); }
/// <summary> /// Calculates the position of the mouse over the grid map in local space coordinates. /// </summary> /// <returns>Returns true if the mouse is over the grid map.</returns> private bool UpdateHitPosition() { // get reference to the grid map component var map = (GridMap)this.target; // build a plane object that // rotate up the same as map rotation var directionVector = Vector3.MoveTowards(Vector3.Up, map.transform.up, 1); directionVector.Normalize(); directionVector *= this.ActiveLayer * map.Depth; var p = new Plane(map.transform.up, map.transform.position + directionVector); // build a ray type from the current mouse position var ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); // stores the hit location var hit = new Vector3(); // stores the distance to the hit location float dist; // cast a ray to determine what location it intersects with the plane if (p.Raycast(ray, out dist)) { // the ray hits the plane so we calculate the hit location in world space hit = ray.origin + (ray.direction.normalized * dist); } // convert the hit location from world space to local space var value = map.transform.InverseTransformPoint(hit); var changed = value != this.mouseHitPosition; this.mouseHitPosition = value; // return true indicating a successful hit test return changed; }
/// <summary> /// positions a prefab on the map. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="row">The row where the prefab will be placed.</param> /// <param name="prefab">The prefab to be placed. </param> /// <param name="layer">The layer where placement will occur.</param> /// <param name="column">The column where the prefab will be placed.</param> /// <param name="autoCenterPrefab">Determines whether or not to automatically center the prefab within the grid cell.</param> /// <param name="autoScalePrefab">If true the prefab will be automatically scaled to fit within the confines of the maps cell size.</param> public static void PositionPrefabOnMap(this GridMap map, int layer, int column, int row, GameObject prefab, bool autoCenterPrefab, bool autoScalePrefab) { if (prefab == null) { throw new ArgumentNullException("prefab"); } #if PERFORMANCE var perf = PerformanceTesting<PerformanceID>.Instance; perf.Start(PerformanceID.PositionPrefabOnMapExtensionMethod); #endif var transform = prefab.transform; var bounds = new Bounds(); if (autoScalePrefab) { // map.ScalePrefab(prefab); #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_ScalePrefab); #endif // get bounds of the prefab var encapsulate = false; if (Utilities.Helpers.GetBoundWithChildren(transform, ref bounds, ref encapsulate)) { // apply scaling to the prefab var scale = transform.localScale; // set x/z scale scale.x *= map.CellWidth / bounds.size.x; scale.z *= map.CellHeight / bounds.size.z; // scale.y *= (map.Depth / bounds.size.y) * (scale.x / scale.z); // check for infinity values and if found set to 0 scale.x = float.IsInfinity(scale.x) ? 0 : scale.x; scale.y = float.IsInfinity(scale.y) ? 0 : scale.y; scale.z = float.IsInfinity(scale.z) ? 0 : scale.z; scale.x = float.IsNaN(scale.x) ? 1 : scale.x; scale.y = float.IsNaN(scale.y) ? 1 : scale.y; scale.z = float.IsNaN(scale.z) ? 1 : scale.z; // set scale transform.localScale = scale; #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_ScalePrefab); #endif } } #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_SetParent); #endif transform.parent = map.transform; #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_SetParent); #endif #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_Rotate); #endif // get maps rotation UnityEngine.Vector3 axis; float angle; map.transform.rotation.ToAngleAxis(out angle, out axis); // apply maps rotation to the prefab so the prefab is rotated along with the map transform.Rotate(axis, angle, Space.World); #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_Rotate); #endif var gridPositionInLocalSpace = Vector3.Zero; if (autoCenterPrefab) { #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_AutoCenter); #endif // ensure prefab is perfectly centered in the middle of the grid cell based on it's render bounds var encapsulate = false; // zero out the prefab's position transform.position = Vector3.Zero; // get rendering bounds for the prefab if not already done so Utilities.Helpers.GetBoundWithChildren(transform, ref bounds, ref encapsulate); gridPositionInLocalSpace = new Vector3( (column * map.CellWidth) + (map.CellWidth / 2) - bounds.center.x, (layer * map.Depth) - bounds.center.y, (row * map.CellHeight) + (map.CellHeight / 2) - bounds.center.z); #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_AutoCenter); #endif } else { // set the prefabs position in the center of the grid cell not taking into account it's render bounds gridPositionInLocalSpace = new Vector3( (column * map.CellWidth) + (map.CellWidth / 2), layer * map.Depth, (row * map.CellHeight) + (map.CellHeight / 2)); } // set the prefabs transform position #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_SetPosition); #endif transform.localPosition = gridPositionInLocalSpace; #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_SetPosition); #endif #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMapExtensionMethod); #endif }
/// <summary> /// Recalculates the position of the marker based on the location of the mouse pointer. /// </summary> private void RecalculateHighlightPosition() { #if PERFORMANCE var performance = PerformanceTesting<PerformanceID>.Instance; performance.Start(PerformanceID.RecalculateHighlightPosition); #endif // get reference to the grid map component var map = (GridMap)this.target; // store the grid location (Column/Row) based on the current location of the mouse pointer var gridPosition = this.GetGridPosition(this.mouseHitPosition); // store the grid position in local space var position = new Vector3(gridPosition.X * map.CellWidth, 0, gridPosition.Y * map.CellHeight); // set the highlightPosition value this.highlightPosition = new Vector3( position.X + (map.CellWidth / 2), this.ActiveLayer * map.Depth, position.Z + (map.CellHeight / 2)); #if PERFORMANCE performance.Stop(PerformanceID.RecalculateHighlightPosition); #endif }
/// <summary> /// positions a prefab on the map. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="row">The row where the prefab will be placed.</param> /// <param name="prefab">The prefab to be placed. </param> /// <param name="layer">The layer where placement will occur.</param> /// <param name="column">The column where the prefab will be placed.</param> /// <param name="autoCenterPrefab">Determines whether or not to automatically center the prefab within the grid cell.</param> /// <param name="autoScalePrefab">If true the prefab will be automatically scaled to fit within the confines of the maps cell size.</param> public static void PositionPrefabOnMap(this GridMap map, int layer, int column, int row, GameObject prefab, bool autoCenterPrefab, bool autoScalePrefab) { if (prefab == null) { throw new ArgumentNullException("prefab"); } #if PERFORMANCE var perf = PerformanceTesting <PerformanceID> .Instance; perf.Start(PerformanceID.PositionPrefabOnMapExtensionMethod); #endif var transform = prefab.transform; var bounds = new Bounds(); if (autoScalePrefab) { // map.ScalePrefab(prefab); #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_ScalePrefab); #endif // get bounds of the prefab var encapsulate = false; if (Utilities.Helpers.GetBoundWithChildren(transform, ref bounds, ref encapsulate)) { // apply scaling to the prefab var scale = transform.localScale; // set x/z scale scale.x *= map.CellWidth / bounds.size.x; scale.z *= map.CellHeight / bounds.size.z; // scale.y *= (map.Depth / bounds.size.y) * (scale.x / scale.z); // check for infinity values and if found set to 0 scale.x = float.IsInfinity(scale.x) ? 0 : scale.x; scale.y = float.IsInfinity(scale.y) ? 0 : scale.y; scale.z = float.IsInfinity(scale.z) ? 0 : scale.z; scale.x = float.IsNaN(scale.x) ? 1 : scale.x; scale.y = float.IsNaN(scale.y) ? 1 : scale.y; scale.z = float.IsNaN(scale.z) ? 1 : scale.z; // set scale transform.localScale = scale; #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_ScalePrefab); #endif } } #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_SetParent); #endif transform.parent = map.transform; #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_SetParent); #endif #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_Rotate); #endif // get maps rotation UnityEngine.Vector3 axis; float angle; map.transform.rotation.ToAngleAxis(out angle, out axis); // apply maps rotation to the prefab so the prefab is rotated along with the map transform.Rotate(axis, angle, Space.World); #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_Rotate); #endif var gridPositionInLocalSpace = Vector3.Zero; if (autoCenterPrefab) { #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_AutoCenter); #endif // ensure prefab is perfectly centered in the middle of the grid cell based on it's render bounds var encapsulate = false; // zero out the prefab's position transform.position = Vector3.Zero; // get rendering bounds for the prefab if not already done so Utilities.Helpers.GetBoundWithChildren(transform, ref bounds, ref encapsulate); gridPositionInLocalSpace = new Vector3( (column * map.CellWidth) + (map.CellWidth / 2) - bounds.center.x, (layer * map.Depth) - bounds.center.y, (row * map.CellHeight) + (map.CellHeight / 2) - bounds.center.z); #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_AutoCenter); #endif } else { // set the prefabs position in the center of the grid cell not taking into account it's render bounds gridPositionInLocalSpace = new Vector3( (column * map.CellWidth) + (map.CellWidth / 2), layer * map.Depth, (row * map.CellHeight) + (map.CellHeight / 2)); } // set the prefabs transform position #if PERFORMANCE perf.Start(PerformanceID.PositionPrefabOnMap_SetPosition); #endif transform.localPosition = gridPositionInLocalSpace; #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMap_SetPosition); #endif #if PERFORMANCE perf.Stop(PerformanceID.PositionPrefabOnMapExtensionMethod); #endif }