Advertisement
AriesOnThat

Chunk.cs

Sep 4th, 2024
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.92 KB | Source Code | 0 0
  1. using Godot;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq.Expressions;
  5. using System.Threading;
  6.  
  7. [Tool]
  8. public partial class Chunk : StaticBody3D
  9. {
  10.     [Export]
  11.     public CollisionShape3D CollisionShape { get; set;}
  12.  
  13.     [Export]
  14.     public MeshInstance3D MeshInstance { get; set; }
  15.  
  16.     public static Vector3I dimensions = new Vector3I(16, 64, 16);
  17.  
  18.     private object dimensionsLock = new();
  19.  
  20.     private static readonly Vector3I[] _vertices = new Vector3I[]
  21.     {
  22.         new Vector3I(0, 0, 0),
  23.         new Vector3I(1, 0, 0),
  24.         new Vector3I(0, 1, 0),
  25.         new Vector3I(1, 1, 0),
  26.         new Vector3I(0, 0, 1),
  27.         new Vector3I(1, 0, 1),
  28.         new Vector3I(0, 1, 1),
  29.         new Vector3I(1, 1, 1)
  30.     };
  31.  
  32.     private static readonly int[] _top = new int[] { 2, 3, 7, 6 };
  33.     private static readonly int[] _bottom = new int[] { 0, 4, 5, 1 };
  34.     private static readonly int[] _left = new int[] { 6, 4, 0, 2 };
  35.     private static readonly int[] _right = new int[] { 3, 1, 5, 7 };
  36.     private static readonly int[] _back = new int[] { 7, 5, 4, 6 };
  37.     private static readonly int[] _front = new int[] { 2, 0, 1, 3 };
  38.  
  39.     private SurfaceTool _surfaceTool = new();
  40.  
  41.     private Block[,,] _blocks = new Block[dimensions.X, dimensions.Y, dimensions.Z];
  42.  
  43.     public Vector2I ChunkPosition { get; private set; }
  44.  
  45.     private Chunk[] neighbors = new Chunk[4];
  46.  
  47.     [Export]
  48.     public FastNoiseLite Noise { get; set; }
  49.  
  50.     public void SetChunkPosition(Vector2I position)
  51.     {
  52.         ChunkManager.Instance.UpdateChunkPosition(this, position, ChunkPosition);
  53.         ChunkPosition = position;
  54.         CallDeferred(Node3D.MethodName.SetGlobalPosition, new Vector3(ChunkPosition.X * dimensions.X, 0, ChunkPosition.Y * dimensions.Z));
  55.         DetermineNeighbors(ChunkManager.Instance.GetChunkMap());
  56.  
  57.         ///new Thread(new ThreadStart(Generate)).Start();
  58.         //new Thread(new ThreadStart(Update)).Start();
  59.         Generate();
  60.         Update();
  61.     }
  62.  
  63.     public void Generate()
  64.     {
  65.         lock (dimensionsLock)
  66.         {
  67.             for (int x = 0; x < dimensions.X; x++)
  68.             {
  69.                 for (int y = 0; y < dimensions.Y; y++)
  70.                 {
  71.                     for (int z = 0; z < dimensions.Z; z++)
  72.                     {
  73.                         Block block;
  74.  
  75.                         var globalBlockPosition = ChunkPosition *  new Vector2I(dimensions.X, dimensions.Z) + new Vector2(x, z);
  76.                         var groundHeight = (int)(dimensions.Y * ((Noise.GetNoise2D(globalBlockPosition.X, globalBlockPosition.Y) + 1f) / 2f));
  77.  
  78.                         if (y < groundHeight / 2)
  79.                         {
  80.                             block = BlockManager.Instance.Stone;
  81.                         }
  82.                         else if (y < groundHeight)
  83.                         {
  84.                             block = BlockManager.Instance.Dirt;
  85.                         }
  86.                         else if (y == groundHeight)
  87.                         {
  88.                             block = BlockManager.Instance.Grass;
  89.                         }
  90.                         else
  91.                         {
  92.                             block = BlockManager.Instance.Air;
  93.                         }
  94.  
  95.                         _blocks[x, y, z] = block;
  96.                     }
  97.                 }
  98.             }
  99.             //Thread.Sleep(100);
  100.         }
  101.        
  102.     }
  103.  
  104.     public void Update()
  105.     {
  106.         lock (dimensionsLock)
  107.         {
  108.             _surfaceTool.Begin(Mesh.PrimitiveType.Triangles);
  109.  
  110.             for (int x = 0; x < dimensions.X; x++)
  111.             {
  112.                 for (int y = 0; y < dimensions.Y; y++)
  113.                 {
  114.                     for (int z = 0; z < dimensions.Z; z++)
  115.                     {
  116.                         CreateBlockMesh(new Vector3I(x, y, z));
  117.                     }
  118.                 }
  119.             }
  120.             //Thread.Sleep(100);
  121.         }
  122.        
  123.  
  124.         _surfaceTool.SetMaterial(BlockManager.Instance.ChunkMaterial);
  125.         var mesh = _surfaceTool.Commit();
  126.  
  127.         MeshInstance.Mesh = mesh;
  128.         CollisionShape.Shape = mesh.CreateTrimeshShape();
  129.     }
  130.  
  131.     public void SetNeighbor(int direction, Chunk neighbor)
  132.     {
  133.         neighbors[direction] = neighbor;
  134.     }
  135.  
  136.     public void DetermineNeighbors(Dictionary<Vector2I, Chunk> chunkMap)
  137.     {
  138.         // Define directions with a Vector2I
  139.         Vector2I[] directions = {
  140.             new Vector2I(-1, 0), //Left
  141.             new Vector2I(1, 0), //Right
  142.             new Vector2I(0, 1), //Up
  143.             new Vector2I(0, -1) //Down
  144.         };
  145.  
  146.         for (int i = 0; i < directions.Length; i++)
  147.         {
  148.             Vector2I neighborPos = ChunkPosition + directions[i];
  149.             if (chunkMap.TryGetValue(neighborPos, out Chunk neighbor))
  150.             {
  151.                 SetNeighbor(i, neighbor);
  152.             }
  153.             else
  154.             {
  155.                 neighbors[i] = null;
  156.             }
  157.         }
  158.     }
  159.  
  160.  
  161.     private void CreateBlockMesh(Vector3I blockPosition)
  162.     {
  163.         var block = _blocks[blockPosition.X, blockPosition.Y, blockPosition.Z];
  164.  
  165.         if (block == BlockManager.Instance.Air) return;
  166.  
  167.         if (CheckTransparent(blockPosition + Vector3I.Up))
  168.         {
  169.             CreateFaceMesh(_top, blockPosition, block.TopTexture ?? block.Texture);
  170.         }
  171.         if (CheckTransparent(blockPosition + Vector3I.Down))
  172.         {
  173.             CreateFaceMesh(_bottom, blockPosition, block.BottomTexture ?? block.Texture);
  174.         }
  175.         if (CheckTransparent(blockPosition + Vector3I.Left))
  176.         {
  177.             CreateFaceMesh(_left, blockPosition, block.Texture);
  178.         }
  179.         if (CheckTransparent(blockPosition + Vector3I.Right))
  180.         {
  181.             CreateFaceMesh(_right, blockPosition, block.Texture);
  182.         }
  183.         if (CheckTransparent(blockPosition + Vector3I.Forward))
  184.         {
  185.             CreateFaceMesh(_front, blockPosition, block.Texture);
  186.         }
  187.         if (CheckTransparent(blockPosition + Vector3I.Back))
  188.         {
  189.             CreateFaceMesh(_back, blockPosition, block.Texture);
  190.         }
  191.  
  192.         CheckNeighborChunks(blockPosition);
  193.     }
  194.  
  195.     private void CheckNeighborChunks(Vector3I blockPosition)
  196.     {
  197.         if (blockPosition.X == 0 && neighbors[0] != null)
  198.         {
  199.             if (neighbors[0].CheckTransparent(new Vector3I(dimensions.X -1, blockPosition.Y, blockPosition.Z)))
  200.             {
  201.                 CreateFaceMesh(_left, blockPosition, _blocks[blockPosition.X, blockPosition.Y, blockPosition.Z].Texture);
  202.             }
  203.         }
  204.  
  205.         if (blockPosition.X == dimensions.X - 1 && neighbors[1] != null)
  206.         {
  207.             if (neighbors[1].CheckTransparent(new Vector3I(0, blockPosition.Y, blockPosition.Z)))
  208.             {
  209.                 CreateFaceMesh(_right, blockPosition, _blocks[blockPosition.X, blockPosition.Y, blockPosition.Z].Texture);
  210.             }
  211.         }
  212.  
  213.         if (blockPosition.Z == 0 && neighbors[3] != null)
  214.         {
  215.             if (neighbors[3].CheckTransparent(new Vector3I(blockPosition.X, blockPosition.Y, dimensions.Z - 1)))
  216.             {
  217.                 CreateFaceMesh(_back, blockPosition, _blocks[blockPosition.X, blockPosition.Y, blockPosition.Z].Texture);
  218.             }
  219.         }
  220.  
  221.         if (blockPosition.Z == dimensions.Z - 1 && neighbors[2] != null)
  222.         {
  223.             if (neighbors[2].CheckTransparent(new Vector3I(blockPosition.X, blockPosition.Y, 0)))
  224.             {
  225.                 CreateFaceMesh(_front, blockPosition, _blocks[blockPosition.X, blockPosition.Y, blockPosition.Z].Texture);
  226.             }
  227.         }
  228.     }
  229.  
  230.     private void CreateFaceMesh(int[] face, Vector3I blockPosition, Texture2D texture)
  231.     {
  232.         var texturePosition = BlockManager.Instance.GetTextureAtlasPosition(texture);
  233.         var textureAtlasSize = BlockManager.Instance.TextureAtlasSize;
  234.  
  235.         var uvOffset = texturePosition / textureAtlasSize;
  236.         var uvWidth = 1f / textureAtlasSize.X;
  237.         var uvHeight = 1f/ textureAtlasSize.Y;
  238.  
  239.         var uvA = uvOffset + new Vector2(0, 0);
  240.         var uvB = uvOffset + new Vector2(0, uvHeight);
  241.         var uvC = uvOffset + new Vector2(uvWidth, uvHeight);
  242.         var uvD = uvOffset + new Vector2(uvWidth, 0);
  243.  
  244.  
  245.         var a = _vertices[face[0]] + blockPosition;
  246.         var b = _vertices[face[1]] + blockPosition;
  247.         var c = _vertices[face[2]] + blockPosition;
  248.         var d = _vertices[face[3]] + blockPosition;
  249.  
  250.         var uvTriangle1 = new Vector2[] { uvA, uvB, uvC };
  251.         var uvTriangle2 = new Vector2[] { uvA, uvC, uvD};
  252.  
  253.         var triangle1 = new Vector3[] { a, b, c };
  254.         var triangle2 = new Vector3[] { a, c, d };
  255.  
  256.         var normal = ((Vector3)(c - a)).Cross(((Vector3)(b - a))).Normalized();
  257.         var normals = new Vector3[] { normal, normal, normal };
  258.  
  259.         _surfaceTool.AddTriangleFan(triangle1, uvTriangle1, normals: normals);
  260.         _surfaceTool.AddTriangleFan(triangle2, uvTriangle2, normals: normals);
  261.     }
  262.  
  263.     private bool CheckTransparent(Vector3I blockPosition)
  264.     {
  265.         if (blockPosition.X < 0 || blockPosition.X >= dimensions.X) return true;
  266.         if (blockPosition.Y < 0 || blockPosition.Y >= dimensions.Y) return true;
  267.         if (blockPosition.Z < 0 || blockPosition.Z >= dimensions.Z) return true;
  268.  
  269.         return _blocks[blockPosition.X, blockPosition.Y, blockPosition.Z] == BlockManager.Instance.Air;
  270.     }
  271.  
  272.     public void SetBlock(Vector3I blockPosition, Block block)
  273.     {
  274.         _blocks[blockPosition.X,blockPosition.Y,blockPosition.Z] = block;
  275.         Update();
  276.     }
  277. }
Tags: C# Godot
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement