Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by fede4961 · Jul 06, 2021 at 05:04 PM · programmingpositioningprocedural generationchunks

Need help fixing procedural generation bug

I've been trying to fix this bug for a week and I still haven't come across a solution. I'm working on a procedural generation system where I have a couple of GameObjects:

  • A player which controls the camera (with the Player.cs script)

  • A "Chunk handler" which updates all of the chunks in the render distance each frame (with the ChunkHandler.cs script)

The more the player moves, the further away the chunks load, this goes on to the point where the chunks are being generated 200 units away from the actual player's position.

Player.cs

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using UnityEngine;
 
 public class Player : MonoBehaviour {
 
     private float movementSpeed = 10f;
     private float fastMovementSpeed = 100f;
     void Start () {
 
         LockCursor ();
 
     }
 
     // Updates the player position and rotation each frame
     void Update () {
         
         // Determines the movement speed based on whether or not the user is pressing the shift key
         var fastMode = Input.GetKey ( KeyCode.LeftShift ) || Input.GetKey ( KeyCode.RightShift );
         var movementSpeed = fastMode ? this.fastMovementSpeed : this.movementSpeed;
 
         // Left movement
         if ( Input.GetKey ( KeyCode.A ) || Input.GetKey ( KeyCode.LeftArrow ) ) {
             transform.position = transform.position + ( -transform.right * movementSpeed * Time.deltaTime );
         }
 
         // Right movement
         if ( Input.GetKey ( KeyCode.D ) || Input.GetKey ( KeyCode.RightArrow ) ) {
             transform.position = transform.position + ( transform.right * movementSpeed * Time.deltaTime );
         }
 
         // Forward movement
         if ( Input.GetKey ( KeyCode.W ) || Input.GetKey ( KeyCode.UpArrow ) ) {
             transform.position = transform.position + ( transform.forward * movementSpeed * Time.deltaTime );
         }
 
         // Backwards movement
         if ( Input.GetKey ( KeyCode.S ) || Input.GetKey ( KeyCode.DownArrow ) ) {
             transform.position = transform.position + ( -transform.forward * movementSpeed * Time.deltaTime );
         }
 
         // Up movement
         if ( Input.GetKey ( KeyCode.Q ) ) {
             transform.position = transform.position + ( transform.up * movementSpeed * Time.deltaTime );
         }
 
         if ( Input.GetKey ( KeyCode.E ) ) {
             transform.position = transform.position + ( -transform.up * movementSpeed * Time.deltaTime );
         }
 
         if ( Input.GetKey ( KeyCode.R ) || Input.GetKey ( KeyCode.PageUp ) ) {
             transform.position = transform.position + ( Vector3.up * movementSpeed * Time.deltaTime );
         }
 
         if (Input.GetKey ( KeyCode.F ) || Input.GetKey ( KeyCode.PageDown ) ) {
             transform.position = transform.position + ( -Vector3.up * movementSpeed * Time.deltaTime );
         }
         
     }
 
     // Hides the cursor
     public void LockCursor () {
 
         Cursor.visible = false;
         Cursor.lockState = CursorLockMode.Locked;
 
     }
 
     // Makes the cursor position visible on the screen
     public void UnlockCursor () {
 
         Cursor.visible = true;
         Cursor.lockState = CursorLockMode.None;
 
     }
 
     // Returns the current position of the player
     public Vector3 GetPosition () {
         return transform.position;
     }
 
 }

