Skip to content

Instantly share code, notes, and snippets.

@GeorgiyRyaposov
Created January 14, 2025 11:17
Show Gist options
  • Save GeorgiyRyaposov/d8559af4b25491bde352a40e6f6ae684 to your computer and use it in GitHub Desktop.
Save GeorgiyRyaposov/d8559af4b25491bde352a40e6f6ae684 to your computer and use it in GitHub Desktop.
Simple square grid: converts position to index; keep flat list of grid items
using Unity.Burst;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Events;
namespace Grids.Square
{
[BurstCompile]
public class SquareGrid<T>
{
private readonly UnityEvent<OnValueChangedArgs> _onValueChanged = new ();
public class OnValueChangedArgs
{
public int X;
public int Y;
}
private readonly int _width;
private readonly int _height;
private readonly T[] _cells;
private readonly IIndexesHelper _indexesHelper;
private readonly float3 _originPosition;
private readonly float _cellSize;
public int Width => _width;
public int Height => _height;
public float3 OriginPosition => _originPosition;
public float CellSize => _cellSize;
public SquareGrid(int width, int height, float cellSize, float3 originPosition, System.Func<SquareGrid<T>, int, int, T> createCell, bool xzPlane = true)
{
_width = width;
_height = height;
_originPosition = originPosition;
_cellSize = cellSize;
_cells = new T[width * height];
_indexesHelper = xzPlane
? new IndexesHelperXZ(cellSize, originPosition)
: new IndexesHelperXY(cellSize, originPosition);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
var index = x + y * _width;
_cells[index] = createCell(this, x, y);
}
}
}
public float3 GetWorldPosition(int x, int y)
{
return _indexesHelper.GetWorldPosition(x, y);
}
public int2 GetIndexes(float3 worldPos)
{
return _indexesHelper.GetCellIndex(worldPos);
}
public void SetValue(float3 worldPos, T value)
{
var indexes = GetIndexes(worldPos);
SetValue(indexes.x, indexes.y, value);
}
public void SetValue(int x, int y, T value)
{
var index = x + y * _width;
if (index < _cells.Length)
{
_cells[index] = value;
TriggerOnValueChanged(x, y);
}
else
{
Debug.LogError($"Index out of range : {index} ({x}:{y})");
}
}
public T GetValue(float3 worldPos)
{
var indexes = GetIndexes(worldPos);
return GetValue(indexes.x, indexes.y);
}
public T GetValue(int x, int y)
{
var index = x + y * _width;
return index < _cells.Length ? _cells[index] : default;
}
public void TriggerOnValueChanged(int x, int y)
{
_onValueChanged.Invoke(new OnValueChangedArgs() {X = x, Y = y});
}
public void SubscribeOnValueChanged(UnityAction<OnValueChangedArgs> action)
{
_onValueChanged.AddListener(action);
}
public void UnsubscribeOnValueChanged(UnityAction<OnValueChangedArgs> action)
{
_onValueChanged.RemoveListener(action);
}
[BurstCompile]
public void DrawGridDebug()
{
var mapWidth = _width;
var mapHeight = _height;
var color = Color.white;
for (int x = 0; x < mapWidth; x++)
{
for (int y = 0; y < mapHeight; y++)
{
DrawCell(x, y, color);
}
}
Debug.DrawLine(GetWorldPosition(0, mapHeight), GetWorldPosition(mapWidth, mapHeight), color, 100f);
Debug.DrawLine(GetWorldPosition(mapWidth, 0), GetWorldPosition(mapWidth, mapHeight), color, 100f);
}
private void DrawCell(int x, int y, Color color)
{
Debug.DrawLine(GetWorldPosition(x, y), GetWorldPosition(x, y + 1), color, 100f);
Debug.DrawLine(GetWorldPosition(x, y), GetWorldPosition(x + 1, y), color, 100f);
}
#region IndexesHelper
private interface IIndexesHelper
{
float3 GetWorldPosition(int x, int y);
int2 GetCellIndex(float3 worldPos);
}
private class IndexesHelperXZ : IIndexesHelper
{
private readonly float _cellSize;
private readonly float3 _originPosition;
public IndexesHelperXZ(float cellSize, float3 originPosition)
{
_cellSize = cellSize;
_originPosition = originPosition;
}
public float3 GetWorldPosition(int x, int y)
{
return new float3(x, 0, y) * _cellSize + _originPosition;
}
public int2 GetCellIndex(float3 worldPos)
{
return SquareGridCellUtil.GetCellIndexXZ(worldPos, _originPosition, _cellSize);
}
}
private class IndexesHelperXY : IIndexesHelper
{
private readonly float _cellSize;
private readonly float3 _originPosition;
public IndexesHelperXY(float cellSize, float3 originPosition)
{
_cellSize = cellSize;
_originPosition = originPosition;
}
public float3 GetWorldPosition(int x, int y)
{
return new float3(x, y, 0) * _cellSize + _originPosition;
}
public int2 GetCellIndex(float3 worldPos)
{
return SquareGridCellUtil.GetCellIndexXY(worldPos, _originPosition, _cellSize);
}
}
#endregion //IndexesHelper
}
public static class SquareGridCellUtil
{
public static int2 GetCellIndexXY(float3 worldPos, float3 gridOriginPos, float gridCellSize)
{
var pos = worldPos - gridOriginPos;
return new int2((int) math.floor(pos.x / gridCellSize),
(int) math.floor(pos.y / gridCellSize));
}
public static int2 GetCellIndexXZ(float3 worldPos, float3 gridOriginPos, float gridCellSize)
{
var pos = worldPos - gridOriginPos;
return new int2((int) math.floor(pos.x / gridCellSize),
(int) math.floor(pos.z / gridCellSize));
}
public static int CalculateIndex(int x, int y, int gridWidth)
{
return x + y * gridWidth;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment