232 lines
9.4 KiB
C#
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;
|
|
}
|
|
} |