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
0
Question by innovstioncollectivellc · Aug 16, 2014 at 05:22 PM · serializationdatabasedata storage

Help saving Voxel Terrain between scenes

Hi I was wondering if anyone could help me figure out a script to save my voxel terrain between scene changes. I've tried using unity serializer but Since theyre generated on the fly It doesn't recognize the chunk clones or their positions. I'm new to unity so any help would be greatly appreciated. here are the scripts I'M working with.

Chunk Script

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 using SimplexNoise;
 
 public enum BrickType {
     None,
     
     RoughStone,
     SmoothStone,
     DarkStone,
     PowderStone,
     Granite,
     Dirt, 
     Sand,
     GreenLattice,
     
     Taint,
     Dust,
     Rust,
     Ice,
     Snow,
     DirtyIce,
     Streaks,
     Lava
 }
 
 [RequireComponent (typeof(MeshRenderer))]
 [RequireComponent (typeof(MeshCollider))]
 [RequireComponent (typeof(MeshFilter))]
 public class Chunk : MonoBehaviour {
     
     public static List<Chunk> chunks = new List<Chunk>();
     public static int width {
         get { return World.currentWorld.chunkWidth; }
     }
     public static int height {
         get { return World.currentWorld.chunkHeight; }
     }
     public static float brickHeight {
         get { return World.currentWorld.brickHeight; }
     }
     
     public byte[,,] map;
     public Mesh visualMesh;
     protected MeshRenderer meshRenderer;
     protected MeshCollider meshCollider;
     protected MeshFilter meshFilter;
 
     // Use this for initialization
     void Start () {
         
         chunks.Add(this);
         
         meshRenderer = GetComponent<MeshRenderer>();
         meshCollider = GetComponent<MeshCollider>();
         meshFilter = GetComponent<MeshFilter>();
         
         
     
         CalculateMapFromScratch();
         StartCoroutine(CreateVisualMesh());
         
     }
     
     // Update is called once per frame
     void Update () {
     
     }
     
     public static byte GetTheoreticalByte(Vector3 pos) {
         Random.seed = World.currentWorld.seed;
         
         Vector3 grain0Offset = new Vector3(Random.value * 10000, Random.value * 10000, Random.value * 10000);
         Vector3 grain1Offset = new Vector3(Random.value * 10000, Random.value * 10000, Random.value * 10000);
         Vector3 grain2Offset = new Vector3(Random.value * 10000, Random.value * 10000, Random.value * 10000);
         
         return GetTheoreticalByte(pos, grain0Offset, grain1Offset, grain2Offset);
         
     }
     
     public static byte GetTheoreticalByte(Vector3 pos, Vector3 offset0, Vector3 offset1, Vector3 offset2)
     {
         float clusterValue = CalculateNoiseValue(pos, offset2,  0.02f);        
         int biomeIndex = Mathf.FloorToInt(clusterValue * World.currentWorld.biomes.Length);
         Biome biome = World.currentWorld.biomes[biomeIndex];
         
         
         float heightBase = biome.minHeight;
         float maxHeight = biome.maxHeight;
         float heightSwing = maxHeight - heightBase;
         
         
         float blobValue = CalculateNoiseValue(pos, offset1,  0.05f);
         float mountainValue = CalculateNoiseValue(pos, offset0,  0.009f);
         
         mountainValue += biome.mountainPowerBonus;
         if (mountainValue < 0) mountainValue = 0;
         
         mountainValue = Mathf.Pow(mountainValue, biome.mountainPower);  //Mathf.Sqrt(mountainValue);
         
         byte brick = biome.GetBrick(Mathf.FloorToInt(pos.y), mountainValue, blobValue);
         
         
         mountainValue *= heightSwing;
         mountainValue += heightBase;
         
         mountainValue += (blobValue * 10) - 5f;
                     
                     
         if (mountainValue >= pos.y)
             return brick;
         return 0;
     }
     
     public virtual void CalculateMapFromScratch() {
         map = new byte[width, height, width];
         
         Random.seed = World.currentWorld.seed;
         Vector3 grain0Offset = new Vector3(Random.value * 10000, Random.value * 10000, Random.value * 10000);
         Vector3 grain1Offset = new Vector3(Random.value * 10000, Random.value * 10000, Random.value * 10000);
         Vector3 grain2Offset = new Vector3(Random.value * 10000, Random.value * 10000, Random.value * 10000);
         
         
         
         for (int x = 0; x < World.currentWorld.chunkWidth; x++)
         {
             for (int y = 0; y < height; y++)
             {
                 for (int z = 0; z < width; z++)
                 {
                     map[x, y, z] = GetTheoreticalByte(new Vector3(x, y, z) + transform.position, grain0Offset, grain1Offset, grain2Offset);
                 
                 }
             }
         }
         
     }
     
     public static float CalculateNoiseValue(Vector3 pos, Vector3 offset, float scale)
     {
         
         float noiseX = Mathf.Abs((pos.x + offset.x) * scale);
         float noiseY = Mathf.Abs((pos.y + offset.y) * scale);
         float noiseZ = Mathf.Abs((pos.z + offset.z) * scale);
         
         return Mathf.Max(0, Noise.Generate(noiseX, noiseY, noiseZ));
 
         
     }
     
     
     public virtual IEnumerator CreateVisualMesh() {
         visualMesh = new Mesh();
         
         List<Vector3> verts = new List<Vector3>();
         List<Vector2> uvs = new List<Vector2>();
         List<int> tris = new List<int>();
         
         
         for (int x = 0; x < width; x++)
         {
             for (int y = 0; y < height; y++)
             {
                 for (int z = 0; z < width; z++)
                 {
                     if (map[x,y,z] == 0) continue;
                     
                     byte brick = map[x,y,z];
                     // Left wall
                     if (IsTransparent(x - 1, y, z))
                         BuildFace (brick, new Vector3(x, y, z), Vector3.up, Vector3.forward, false, verts, uvs, tris);
                     // Right wall
                     if (IsTransparent(x + 1, y , z))
                         BuildFace (brick, new Vector3(x + 1, y, z), Vector3.up, Vector3.forward, true, verts, uvs, tris);
                     
                     // Bottom wall
                     if (IsTransparent(x, y - 1 , z))
                         BuildFace (brick, new Vector3(x, y, z), Vector3.forward, Vector3.right, false, verts, uvs, tris);
                     // Top wall
                     if (IsTransparent(x, y + 1, z))
                         BuildFace (brick, new Vector3(x, y + 1, z), Vector3.forward, Vector3.right, true, verts, uvs, tris);
                     
                     // Back
                     if (IsTransparent(x, y, z - 1))
                         BuildFace (brick, new Vector3(x, y, z), Vector3.up, Vector3.right, true, verts, uvs, tris);
                     // Front
                     if (IsTransparent(x, y, z + 1))
                         BuildFace (brick, new Vector3(x, y, z + 1), Vector3.up, Vector3.right, false, verts, uvs, tris);
                     
                     
                 }
             }
         }
                     
         visualMesh.vertices = verts.ToArray();
         visualMesh.uv = uvs.ToArray();
         visualMesh.triangles = tris.ToArray();
         visualMesh.RecalculateBounds();
         visualMesh.RecalculateNormals();
         
         meshFilter.mesh = visualMesh;
         
         
         meshCollider.sharedMesh = null;
         meshCollider.sharedMesh = visualMesh;
         
         yield return 0;
         
     }
     public virtual void BuildFace(byte brick, Vector3 corner, Vector3 up, Vector3 right, bool reversed, List<Vector3> verts, List<Vector2> uvs, List<int> tris)
     {
         int index = verts.Count;
         
         
         float uvRow = ((corner.y + up.y) % 7);
         if (uvRow >= 4) uvRow = 7 - uvRow;
         uvRow /= 4f;
         Vector2 uvCorner = new Vector2(0.00f, uvRow);
         
         if (brick < 8)
             uvCorner.y += 0.125f;
         
         
         
         corner.y *= brickHeight;
         up.y *= brickHeight;
         right.y *= brickHeight;
         
         
         verts.Add (corner);
         verts.Add (corner + up);
         verts.Add (corner + up + right);
         verts.Add (corner + right);
         
         Vector2 uvWidth = new Vector2(0.125f, 0.125f);
         
         uvCorner.x += (float)((brick - 1) % 8) / 8f;
         
         uvs.Add(uvCorner);
         uvs.Add(new Vector2(uvCorner.x, uvCorner.y + uvWidth.y));
         uvs.Add(new Vector2(uvCorner.x + uvWidth.x, uvCorner.y + uvWidth.y));
         uvs.Add(new Vector2(uvCorner.x + uvWidth.x, uvCorner.y));
         
         if (reversed)
         {
             tris.Add(index + 0);
             tris.Add(index + 1);
             tris.Add(index + 2);
             tris.Add(index + 2);
             tris.Add(index + 3);
             tris.Add(index + 0);
         }
         else
         {
             tris.Add(index + 1);
             tris.Add(index + 0);
             tris.Add(index + 2);
             tris.Add(index + 3);
             tris.Add(index + 2);
             tris.Add(index + 0);
         }
         
     }
     public virtual bool IsTransparent (int x, int y, int z)
     {
         if ( y < 0) return false;
         byte brick = GetByte(x,y,z);
         switch (brick)
         {
         case 0: 
             return true;
         default:
             return false;
         }
     }
     public virtual byte GetByte (int x, int y , int z)
     {
         
         if ((y < 0) || (y >= height))
             return 0;
         
         if ( (x < 0) || (z < 0)  || (x >= width) || (z >= width))
         {
             
             Vector3 worldPos = new Vector3(x, y, z) + transform.position;
             Chunk chunk = Chunk.FindChunk(worldPos);
             if (chunk == this) return 0;
             if (chunk == null) 
             {
                 return GetTheoreticalByte(worldPos);
             }
             return chunk.GetByte (worldPos);
         }
         return map[x,y,z];
     }
     public virtual byte GetByte(Vector3 worldPos) {
         worldPos -= transform.position;
         int x = Mathf.FloorToInt(worldPos.x);
         int y = Mathf.FloorToInt(worldPos.y);
         int z = Mathf.FloorToInt(worldPos.z);
         return GetByte (x, y, z);
     }
     
     public static Chunk FindChunk(Vector3 pos) {
         
         for (int a = 0; a < chunks.Count; a++)
         {
             Vector3 cpos = chunks[a].transform.position;
             
             if ( ( pos.x < cpos.x) || (pos.z < cpos.z) || (pos.x >= cpos.x + width) || (pos.z >= cpos.z + width) ) continue;
             return chunks[a];
             
         }
         return null;
         
     }
     
     public bool SetBrick (byte brick, Vector3 worldPos)
     {
         worldPos -= transform.position;
         return SetBrick(brick, Mathf.FloorToInt(worldPos.x),Mathf.FloorToInt(worldPos.y),Mathf.FloorToInt(worldPos.z));
     }
     public bool SetBrick (byte brick, int x, int y, int z)
     {
         if ( ( x < 0) || (y < 0) || (z < 0) || (x >= width) || (y >= height) || (z >= width) )
         {
             return false;
         }
         
         if (map[x,y,z] == brick) return false;
         map[x,y,z] = brick;
         StartCoroutine(CreateVisualMesh());        
         
         if (x == 0)
         {
             Chunk chunk = FindChunk( new Vector3(x - 2, y, z) + transform.position);
             if (chunk != null)
                 StartCoroutine(chunk.CreateVisualMesh());        
         }
         if (x == width - 1)
         {
             Chunk chunk = FindChunk( new Vector3(x + 2, y, z) + transform.position);
             if (chunk != null)
                 StartCoroutine(chunk.CreateVisualMesh());        
         }
         if (z == 0)
         {
             Chunk chunk = FindChunk( new Vector3(x, y, z - 2) + transform.position);
             if (chunk != null)
                 StartCoroutine(chunk.CreateVisualMesh());        
         }
         if (z == width - 1)
         {
             Chunk chunk = FindChunk( new Vector3(x, y, z + 2) + transform.position);
             if (chunk != null)
                 StartCoroutine(chunk.CreateVisualMesh());        
         }
         
         return true;
     }
 }


