Archived
Private
Public Access
1
0
This repository has been archived on 2026-02-04. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ProjectBackup/Unity/Minecraft/Assets/Scripts/Terrain/Clouds.cs
2022-11-12 13:10:03 +01:00

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;
}
}
}