ChunkHandler.cs

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class ChunkHandler : MonoBehaviour {
 
     private int renderDistance;
     private int chunkSize;
 
     public Player player;
 
     private Dictionary<Vector3, Chunk> chunks = new Dictionary<Vector3, Chunk> ();
 
     void Start () {
 
         // Configures the terrain generation settings
         chunkSize = 24;
         renderDistance = 2;
 
         // Gets the player object
         player = GameObject.Find ( "Player" ).GetComponent<Player> ();
 
     }
 
     // Updates the visible chunks each frame
     void Update () {
 
         UpdateChunks ();
 
     }
 
     // Updates the visible chunks
     private void UpdateChunks () {
 
         // Gets the chunk the player is currently in
         Vector3 playerChunk = GetPlayerChunk ();
 
         // Gets the player's position
         Vector3 playerPosition = player.GetPosition ();
 
         // Loops through each possible chunk in the render distance
         for ( int x = -renderDistance; x < renderDistance; x++ ) {
             for ( int z = -renderDistance; z < renderDistance; z++ ) {
 
                 // Calculates the chunk's position relative to the player's current chunk
                 Vector3 chunkPosition = new Vector3 ( playerChunk.x + x * chunkSize / 2, playerChunk.y, playerChunk.z + z * chunkSize / 2 );
 
                 // Checks if the chunk already exists
                 if ( chunks.ContainsKey ( chunkPosition ) ) {
 
                     // Updates the chunk
                     chunks[chunkPosition].UpdateChunk ( renderDistance, chunkSize, playerPosition );
 
                 } else {
 
                     // Creates a new chunk
                     Chunk newChunk = new Chunk ( chunkPosition, chunkSize );
                     newChunk.UpdateChunk ( renderDistance, chunkSize, playerPosition );
                     chunks.Add ( chunkPosition, newChunk );
 
                 }
 
             }
         }
 
     }
 
     // Returns the position of the chunk the player is currently in
     private Vector3 GetPlayerChunk () {
 
         // Loops through each chunk
         foreach ( Chunk chunk in chunks.Values ) {
             // Terribly inefficient i know I'll fix it right after the chunk loading problem
             if ( chunk.IsPlayerInChunk ( player.GetPosition () ) ) {
                 return chunk.GetPosition ();
             }
 
         }
 
         return new Vector3 ( 0, 0, 0 );
 
     }
 
 }
 

