Skip to content

Instantly share code, notes, and snippets.

@baba-s
Created December 29, 2025 03:36
Show Gist options
  • Select an option

  • Save baba-s/dc692e3f15462f9a823b60cf54321431 to your computer and use it in GitHub Desktop.

Select an option

Save baba-s/dc692e3f15462f9a823b60cf54321431 to your computer and use it in GitHub Desktop.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace Kogane
{
[RequireComponent( typeof( MeshFilter ), typeof( MeshRenderer ) )]
public sealed class ColoredTilemap : MonoBehaviour
{
private const int VERTICES_PER_TILE = 4;
private const int INDICES_PER_TILE = 6;
[SerializeField] private MeshFilter m_meshFilter;
[SerializeField] private MeshRenderer m_meshRenderer;
[SerializeField] private int m_width = 64;
[SerializeField] private int m_height = 64;
[SerializeField] private float m_cellSize = 1;
private bool m_isInitialized;
private int m_tileCount;
private int m_halfWidth;
private int m_halfHeight;
private Mesh m_mesh;
private Color32[] m_tileColors;
private Color32[] m_meshColors32;
private bool m_isDirty;
private void OnDestroy()
{
if ( m_mesh == null ) return;
Destroy( m_mesh );
m_mesh = null;
}
private void Awake()
{
Initialize();
}
private void Initialize()
{
if ( m_isInitialized ) return;
m_isInitialized = true;
m_tileCount = m_width * m_height;
m_halfWidth = m_width / 2;
m_halfHeight = m_height / 2;
var vertexCount = m_tileCount * VERTICES_PER_TILE;
var indexCount = m_tileCount * INDICES_PER_TILE;
m_tileColors = new Color32[ m_tileCount ];
m_meshColors32 = new Color32[ vertexCount ];
var vertices = new Vector3[ vertexCount ];
var uvs = new Vector2[ vertexCount ];
var triangles = new int[ indexCount ];
var vi = 0;
var ti = 0;
for ( var y = 0; y < m_height; y++ )
{
var gy = y - m_halfHeight; // グリッドy
for ( var x = 0; x < m_width; x++ )
{
var gx = x - m_halfWidth; // グリッドx
// タイルの左下座標(ローカル)
var lx = gx * m_cellSize;
var ly = gy * m_cellSize;
// 4頂点(左下, 右下, 右上, 左上)
vertices[ vi + 0 ] = new( lx, ly );
vertices[ vi + 1 ] = new( lx + m_cellSize, ly );
vertices[ vi + 2 ] = new( lx + m_cellSize, ly + m_cellSize );
vertices[ vi + 3 ] = new( lx, ly + m_cellSize );
// UV(適当でOK)
uvs[ vi + 0 ] = new( 0, 0 );
uvs[ vi + 1 ] = new( 1, 0 );
uvs[ vi + 2 ] = new( 1, 1 );
uvs[ vi + 3 ] = new( 0, 1 );
// 2三角形
triangles[ ti + 0 ] = vi + 0;
triangles[ ti + 1 ] = vi + 2;
triangles[ ti + 2 ] = vi + 1;
triangles[ ti + 3 ] = vi + 0;
triangles[ ti + 4 ] = vi + 3;
triangles[ ti + 5 ] = vi + 2;
vi += VERTICES_PER_TILE;
ti += INDICES_PER_TILE;
}
}
m_mesh = new();
m_mesh.MarkDynamic();
m_mesh.indexFormat = IndexFormat.UInt32;
m_mesh.vertices = vertices;
m_mesh.uv = uvs;
m_mesh.triangles = triangles;
m_mesh.RecalculateBounds();
m_mesh.RecalculateNormals();
m_meshFilter.sharedMesh = m_mesh;
}
public void Setup
(
in Vector2Int position,
in Color color
)
{
Initialize();
SetTileColor
(
position: position,
color: color
);
ApplyColorToMesh( position );
}
public void Setup
(
IReadOnlyList<Vector2Int> positions,
in Color color
)
{
Initialize();
for ( var i = 0; i < positions.Count; i++ )
{
SetTileColor
(
position: positions[ i ],
color: color
);
}
ApplyAllColorsToMesh();
}
private void SetTileColor
(
in Vector2Int position,
in Color color
)
{
if ( !TryToIndex( position, out var index ) ) return;
m_tileColors[ index ] = color;
}
private void ApplyAllColorsToMesh()
{
for ( var i = 0; i < m_tileCount; i++ )
{
var color = m_tileColors[ i ];
var startIndex = i * VERTICES_PER_TILE;
m_meshColors32[ startIndex + 0 ] = color;
m_meshColors32[ startIndex + 1 ] = color;
m_meshColors32[ startIndex + 2 ] = color;
m_meshColors32[ startIndex + 3 ] = color;
}
m_isDirty = true;
}
private void ApplyColorToMesh( in Vector2Int position )
{
if ( !TryToIndex( position, out var index ) ) return;
var color = m_tileColors[ index ];
var startIndex = index * VERTICES_PER_TILE;
m_meshColors32[ startIndex + 0 ] = color;
m_meshColors32[ startIndex + 1 ] = color;
m_meshColors32[ startIndex + 2 ] = color;
m_meshColors32[ startIndex + 3 ] = color;
m_isDirty = true;
}
private bool TryToIndex
(
in Vector2Int position,
out int index
)
{
var x = position.x + m_halfWidth;
var y = position.y + m_halfHeight;
if ( x < 0 || m_width <= x || y < 0 || m_height <= y )
{
index = -1;
return false;
}
index = x + y * m_width;
return true;
}
private void LateUpdate()
{
if ( !m_isDirty ) return;
m_isDirty = false;
m_mesh.colors32 = m_meshColors32;
}
public Vector3Int WorldToCell( in Vector3 worldPosition )
{
Initialize();
var local = transform.InverseTransformPoint( worldPosition );
var gridX = Mathf.FloorToInt( local.x / m_cellSize + 0.5f );
var gridY = Mathf.FloorToInt( local.y / m_cellSize + 0.5f );
return new( gridX, gridY );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment