WorldGen
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user