world script

using UnityEngine; using System.Collections;

public class World : MonoBehaviour {

 public Biome[] biomes;
 
 public static World currentWorld;
 public int chunkWidth = 20, chunkHeight = 20, seed = 0;
 public float viewRange = 30;
 
 public float brickHeight = 1;
 
 public Chunk chunkFab;
 
 // Use this for initialization
 void Awake () {
     currentWorld = this;
     if (seed == 0)
         seed = Random.Range(0, int.MaxValue);
 }
 
 // Update is called once per frame
 void Update () {
     
     
     for (float x = transform.position.x - viewRange; x < transform.position.x + viewRange; x+= chunkWidth)
     {
         for (float z = transform.position.z - viewRange; z < transform.position.z + viewRange; z+= chunkWidth)
         {
             
             Vector3 pos = new Vector3(x, 0, z);
             pos.x = Mathf.Floor(pos.x / (float)chunkWidth) * chunkWidth;
             pos.z = Mathf.Floor(pos.z / (float)chunkWidth) * chunkWidth;
             
             Chunk chunk = Chunk.FindChunk(pos);
             if (chunk != null) continue;
             
             chunk = (Chunk)Instantiate(chunkFab, pos, Quaternion.identity);
             
             
             
         }
     }
 
 }

}

Thank you in advance in a noobie.

