SamsonGame/Assets/Sources/Feel/MMTools/Tools/MMTilemaps/MMTilemapGridRenderer.cs

190 lines
7.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
namespace MoreMountains.Tools
{
public class MMTilemapGridRenderer
{
/// <summary>
/// Renders the specified grid on the specified tilemap, with optional slow mode (only works at runtime)
/// </summary>
/// <param name="grid"></param>
/// <param name="tilemap"></param>
/// <param name="tile"></param>
/// <param name="slowRender"></param>
/// <param name="slowRenderDuration"></param>
/// <param name="slowRenderTweenType"></param>
/// <param name="slowRenderSupport"></param>
public static void RenderGrid(int[,] grid, MMTilemapGeneratorLayer layer, bool slowRender = false, float slowRenderDuration = 1f,
MMTweenType slowRenderTweenType = null, MonoBehaviour slowRenderSupport = null)
{
if (layer.FusionMode == MMTilemapGeneratorLayer.FusionModes.Normal)
{
ClearTilemap(layer.TargetTilemap);
}
TileBase tile = layer.Tile;
if (layer.FusionMode == MMTilemapGeneratorLayer.FusionModes.Combine)
{
grid = MMGridGenerator.InvertGrid(grid);
tile = null;
}
if (layer.FusionMode == MMTilemapGeneratorLayer.FusionModes.Subtract)
{
grid = MMGridGenerator.InvertGrid(grid);
}
if (!slowRender || !Application.isPlaying)
{
DrawGrid(grid, layer.TargetTilemap, tile, 0, TotalFilledBlocks(grid));
}
else
{
slowRenderSupport.StartCoroutine(SlowRenderGrid(grid, layer.TargetTilemap, tile, slowRenderDuration, slowRenderTweenType, 60));
}
if (!Application.isPlaying && slowRender)
{
Debug.LogWarning("Rendering maps in SlowRender mode is only supported at runtime.");
}
}
/// <summary>
/// Renders a grid chunk by chunk - runtime only
/// </summary>
/// <param name="grid"></param>
/// <param name="tilemap"></param>
/// <param name="tile"></param>
/// <param name="slowRenderDuration"></param>
/// <param name="slowRenderTweenType"></param>
/// <param name="frameRate"></param>
/// <returns></returns>
public static IEnumerator SlowRenderGrid(int[,] grid, Tilemap tilemap, TileBase tile, float slowRenderDuration, MMTweenType slowRenderTweenType, int frameRate)
{
int totalBlocks = TotalFilledBlocks(grid);
totalBlocks = (totalBlocks == 0) ? 1 : totalBlocks;
frameRate = (frameRate == 0) ? 1 : frameRate;
float refreshFrequency = 1f / frameRate;
float startedAt = Time.unscaledTime;
float lastWaitAt = startedAt;
int drawnBlocks = 0;
int lastIndex = 0;
while (Time.unscaledTime - startedAt < slowRenderDuration)
{
while (Time.unscaledTime - lastWaitAt < refreshFrequency)
{
yield return null;
}
int remainingBlocks = totalBlocks - drawnBlocks;
float elapsedTime = Time.unscaledTime - startedAt;
float remainingTime = slowRenderDuration - elapsedTime;
float normalizedProgress = MMMaths.Remap(elapsedTime, 0f, slowRenderDuration, 0f, 1f);
float curveProgress = MMTween.Tween(normalizedProgress, 0f, 1f, 0f, 1f, slowRenderTweenType);
float ratio = 1 - (normalizedProgress - curveProgress);
int blocksToDraw = Mathf.RoundToInt((remainingBlocks / remainingTime) * refreshFrequency * ratio);
lastIndex = DrawGrid(grid, tilemap, tile, lastIndex, blocksToDraw);
drawnBlocks += blocksToDraw;
lastWaitAt = Time.unscaledTime;
}
DrawGrid(grid, tilemap, tile, lastIndex, totalBlocks - lastIndex);
}
/// <summary>
/// Returns the total amount of filled blocks in a grid
/// </summary>
/// <param name="grid"></param>
/// <returns></returns>
public static int TotalFilledBlocks(int[,] grid)
{
int width = grid.GetUpperBound(0);
int height = grid.GetUpperBound(1);
int totalBlocks = 0;
for (int i = 0; i <= width ; i++)
{
for (int j = 0; j <= height; j++)
{
if (grid[i, j] == 1)
{
totalBlocks++;
}
}
}
return totalBlocks;
}
/// <summary>
/// Draws the specified section of a grid on a target tilemap
/// </summary>
/// <param name="grid"></param>
/// <param name="tilemap"></param>
/// <param name="tile"></param>
/// <param name="startIndex"></param>
/// <param name="numberOfTilesToDraw"></param>
/// <returns></returns>
private static int DrawGrid(int[,] grid, Tilemap tilemap, TileBase tile, int startIndex, int numberOfTilesToDraw)
{
int width = grid.GetUpperBound(0);
int height = grid.GetUpperBound(1);
tilemap.RefreshAllTiles();
int counter = 0;
int drawCount = 0;
for (int i = 0; i <= width ; i++)
{
for (int j = 0; j <= height; j++)
{
if (grid[i, j] == 1)
{
if (counter >= startIndex)
{
Vector3Int tilePosition = new Vector3Int(i, j, 0);
tilePosition += ComputeOffset(width, height);
tilemap.SetTile(tilePosition, tile);
drawCount++;
}
if (drawCount > numberOfTilesToDraw)
{
return counter;
}
counter++;
}
}
}
return counter;
}
/// <summary>
/// Determines the offset to apply to a grid to have it centered
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public static Vector3Int ComputeOffset(int width, int height)
{
Vector3Int offset = new Vector3Int(width + 2, height + 2, 0);
offset = offset - offset/2;
return -offset;
}
/// <summary>
/// Clears and refreshes an entire tilemap
/// </summary>
/// <param name="tilemap"></param>
public static void ClearTilemap(Tilemap tilemap)
{
tilemap.ClearAllTiles();
tilemap.RefreshAllTiles();
}
}
}