Files
TheDeclineOfWarriors/Assets/Scripts/WorldGen/ChunkTemplate.cs
T
2026-03-29 02:26:31 +07:00

233 lines
6.3 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace InfiniteWorld
{
[CreateAssetMenu(menuName = "Infinite World/Chunk Template", fileName = "ChunkTemplate")]
public class ChunkTemplate : ScriptableObject
{
[Min(4)] public int width = 16;
[Min(4)] public int height = 16;
[Header("Exits")]
public bool exitTop = true;
public bool exitRight = true;
public bool exitBottom = true;
public bool exitLeft = true;
[SerializeField] private List<ChunkCellData> cells = new List<ChunkCellData>();
public int CellCount => width * height;
public void EnsureCellData()
{
int target = Mathf.Max(1, width * height);
while (cells.Count < target)
{
cells.Add(new ChunkCellData());
}
while (cells.Count > target)
{
cells.RemoveAt(cells.Count - 1);
}
}
public void Resize(int newWidth, int newHeight)
{
newWidth = Mathf.Max(4, newWidth);
newHeight = Mathf.Max(4, newHeight);
List<ChunkCellData> oldCells = new List<ChunkCellData>(cells);
int oldWidth = width;
int oldHeight = height;
width = newWidth;
height = newHeight;
cells = new List<ChunkCellData>(newWidth * newHeight);
for (int i = 0; i < newWidth * newHeight; i++)
{
cells.Add(new ChunkCellData());
}
for (int y = 0; y < Mathf.Min(oldHeight, newHeight); y++)
{
for (int x = 0; x < Mathf.Min(oldWidth, newWidth); x++)
{
int oldIndex = y * oldWidth + x;
if (oldIndex < oldCells.Count)
{
cells[Index(x, y)] = oldCells[oldIndex];
}
}
}
}
public void Clear()
{
EnsureCellData();
for (int i = 0; i < cells.Count; i++)
{
cells[i] = new ChunkCellData();
}
}
public bool GetWall(int x, int y)
{
return IsInBounds(x, y) && cells[Index(x, y)].wall;
}
public bool GetEnvironment(int x, int y)
{
return IsInBounds(x, y) && cells[Index(x, y)].environment;
}
public void SetWall(int x, int y, bool value)
{
if (!IsInBounds(x, y))
{
return;
}
EnsureCellData();
ChunkCellData data = cells[Index(x, y)];
data.wall = value;
if (value)
{
data.environment = false;
}
cells[Index(x, y)] = data;
}
public void SetEnvironment(int x, int y, bool value)
{
if (!IsInBounds(x, y))
{
return;
}
EnsureCellData();
ChunkCellData data = cells[Index(x, y)];
data.environment = value;
if (value)
{
data.wall = false;
}
cells[Index(x, y)] = data;
}
public bool GetExit(ChunkExit exit)
{
return exit switch
{
ChunkExit.Top => exitTop,
ChunkExit.Right => exitRight,
ChunkExit.Bottom => exitBottom,
ChunkExit.Left => exitLeft,
_ => false
};
}
public int ExitCount()
{
int count = 0;
count += exitTop ? 1 : 0;
count += exitRight ? 1 : 0;
count += exitBottom ? 1 : 0;
count += exitLeft ? 1 : 0;
return count;
}
public void ApplyBorderWallsFromExits(int openingWidth = 3)
{
EnsureCellData();
Clear();
for (int x = 0; x < width; x++)
{
SetWall(x, 0, true);
SetWall(x, height - 1, true);
}
for (int y = 0; y < height; y++)
{
SetWall(0, y, true);
SetWall(width - 1, y, true);
}
CarveExit(ChunkExit.Top, openingWidth);
CarveExit(ChunkExit.Right, openingWidth);
CarveExit(ChunkExit.Bottom, openingWidth);
CarveExit(ChunkExit.Left, openingWidth);
}
public void CarveExit(ChunkExit exit, int openingWidth = 3)
{
if (!GetExit(exit))
{
return;
}
int half = Mathf.Max(1, openingWidth) / 2;
switch (exit)
{
case ChunkExit.Top:
for (int x = width / 2 - half; x <= width / 2 + half; x++)
{
SetWall(x, height - 1, false);
SetWall(x, height - 2, false);
}
break;
case ChunkExit.Right:
for (int y = height / 2 - half; y <= height / 2 + half; y++)
{
SetWall(width - 1, y, false);
SetWall(width - 2, y, false);
}
break;
case ChunkExit.Bottom:
for (int x = width / 2 - half; x <= width / 2 + half; x++)
{
SetWall(x, 0, false);
SetWall(x, 1, false);
}
break;
case ChunkExit.Left:
for (int y = height / 2 - half; y <= height / 2 + half; y++)
{
SetWall(0, y, false);
SetWall(1, y, false);
}
break;
}
}
private int Index(int x, int y)
{
return y * width + x;
}
private bool IsInBounds(int x, int y)
{
return x >= 0 && y >= 0 && x < width && y < height;
}
}
public enum ChunkExit
{
Top,
Right,
Bottom,
Left
}
[Serializable]
public struct ChunkCellData
{
public bool wall;
public bool environment;
}
}