181 lines
7.4 KiB
C#
181 lines
7.4 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Terrain {
|
|
public class Clouds : MonoBehaviour {
|
|
|
|
public int cloudHeight = 100;
|
|
|
|
[SerializeField] private Texture2D cloudPattern;
|
|
[SerializeField] private Material cloudMaterial;
|
|
[SerializeField] private World world;
|
|
private bool[,] _cloudData;
|
|
|
|
private int _cloudTextureWidth;
|
|
private int _cloudTileSize;
|
|
private Vector3Int _offset;
|
|
|
|
private readonly Dictionary<Vector2Int, GameObject> _clouds = new Dictionary<Vector2Int, GameObject>();
|
|
|
|
private void Start() {
|
|
if (World.Settings.clouds == 0) return;
|
|
_cloudTextureWidth = cloudPattern.width;
|
|
_cloudTileSize = WorldData.ChunkSize.x;
|
|
_offset = new Vector3Int(-(_cloudTextureWidth / 2), 0, -(_cloudTextureWidth / 2));
|
|
|
|
transform.position = new Vector3(WorldData.WorldCenter, cloudHeight, WorldData.WorldCenter);
|
|
|
|
LoadCloudData();
|
|
CreateClouds();
|
|
}
|
|
|
|
private void LoadCloudData() {
|
|
_cloudData = new bool[_cloudTextureWidth, _cloudTextureWidth];
|
|
Color[] colors = cloudPattern.GetPixels();
|
|
|
|
for (int x = 0; x < _cloudTextureWidth; x++) {
|
|
for (int y = 0; y < _cloudTextureWidth; y++) {
|
|
_cloudData[x, y] = colors[x + y * _cloudTextureWidth].a > 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateClouds() {
|
|
for (int x = 0; x < _cloudTextureWidth; x += _cloudTileSize)
|
|
for (int y = 0; y < _cloudTextureWidth; y += _cloudTileSize) {
|
|
Mesh cloudMesh = World.Settings.clouds == 1 ? CreateFastCloudMesh(x, y) : CreateFancyCloudMesh(x, y);
|
|
Vector3 position = new Vector3(x, cloudHeight, y);
|
|
_clouds.Add(CloudTilePosFromVector3(position), CreateCloudTile(cloudMesh, position));
|
|
}
|
|
}
|
|
|
|
public void UpdateClouds() {
|
|
if (World.Settings.clouds == 0) return;
|
|
|
|
for (int x = 0; x < _cloudTextureWidth; x += _cloudTileSize)
|
|
for (int y = 0; y < _cloudTextureWidth; y += _cloudTileSize) {
|
|
Vector3 position = world.player.position + new Vector3(x, 0, y) + _offset;
|
|
position = new Vector3(RoundToCloud(position.x), cloudHeight, RoundToCloud(position.z));
|
|
Vector2Int cloudPostition = CloudTilePosFromVector3(position);
|
|
|
|
_clouds[cloudPostition].transform.position = position;
|
|
}
|
|
}
|
|
|
|
private int RoundToCloud(float value) => Mathf.FloorToInt(value / _cloudTileSize) * _cloudTileSize;
|
|
|
|
private Mesh CreateFastCloudMesh(int x, int y) {
|
|
List<Vector3> vertices = new List<Vector3>();
|
|
List<int> triangles = new List<int>();
|
|
List<Vector3> normals = new List<Vector3>();
|
|
int vertexCount = 0;
|
|
|
|
for (int xIncrement = 0; xIncrement < _cloudTileSize; xIncrement++) {
|
|
for (int yIncrement = 0; yIncrement < _cloudTileSize; yIncrement++) {
|
|
int xVal = x + xIncrement;
|
|
int yVal = y + yIncrement;
|
|
|
|
if (!_cloudData[xVal, yVal]) continue;
|
|
|
|
vertices.Add(new Vector3(xIncrement, 0, yIncrement));
|
|
vertices.Add(new Vector3(xIncrement, 0, yIncrement + 1));
|
|
vertices.Add(new Vector3(xIncrement + 1, 0, yIncrement + 1));
|
|
vertices.Add(new Vector3(xIncrement + 1, 0, yIncrement));
|
|
|
|
for (int i = 0; i < 4; i++) normals.Add(Vector3.down);
|
|
|
|
triangles.Add(vertexCount + 1);
|
|
triangles.Add(vertexCount);
|
|
triangles.Add(vertexCount + 2);
|
|
|
|
triangles.Add(vertexCount + 2);
|
|
triangles.Add(vertexCount);
|
|
triangles.Add(vertexCount + 3);
|
|
|
|
vertexCount += 4;
|
|
}
|
|
}
|
|
|
|
Mesh mesh = new Mesh();
|
|
mesh.vertices = vertices.ToArray();
|
|
mesh.triangles = triangles.ToArray();
|
|
mesh.normals = normals.ToArray();
|
|
return mesh;
|
|
}
|
|
|
|
private Mesh CreateFancyCloudMesh(int x, int y) {
|
|
List<Vector3> vertices = new List<Vector3>();
|
|
List<int> triangles = new List<int>();
|
|
List<Vector3> normals = new List<Vector3>();
|
|
int vertexCount = 0;
|
|
|
|
for (int xIncrement = 0; xIncrement < _cloudTileSize; xIncrement++) {
|
|
for (int yIncrement = 0; yIncrement < _cloudTileSize; yIncrement++) {
|
|
int xVal = x + xIncrement;
|
|
int yVal = y + yIncrement;
|
|
|
|
if (!_cloudData[xVal, yVal]) continue;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
if (CheckCloudData(new Vector3Int(xVal, 0, yVal) + WorldData.FaceChecks[i])) continue;
|
|
|
|
for (int j = 0; j < 4; j++) {
|
|
Vector3 vert = new Vector3(xIncrement, 0, yIncrement);
|
|
vert += WorldData.BlockVerts[WorldData.BlockTris[i, j]];
|
|
vertices.Add(vert);
|
|
}
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
normals.Add(WorldData.FaceChecks[j]);
|
|
|
|
triangles.Add(vertexCount);
|
|
triangles.Add(vertexCount + 1);
|
|
triangles.Add(vertexCount + 2);
|
|
triangles.Add(vertexCount + 2);
|
|
triangles.Add(vertexCount + 1);
|
|
triangles.Add(vertexCount + 3);
|
|
|
|
vertexCount += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
Mesh mesh = new Mesh();
|
|
mesh.vertices = vertices.ToArray();
|
|
mesh.triangles = triangles.ToArray();
|
|
mesh.normals = normals.ToArray();
|
|
return mesh;
|
|
}
|
|
|
|
private bool CheckCloudData(Vector3Int faceCheck) {
|
|
if (faceCheck.y != 0) return false;
|
|
Vector2Int pos = CloudTilePosFromVector3(faceCheck);
|
|
return _cloudData[pos.x, pos.y];
|
|
}
|
|
|
|
private GameObject CreateCloudTile(in Mesh mesh, in Vector3 position) {
|
|
GameObject cloudTile = new GameObject();
|
|
cloudTile.transform.position = new Vector3(position.x, position.y, position.z);
|
|
cloudTile.transform.parent = transform;
|
|
cloudTile.name = $"CloudTile [{position.x}:{position.z}]";
|
|
|
|
MeshFilter meshFilter = cloudTile.AddComponent<MeshFilter>();
|
|
MeshRenderer meshRenderer = cloudTile.AddComponent<MeshRenderer>();
|
|
|
|
meshRenderer.material = cloudMaterial;
|
|
meshFilter.mesh = mesh;
|
|
|
|
return cloudTile;
|
|
}
|
|
|
|
private Vector2Int CloudTilePosFromVector3(in Vector3 pos) => new Vector2Int(CloudTileCoordFromFloat(pos.x), CloudTileCoordFromFloat(pos.z));
|
|
|
|
private int CloudTileCoordFromFloat(in float coord) {
|
|
float a = coord / _cloudTextureWidth;
|
|
a -= Mathf.FloorToInt(a);
|
|
int b = Mathf.FloorToInt(_cloudTextureWidth * a);
|
|
return b;
|
|
}
|
|
|
|
}
|
|
} |