Comment
Add comment · Show 1
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
avatar image christoph_r · Aug 16, 2014 at 05:38 PM 0
Share

Wow, well, that's a lot of code. But if all you need is persistence across scenes ins$$anonymous$$d of full save/load functionality, wouldn't DontDestroyOnLoad work?

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by PaulOrac · Aug 16, 2014 at 05:48 PM

I added this answer some minutes ago but It didn't show I'll do it again...

http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html

I hope this helps you my friend, this will keep your GameObject alive between the scenes but it won't be saved if you quit the application

Comment
Add comment · Show 3 · 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
avatar image robertbu · Aug 16, 2014 at 05:50 PM 0
Share

@PaulOrac - until you have 15 $$anonymous$$arma points, all your questions go through moderation. It can be $$anonymous$$utes or hours depending what moderators are online before a question from the moderation queue is published, so reposting questions just makes work for the moderators.

avatar image PaulOrac · Aug 16, 2014 at 05:55 PM 0
Share

oh Sorry about that robertbu, I got worried as I didn't even see the answer in my dashboard. Thankyou!!

avatar image innovstioncollectivellc · Aug 16, 2014 at 10:55 PM 0
Share

THAN$$anonymous$$ YOU!!!!!!!!!! I feel dumb lol but it worked!!

avatar image
0

Answer by Cherno · Aug 17, 2014 at 01:37 AM

If you want to saveto file, you can use Unity Serializer or your own Serializer to just save the information from your 3-dimension array and then load it when loading the saved file again, and then rebuilding your chunks/meshes.

Be aware that you can not save multi-dimensional arrays though, so you have to put the block info into one long array and when loading, use the xyz size values to put that long array back into 3-dimensional form.

 int x = 0;
 int y = 0;
 int z = 0;
 for(int i = 0; i < yourFlattenedArray; i ++) {
 
      yourWorld[x,y,z].fillData = loadedGame.fillDataList[i];
 
      z++;
 
      if (z == zSize) {
           z = 0;
           if(y < ySize - 1) {
                y++;
           }
           else {
                x++;
                y = 0;
           }
      }
 }
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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

Serialize loads of different data 0 Answers

Scriptable Object's Data Gets Lost After Re-opening Unity!!! 1 Answer

Fatal Error: Database or Disk is Full. 0 Answers

How to get update from database? 1 Answer


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