public GridMapGameObjectTracker(GridMap map, bool scan, bool background) { if (map == null) { throw new ArgumentNullException("map"); } this.map = map; if (scan) { this.Scan(background); } }
/// <summary> /// Draws a rectangular area of the map with a specified prefab. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="width">The width of the rectangle.</param> /// <param name="height">The height of the rectangle.</param> /// <param name="prefab">The prefab to be drawn. Specify null to erase.</param> /// <param name="layer">The layer where drawing will occur.</param> /// <param name="left">The left position of the rectangle in grid co-ordinates.</param> /// <param name="top">The top position of the rectangle in grid co-ordinates.</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> /// <param name="callback">Provides a draw callback function that if returns true will allow the prefab to be drawn. </param> /// <remarks>If <see cref="callback"/> is null the check is ignored and drawing is allowed.</remarks> public static void DrawRectangle(this GridMap map, int layer, int left, int top, int width, int height, GameObject prefab, bool autoCenterPrefab, bool autoScalePrefab, Func <int, int, int, GameObject, bool> callback) { if (prefab == null) { throw new ArgumentNullException("prefab"); } var dimensions = new Rect(0, 0, map.Columns, map.Rows); var firstRun = true; if (!dimensions.Intersects(new Rect(left, top, width, height))) { return; } var material = prefab.renderer.sharedMaterial; var getClone = new Func <GameObject>(() => { var value = firstRun ? prefab : Helpers.PerformInstantiation(prefab); // clear material references before assigning new material value.renderer.material = null; value.renderer.sharedMaterial = material; return(value); }); for (var rowIndex = 0; rowIndex < height; rowIndex++) { if (rowIndex + top < 0 || rowIndex + top > map.Rows - 1) { continue; } if (left < 0 || left > map.Columns - 1 && left + width - 1 < 0 || left + width - 1 > map.Columns - 1) { continue; } // left side var clonedObject = getClone(); firstRun = false; if (callback != null && !callback(left, rowIndex + top, layer, clonedObject)) { continue; } map.PositionPrefabOnMap(layer, left, rowIndex + top, clonedObject, autoCenterPrefab, autoScalePrefab); if (left != left + width - 1) { // right side clonedObject = getClone(); // clonedObject = firstRun ? prefab : Helpers.PerformInstantiation(prefab); if (callback != null && !callback(left + width - 1, rowIndex + top, layer, clonedObject)) { continue; } map.PositionPrefabOnMap(layer, left + width - 1, rowIndex + top, clonedObject, autoCenterPrefab, autoScalePrefab); } } if (left == left + width - 1) { return; } for (var columnIndex = 1; columnIndex < width - 1; columnIndex++) { if (columnIndex + left < 0 || columnIndex + left > map.Columns - 1) { continue; } if (top < 0 || top > map.Rows - 1 && top + height - 1 < 0 || top + height - 1 > map.Rows - 1) { continue; } // top side var clonedObject = getClone(); // var clonedObject = firstRun ? prefab : Helpers.PerformInstantiation(prefab); if (callback != null && !callback(columnIndex + left, top, layer, clonedObject)) { continue; } map.PositionPrefabOnMap(layer, columnIndex + left, top, clonedObject, autoCenterPrefab, autoScalePrefab); if (top != top + height - 1) { // bottom side clonedObject = getClone(); // clonedObject = firstRun ? prefab : Helpers.PerformInstantiation(prefab); if (callback != null && !callback(columnIndex + left, top + height - 1, layer, clonedObject)) { continue; } map.PositionPrefabOnMap(layer, columnIndex + left, top + height - 1, clonedObject, autoCenterPrefab, autoScalePrefab); } } }
/// <summary> /// Fills a rectangular area of the map with a specified prefab. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="width">The width of the rectangle.</param> /// <param name="height">The height of the rectangle.</param> /// <param name="prefab">The prefab to be drawn. Specify null to erase.</param> /// <param name="layer">The layer where drawing will occur.</param> /// <param name="left">The left position of the rectangle in grid co-ordinates.</param> /// <param name="top">The top position of the rectangle in grid co-ordinates.</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> /// <param name="callback">Provides a draw callback function that if returns true will allow the prefab to be drawn. </param> /// <remarks>If <see cref="callback"/> is null the check is ignored and drawing is allowed.</remarks> public static void FillRectangle(this GridMap map, int layer, int left, int top, int width, int height, GameObject prefab, bool autoCenterPrefab, bool autoScalePrefab, Func <int, int, int, GameObject, bool> callback) { if (prefab == null) { throw new ArgumentNullException("prefab"); } var dimensions = new Rect(0, 0, map.Columns, map.Rows); var firstRun = true; if (!dimensions.Intersects(new Rect(left, top, width, height))) { return; } var material = prefab.renderer.sharedMaterial; var getClone = new Func <GameObject>(() => { var value = firstRun ? prefab : Helpers.PerformInstantiation(prefab); // clear material references before assigning new material value.renderer.material = null; value.renderer.sharedMaterial = material; return(value); }); #if PERFORMANCE var perf = PerformanceTesting <PerformanceID> .Instance; perf.Start(PerformanceID.FillRectangleExtensionMethod); #endif for (var rowIndex = 0; rowIndex < height; rowIndex++) { if (rowIndex + top < 0 || rowIndex + top > map.Rows - 1) { continue; } for (var columnIndex = 0; columnIndex < width; columnIndex++) { if (columnIndex + left < 0 || columnIndex + left > map.Columns - 1) { continue; } #if PERFORMANCE perf.Start(PerformanceID.FillRectangleExtensionMethod_Instantiation); #endif var clonedObject = getClone(); #if PERFORMANCE perf.Stop(PerformanceID.FillRectangleExtensionMethod_Instantiation); #endif firstRun = false; #if PERFORMANCE perf.Start(PerformanceID.FillRectangleExtensionMethod_Callback); #endif if (callback != null && !callback(columnIndex + left, rowIndex + top, layer, clonedObject)) { #if PERFORMANCE perf.Stop(PerformanceID.FillRectangleExtensionMethod_Callback); #endif continue; } #if PERFORMANCE perf.Stop(PerformanceID.FillRectangleExtensionMethod_Callback); #endif map.PositionPrefabOnMap(layer, columnIndex + left, rowIndex + top, clonedObject, autoCenterPrefab, autoScalePrefab); } } #if PERFORMANCE perf.Stop(PerformanceID.FillRectangleExtensionMethod); #endif }
/// <summary> /// Finds and renames prefabs so that they are on different layers /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="index">The index of the layer.</param> /// <param name="newIndex">The index of the other layer.</param> /// <param name="callback">A callback that will be called with the map, and game objects that will be affected by the swap.</param> /// <param name="completedCallback">A callback that will be called with the map, and game objects that were affected by the swap.</param> /// <remarks>The <see cref="callback"/> and <see cref="completedCallback"/> parameters will be called with the fallowing arguments (Map, LayerIndex, NewLayerIndex, LayerA, LayerB).</remarks> public static void SwapLayers(this GridMap map, int index, int newIndex, Action <SwapModel> callback, Action <SwapModel> completedCallback) { // find list of objects to delete var layerA = new List <GameObject>(); var layerB = new List <GameObject>(); for (var col = 0; col < map.Columns; col++) { for (var row = 0; row < map.Rows; row++) { var obj = map.SearchForExistingPrefab(index, col, row); if (obj != null) { layerA.Add(obj); } obj = map.SearchForExistingPrefab(newIndex, col, row); if (obj != null) { layerB.Add(obj); } } } var layerAObjects = layerA.ToArray(); var layerBObjects = layerB.ToArray(); var swapModel = new SwapModel() { Map = map, LayerIndex = index, NewLayerIndex = newIndex, LayerAObjects = layerAObjects, LayerBObjects = layerBObjects }; if (callback != null) { callback(swapModel); } // setup variables const string NameFormat = "{0}_l{1}_c{2}_r{3}"; // setup processor callback var changeNames = new Action <List <GameObject>, int>( (stack, layerIndex) => { foreach (var item in stack) { string name; int layer; int column; int row; if (!item.name.TryParsePrefabName(out name, out layer, out column, out row)) { continue; } // give the prefab a name that represents it's location within the grid map item.name = string.Format(NameFormat, name, layerIndex, column, row); // move prefab into proper layer position var transform = item.transform; var position = transform.localPosition; position.y = layerIndex * map.Depth; transform.position = position; } }); // change names changeNames(layerA, newIndex); changeNames(layerB, index); // change model indexes var model = map.Layers[index]; map.Layers[index] = map.Layers[newIndex]; map.Layers[newIndex] = model; if (completedCallback != null) { completedCallback(swapModel); } }
/// <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> /// Finds and renames prefabs so that they are on different layers /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="index">The index of the layer.</param> /// <param name="newIndex">The index of the other layer.</param> public static void SwapLayers(this GridMap map, int index, int newIndex) { SwapLayers(map, index, newIndex, null, null); }
/// <summary> /// Moves the the specified layer down the layer hierarchy. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="index"> /// The index of the layer that will be deleted. /// </param> /// <param name="visible">The prefabs for the layer will have there active states set.</param> public static void SetLayerVisibility(this GridMap map, int index, bool visible) { SetLayerVisibility(map, index, visible, null); }
/// <summary> /// Moves the the specified layer down the layer hierarchy. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="index"> /// The index of the layer that will be deleted. /// </param> /// <param name="count">The number of positions to move the layer.</param> public static void MoveLayerDown(this GridMap map, int index, int count) { MoveLayerDown(map, index, count, null, null); }
/// <summary> /// Gets the name of the specified layer. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="index"> /// The index of the layer. /// </param> /// <param name="value"> /// The new name for the layer. /// </param> public static void SetLayerName(this GridMap map, int index, string value) { map.Layers[index].Name = value; }
/// <summary> /// Gets the name of the specified layer. /// </summary> /// <param name="map">The reference to a <see cref="GridMap"/> type.</param> /// <param name="index">The index of the layer.</param> /// <returns>Returns the name of the layer.</returns> public static string GetLayerName(this GridMap map, int index) { return(map.Layers[index].Name); }