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
2022-11-12 13:10:03 +01:00

232 lines
9.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading.Tasks;
using UnityEngine;
namespace Terrain {
public class Chunk {
public readonly Vector2 Position;
public readonly World World;
private readonly Dictionary<Vector2, int> _blocks = new Dictionary<Vector2, int>();
private readonly Dictionary<Vector2, Obstical> _obsticals = new Dictionary<Vector2, Obstical>();
private readonly GameObject _object;
private readonly MeshFilter _filter;
private readonly Bounds _chunkWorldBounds;
private readonly Bounds _chunkViewBounds;
private readonly GameObject _subObject;
private readonly MeshFilter _subFilter;
public bool Visible;
public Chunk(Vector2 position, World world) {
Position = position;
World = world;
_object = new GameObject();
_object.SetActive(false);
_filter = _object.AddComponent<MeshFilter>();
MeshRenderer renderer = _object.AddComponent<MeshRenderer>();
renderer.material = world.GetTerrainTextureManager().Material;
renderer.sortingLayerName = "Terrain";
_object.transform.SetParent(world.transform);
_object.transform.position = new Vector3(position.x * World.ChunkSize,
position.y * World.ChunkSize);
_object.name = $"Chunk [{position.x}:{position.y}]";
_chunkWorldBounds = new Bounds(_object.transform.position + new Vector3(5, 5), new Vector3(10, 10));
_chunkViewBounds = new Bounds(_chunkWorldBounds.center, _chunkWorldBounds.size + new Vector3(5, 5));
_subObject = new GameObject();
_subObject.SetActive(false);
_subObject.transform.SetParent(_object.transform);
_subObject.transform.position = _object.transform.position;
_subObject.name = "Animatable Blocks";
_subFilter = _subObject.AddComponent<MeshFilter>();
MeshRenderer subRenderer = _subObject.AddComponent<MeshRenderer>();
subRenderer.material = world.GetTerrainTextureManager().Material;
subRenderer.sortingLayerName = "Terrain";
GenerateChunk();
}
private void GenerateChunk() {
Mesh mesh = new Mesh();
int vertexIndex = 0;
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
List<Vector2> uvs = new List<Vector2>();
Mesh aMesh = new Mesh();
int aVertexIndex = 0;
List<Vector3> aVertices = new List<Vector3>();
List<int> aTriangles = new List<int>();
List<Vector2> aUVs = new List<Vector2>();
for (int x = 0; x < World.ChunkSize; x++) {
for (int y = World.ChunkSize; y > 0; y--) {
Vector3 pos = new Vector2(x, y);
Block block = GenerateBlock(pos + _object.transform.position);
RectangleF texture = block.GetTile(World.GetTerrainTextureManager());
if (block.Animatable) {
aVertices.Add(pos);
aVertices.Add(pos + new Vector3(0, 1));
aVertices.Add(pos + new Vector3(1, 0));
aVertices.Add(pos + new Vector3(1, 1));
aUVs.Add(new Vector2(texture.X, texture.Y));
aUVs.Add(new Vector2(texture.X, texture.Y + texture.Height));
aUVs.Add(new Vector2(texture.X + texture.Width, texture.Y));
aUVs.Add(new Vector2(texture.X + texture.Width, texture.Y + texture.Height));
aTriangles.Add(aVertexIndex);
aTriangles.Add(aVertexIndex + 1);
aTriangles.Add(aVertexIndex + 2);
aTriangles.Add(aVertexIndex + 2);
aTriangles.Add(aVertexIndex + 1);
aTriangles.Add(aVertexIndex + 3);
aVertexIndex += 4;
}
else {
vertices.Add(pos);
vertices.Add(pos + new Vector3(0, 1));
vertices.Add(pos + new Vector3(1, 0));
vertices.Add(pos + new Vector3(1, 1));
uvs.Add(new Vector2(texture.X, texture.Y));
uvs.Add(new Vector2(texture.X, texture.Y + texture.Height));
uvs.Add(new Vector2(texture.X + texture.Width, texture.Y));
uvs.Add(new Vector2(texture.X + texture.Width, texture.Y + texture.Height));
triangles.Add(vertexIndex);
triangles.Add(vertexIndex + 1);
triangles.Add(vertexIndex + 2);
triangles.Add(vertexIndex + 2);
triangles.Add(vertexIndex + 1);
triangles.Add(vertexIndex + 3);
vertexIndex += 4;
}
}
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.uv = uvs.ToArray();
mesh.RecalculateNormals();
_filter.mesh = mesh;
aMesh.vertices = aVertices.ToArray();
aMesh.triangles = aTriangles.ToArray();
aMesh.uv = aUVs.ToArray();
aMesh.RecalculateNormals();
_subFilter.mesh = aMesh;
}
private Block GenerateBlock(Vector2 position) {
int blockId = World.GenerateBlock(position, this);
_blocks.Add(position, blockId);
Block block = Block.GetBlock(blockId);
return block;
}
public void Update() {
SetVisible(World.player.CanSee(_chunkViewBounds));
}
public void FixedUpdate() {
}
public void SetVisible(bool value) {
if (value) {
_object.SetActive(true);
_subObject.SetActive(true);
foreach (var obs in _obsticals.Values)
obs.SetActive(true);
Visible = true;
}
else {
Visible = false;
_object.SetActive(false);
_subObject.SetActive(false);
foreach (var obs in _obsticals.Values)
obs.SetActive(false);
}
}
public void OnAnimationFrameChange(int frame) {
if (!Visible) return;
Mesh mesh = new Mesh();
int vertexIndex = 0;
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
List<Vector2> uvs = new List<Vector2>();
for (int x = 0; x < World.ChunkSize; x++) {
for (int y = World.ChunkSize; y > 0; y--) {
Vector3 pos = new Vector2(x, y);
Block block = Block.GetBlock(_blocks[pos + _object.transform.position]);
if (!block.Animatable) continue;
vertices.Add(pos);
vertices.Add(pos + new Vector3(0, 1));
vertices.Add(pos + new Vector3(1, 0));
vertices.Add(pos + new Vector3(1, 1));
RectangleF texture = block.GetTile(World.GetTerrainTextureManager(), frame % block.Tiles.Length);
uvs.Add(new Vector2(texture.X, texture.Y));
uvs.Add(new Vector2(texture.X, texture.Y + texture.Height));
uvs.Add(new Vector2(texture.X + texture.Width, texture.Y));
uvs.Add(new Vector2(texture.X + texture.Width, texture.Y + texture.Height));
triangles.Add(vertexIndex);
triangles.Add(vertexIndex + 1);
triangles.Add(vertexIndex + 2);
triangles.Add(vertexIndex + 2);
triangles.Add(vertexIndex + 1);
triangles.Add(vertexIndex + 3);
vertexIndex += 4;
}
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.uv = uvs.ToArray();
mesh.RecalculateNormals();
_subFilter.mesh = mesh;
}
public Block GetBlock(Vector2 pos) {
try {
return Block.GetBlock(_blocks[pos]);
}
catch (Exception) {
return null;
}
}
public Obstical GetObstical(Vector2 pos) {
try {
return _obsticals[pos];
}
catch (Exception) {
return null;
}
}
public GameObject GetObject() { return _object; }
public void AddObstical(Obstical obstical) { _obsticals.Add(obstical.Position, obstical); }
public void RemoveObstical(Vector2 pos) {
Obstical obstical = _obsticals[pos];
MonoBehaviour.Destroy(obstical.GameObject);
_obsticals.Remove(pos);
}
public override string ToString() => _object.name;
}
}