Chunk.cs (this script defines the chunk gameobject

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class Chunk {
     
     private Vector3 position;
     private GameObject chunkObject;
     private Bounds chunkBounds;
     private int size;
 
     private MeshFilter chunkFilter;
     private MeshRenderer chunkRenderer;
     private Mesh chunkMesh;
 
     public Chunk ( Vector3 position_, int size_ ) {
 
         position = position_;
         size = size_;
 
         // Creates the new "Chunk" gameobject
         chunkObject = new GameObject ( "Chunk" );
         chunkObject.transform.position = position;
 
         // Gets the mesh components
         chunkFilter = chunkObject.AddComponent<MeshFilter> ();
         chunkRenderer = chunkObject.AddComponent<MeshRenderer> ();
 
         // Generates and displays the chunk's mesh
         chunkMesh = GenerateMesh ();
         DisplayMesh ();
 
         // Creates the chunk bounds
         // Used to tell whether or not the chunk should be rendered
         chunkBounds = new Bounds ( chunkFilter.mesh.bounds.center, new Vector3 ( chunkFilter.mesh.bounds.size.x, 300, chunkFilter.mesh.bounds.size.z ) );
 
         SetVisibility ( false );
 
     }
 
     // Generates the chunk mesh
     private Mesh GenerateMesh () {
 
         MeshData meshData = new MeshData ( size );
 
         // Loops through each vertex
         int vertexIndex = 0;
         for ( int x = 0; x < size; x++ ) {
             for ( int z = 0; z < size; z++ ) {
 
                 // Adds a vertex to the mesh
                 meshData.vertices[vertexIndex] = new Vector3 ( position.x + x, 0, position.z + z );
 
                 // Adds a UV value so that a texture can later be applied
                 meshData.uvs[vertexIndex] = new Vector2 ( x / (float) size, z / (float) size );
                 
                 // Ignores the bottom and right vertices
                 if ( x < size - 1 && z < size - 1 ) {
                     meshData.CreateTriangle ( vertexIndex, vertexIndex + size + 1, vertexIndex + size );
                     meshData.CreateTriangle ( vertexIndex + size + 1, vertexIndex, vertexIndex + 1 );
                 }
 
                 vertexIndex++;
 
             }
         }
         
         return meshData.CreateMesh ();
 
     }
 
     // Updates the mesh normals and bounds
     private void UpdateMesh () {
 
         chunkMesh.RecalculateBounds ();
         chunkMesh.RecalculateNormals ();
 
     }
 
     // Displays the mesh
     private void DisplayMesh () {
 
         // Applies mesh to filter
         chunkFilter.sharedMesh = chunkMesh;
 
         // Generates mesh texture
         Texture2D meshTexture = TextureHandler.TextureFromHeightMap ( size );
 
         // Applies texture to renderer
         Material chunkMaterial = new Material ( Shader.Find ( "Standard" ) );
         chunkMaterial.mainTexture = meshTexture;
         chunkRenderer.material = chunkMaterial;
 
         // Updates the mesh normals to render lighting correctly
         UpdateMesh ();
 
 
     }
 
     // Sets whether or not the chunk should be rendered
     public void SetVisibility ( bool visible ) {
         chunkObject.SetActive (visible);
     } 
 
     // Updates whether or not the chunk will be rendered based on the given render distance
     public void UpdateChunk ( int renderDistance, int chunkSize, Vector3 playerPosition ) {
         float playerDistance = Mathf.Sqrt ( chunkBounds.SqrDistance ( playerPosition ) );
         SetVisibility ( playerDistance <= renderDistance * chunkSize );
 
     }
 
     // Returns whether or not the player is currently in the chunk
     public bool IsPlayerInChunk ( Vector3 playerPosition ) {
         return chunkBounds.Contains ( playerPosition );
     }
 
     // Returns whether or not the chunk will be rendered
     public bool IsVisible () {
         return chunkObject.activeSelf;
     }
 
     // Returns a vector with the chunk's position
     public Vector3 GetPosition () {
         return chunkObject.transform.position;
     }
 
 }
 
 // This class contains all the data to generate the chunk mesh
 public class MeshData {
 
     public Vector3[] vertices;
     public int[] triangles;
     public Vector2[] uvs;
     int triangleIndex;
     public MeshData ( int size ) {
 
         size += 1;
         vertices = new Vector3[size * size];
         triangles = new int[( size - 1 ) * ( size - 1 ) * 6];
         uvs = new Vector2[size * size];
 
     }
 
     // Adds a triangle to the mesh
     public void CreateTriangle ( int x, int y, int z ) {
 
         triangles[triangleIndex] = x;
         triangles[triangleIndex + 1] = y;
         triangles[triangleIndex + 2] = z;
         triangleIndex += 3;
 
     } 
 
     // Returns the current mesh
     public Mesh CreateMesh () {
         
         Mesh mesh = new Mesh ();
         mesh.vertices = vertices;
         mesh.triangles = triangles;
         mesh.uv = uvs;
 
         mesh.RecalculateBounds ();
         mesh.RecalculateNormals ();
 
         return mesh;
 
     }
 
 }

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by andrew-lukasik · Jul 06, 2021 at 10:37 PM

Add these lines in your ChunkHandler and you will immediately see what is wrong:

 #if UNITY_EDITOR
 void OnDrawGizmos ()
 {
     foreach( Chunk chunk in chunks.Values )
     {
         Gizmos.color = Color.HSVToRGB( Mathf.Abs((float)chunk.GetHashCode()%17f)/17f , 1 , 1 );
         Gizmos.DrawLine( chunk.position , chunk.chunkBounds.center );
         Gizmos.DrawWireCube( chunk.chunkBounds.center , chunk.chunkBounds.size );
     }
 }
 #endif

Your GetPlayerChunk() method rely on these bounds:

wrong chunk bounds


screenshot-2021-07-07-003358.jpg (258.3 kB)
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

183 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

Big problem on chunk generation (Unity Tilemaps) 1 Answer

Click and drag box not working 1 Answer

Help me finish my room generator 0 Answers

Can someone help me with procedural voxel terrain generation? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges