216 lines
6.2 KiB
C#
216 lines
6.2 KiB
C#
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Utility struct for chunk coordinate conversions.
|
|
/// Handles conversions between world, grid, chunk, and local block coordinates.
|
|
/// </summary>
|
|
public struct ChunkCoord
|
|
{
|
|
public const int CHUNK_SIZE = 4;
|
|
|
|
/// <summary>
|
|
/// Chunk position in chunk coordinates (not world or grid)
|
|
/// </summary>
|
|
public Vector3Int chunkPos;
|
|
|
|
public ChunkCoord(Vector3Int pos)
|
|
{
|
|
chunkPos = pos;
|
|
}
|
|
|
|
public ChunkCoord(int x, int y, int z)
|
|
{
|
|
chunkPos = new Vector3Int(x, y, z);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the grid position of the chunk's origin (corner with smallest coordinates)
|
|
/// </summary>
|
|
public Vector3Int GridOrigin => new Vector3Int(
|
|
chunkPos.x * CHUNK_SIZE,
|
|
chunkPos.y * CHUNK_SIZE,
|
|
chunkPos.z * CHUNK_SIZE
|
|
);
|
|
|
|
/// <summary>
|
|
/// Get world position of chunk origin using BuildManager's grid system
|
|
/// </summary>
|
|
public Vector3 WorldOrigin
|
|
{
|
|
get
|
|
{
|
|
if (BuildManager.Instance != null)
|
|
{
|
|
return BuildManager.Instance.GridToWorld(GridOrigin);
|
|
}
|
|
// Fallback if BuildManager not available
|
|
return new Vector3(
|
|
GridOrigin.x + 0.5f,
|
|
GridOrigin.y + 0.5f,
|
|
GridOrigin.z + 0.5f
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert grid coordinates to chunk coordinates
|
|
/// </summary>
|
|
public static ChunkCoord FromGridPos(Vector3Int gridPos)
|
|
{
|
|
return new ChunkCoord(
|
|
Mathf.FloorToInt((float)gridPos.x / CHUNK_SIZE),
|
|
Mathf.FloorToInt((float)gridPos.y / CHUNK_SIZE),
|
|
Mathf.FloorToInt((float)gridPos.z / CHUNK_SIZE)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert world position to chunk coordinates
|
|
/// </summary>
|
|
public static ChunkCoord FromWorldPos(Vector3 worldPos)
|
|
{
|
|
Vector3Int gridPos;
|
|
if (BuildManager.Instance != null)
|
|
{
|
|
gridPos = BuildManager.Instance.WorldToGrid3D(worldPos);
|
|
}
|
|
else
|
|
{
|
|
// Fallback
|
|
gridPos = new Vector3Int(
|
|
Mathf.RoundToInt(worldPos.x - 0.5f),
|
|
Mathf.RoundToInt(worldPos.y - 0.5f),
|
|
Mathf.RoundToInt(worldPos.z - 0.5f)
|
|
);
|
|
}
|
|
return FromGridPos(gridPos);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get local block coordinates within chunk from grid position
|
|
/// </summary>
|
|
public static Vector3Int GridToLocal(Vector3Int gridPos)
|
|
{
|
|
// Use modulo to get local position, handling negative coords
|
|
int x = ((gridPos.x % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE;
|
|
int y = ((gridPos.y % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE;
|
|
int z = ((gridPos.z % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE;
|
|
return new Vector3Int(x, y, z);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert local block coordinates to grid position
|
|
/// </summary>
|
|
public Vector3Int LocalToGrid(Vector3Int localPos)
|
|
{
|
|
return GridOrigin + localPos;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert local block coordinates to world position
|
|
/// </summary>
|
|
public Vector3 LocalToWorld(Vector3Int localPos)
|
|
{
|
|
Vector3Int gridPos = LocalToGrid(localPos);
|
|
if (BuildManager.Instance != null)
|
|
{
|
|
return BuildManager.Instance.GridToWorld(gridPos);
|
|
}
|
|
return new Vector3(gridPos.x + 0.5f, gridPos.y + 0.5f, gridPos.z + 0.5f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert local index to local 3D coordinates
|
|
/// </summary>
|
|
public static Vector3Int IndexToLocal(int index)
|
|
{
|
|
int x = index % CHUNK_SIZE;
|
|
int y = (index / CHUNK_SIZE) % CHUNK_SIZE;
|
|
int z = index / (CHUNK_SIZE * CHUNK_SIZE);
|
|
return new Vector3Int(x, y, z);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert local 3D coordinates to index
|
|
/// </summary>
|
|
public static int LocalToIndex(Vector3Int localPos)
|
|
{
|
|
return localPos.x + localPos.y * CHUNK_SIZE + localPos.z * CHUNK_SIZE * CHUNK_SIZE;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert local coordinates (int) to index
|
|
/// </summary>
|
|
public static int LocalToIndex(int x, int y, int z)
|
|
{
|
|
return x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if local coordinates are within valid range
|
|
/// </summary>
|
|
public static bool IsValidLocal(int x, int y, int z)
|
|
{
|
|
return x >= 0 && x < CHUNK_SIZE &&
|
|
y >= 0 && y < CHUNK_SIZE &&
|
|
z >= 0 && z < CHUNK_SIZE;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if local position is within valid range
|
|
/// </summary>
|
|
public static bool IsValidLocal(Vector3Int local)
|
|
{
|
|
return IsValidLocal(local.x, local.y, local.z);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert world hit point to local block index within chunk
|
|
/// </summary>
|
|
public int WorldPointToLocalIndex(Vector3 worldPoint)
|
|
{
|
|
// Get chunk origin in world space
|
|
Vector3 chunkWorldOrigin = WorldOrigin;
|
|
|
|
// Calculate offset from chunk origin (in grid units, assuming 1 unit per block)
|
|
float cellSize = BuildManager.Instance != null ? BuildManager.Instance.cellSize : 1f;
|
|
Vector3 offset = (worldPoint - chunkWorldOrigin) / cellSize;
|
|
|
|
// Convert to local coordinates (add small epsilon to handle edge cases)
|
|
int lx = Mathf.Clamp(Mathf.FloorToInt(offset.x + 0.5f), 0, CHUNK_SIZE - 1);
|
|
int ly = Mathf.Clamp(Mathf.FloorToInt(offset.y + 0.5f), 0, CHUNK_SIZE - 1);
|
|
int lz = Mathf.Clamp(Mathf.FloorToInt(offset.z + 0.5f), 0, CHUNK_SIZE - 1);
|
|
|
|
return LocalToIndex(lx, ly, lz);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (obj is ChunkCoord other)
|
|
{
|
|
return chunkPos == other.chunkPos;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return chunkPos.GetHashCode();
|
|
}
|
|
|
|
public static bool operator ==(ChunkCoord a, ChunkCoord b)
|
|
{
|
|
return a.chunkPos == b.chunkPos;
|
|
}
|
|
|
|
public static bool operator !=(ChunkCoord a, ChunkCoord b)
|
|
{
|
|
return a.chunkPos != b.chunkPos;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"ChunkCoord({chunkPos.x}, {chunkPos.y}, {chunkPos.z})";
|
|
}
|
|
}
|