Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 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
8
Question by SoloChristian · May 13, 2010 at 12:35 AM · terraindynamicinfinitescript-ready-to-use

Dynamic Terrain Loading

I have a lot of Questions about Infinite Terrains and Terrain.SetNeighbors().

Here is a list of the questions:

1 If you use Terrain.SetNeighbors() do all the Neighboring Terrains have to be creared at the same resolution?

2 If I'm storing the extra Terrains as Assets Or separate scene files to Additve load, will the Terrain.SetNeighbors() function throw out a bunch of errors because the extra terrains are not in the Current scene?

3 Should the terrains be made into Prefabs?

4 Is there any major Benifit or drawback to making them prefabs?

5 Is there currently any way to Paint multiple terrains in Unity at the same time?

6 Is there already a system like UniLOD for terrains?

7 Is there any Hands on tutorials for infinite worlds?


What I imagine An Infinite Terrain system to be :

Like the old arcade games in the 80's if the player travled to far to the left of world/screen his location would be moved to the far right of the screen. And the same with the top or bottom.

Then the terrain would be a grid such as a chess board where the ring of terrains around the player would always be loaded.

Terrains could check "distance from player" and unload/destoy themselves when no longer needed.

Not sure how efficient this system would be with all the loading and unloading.

So I'm wondering if this is the right direction to go or if someone has already made a better system.

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

7 Replies

· Add your reply
  • Sort: 
avatar image
7

Answer by jonas-echterhoff · May 13, 2010 at 05:34 PM

Check out this example. It will dynamically load und unload neighboring terrains as the player moves around the world, and should answer most of your questions.

Comment
Add comment · Show 2 · 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 SoloChristian · May 14, 2010 at 09:25 AM 0
Share

I tried to play this on my browser and the Unity player says made with Beta can only play on your machine.

I haven't updated yet to get the Beta. So I tried to rebuild on my version of Unity but got this error:

Assets/Plugins/ZoneLoader.cs(130,17): error CS0246: The type or namespace name `AsynchronousOperation' could not be found. Are you missing a using directive or an assembly reference?

I will go through your code though to see what I can learn from it Thanks. :)

avatar image SoloChristian · May 14, 2010 at 10:59 AM 0
Share

Got it going :) It's fast and tells me a lot. Thank You

avatar image
1

Answer by SoloChristian · Oct 12, 2010 at 07:18 PM

using UnityEngine; using System.Collections; using System;

using Object = UnityEngine.Object;

public class ZoneLoader : MonoBehaviour { const float m_LoadDistance = 1500.0F; const float m_UnloadDistance = 2500.0F;

 //EDDIE CHANGE TO FIT NEW TERRAIN SIZE
 public const float m_GridSize = 8046.0F;
 public const int m_ZoneCount = 12;

 static public ZoneLoader    ms_Singleton;

 static ZoneLoader singleton
 {
 get
 {   
     // @TODO: use FindObjectsOfType to implement improved hotloading of scripts
     if (ms_Singleton == null)   
     {
         GameObject go = new GameObject ("ZoneLoader", typeof(ZoneLoader));
         ms_Singleton = go.GetComponent(typeof(ZoneLoader)) as ZoneLoader;
     }
     return ms_Singleton;
 }
 }

 bool          m_IsLoading = false;
 bool          m_IsUnloading = false;
 bool          m_UseWWW = true;
 bool          m_UseWWWCaching = false;
 int           m_CacheVersion = 1;

 Vector3       m_PlayerPosition;
 Transform     m_PlayerTransform;

 static int    m_ZonesUnloadedSinceLastAssetUnload = 0;

 [System.Serializable]
 public class Zone
 {
     public bool m_Loaded = false;
     public bool m_IsLoadable = true;
     public GameObject m_Root;
     public Terrain m_Terrain;

     public AssetBundle  m_ZoneBundle;
     public WWW  m_ZoneDownload;
 }

 static string GetBaseUrl ()
 {
     if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.WindowsEditor)
         return "file:// + " + Application.dataPath + "/../builds/AssetBundles/";
     if (Application.platform == RuntimePlatform.OSXPlayer)
         return "file:// + " + Application.dataPath + "/../../AssetBundles/";
     else
         return "AssetBundles/";
 }


 Zone[] m_Zones = new Zone[m_ZoneCount * m_ZoneCount];


 static public string GetPrefix (string prefix, string postfix, int x, int y)
 {
     return string.Format("{0}{1}-{2}{3}", prefix, x, y, postfix);
 }

 static public string GetPrefix (int x, int y)
 {
     return GetPrefix("Map_", "", x, y); 
 }

 IEnumerator LoadZone (int x, int y)
 {
     ////@TODO: if (!Application.CanStreamedLevelBeLoaded (GetPrefix(x, y)))

     if (m_IsLoading)
     {
         Debug.LogError("Already loading zone");
         yield break;
     }

     Zone zone = m_Zones[m_ZoneCount*y + x];

     // Zone cant be loaded
     if (!zone.m_IsLoadable)
         yield break;

     m_IsLoading = true;

     string levelName = GetPrefix(x, y);

     if (m_UseWWWCaching || m_UseWWW)
     {
         string fullUrl = GetBaseUrl() + levelName + ".unity3d";
         if (m_UseWWWCaching)
             zone.m_ZoneDownload = WWW.LoadFromCacheOrDownload (fullUrl, m_CacheVersion);
         else
             zone.m_ZoneDownload = new WWW (fullUrl);
         yield return zone.m_ZoneDownload;

         // Make sure there were no errors in the download
         if (zone.m_ZoneDownload.error != null)
         {
             Debug.LogError(zone.m_ZoneDownload.error);
             zone.m_IsLoadable = false;
             m_IsLoading = false;
             zone.m_ZoneDownload.Dispose();
             zone.m_ZoneDownload = null;
             yield break;
         }

         // Load the scene so it becomes accessable from Application.LoadLevel
         zone.m_ZoneBundle = zone.m_ZoneDownload.assetBundle;
         zone.m_ZoneDownload.Dispose();
         zone.m_ZoneDownload = null;
         if (zone.m_ZoneBundle == null)
         {
             zone.m_IsLoadable = false;
             m_IsLoading = false;
             yield break;
         }
     }

     // Load Level
     AsyncOperation async = Application.LoadLevelAdditiveAsync(levelName);
     yield return async;

     // Necessary to prevent overwriting of another load level additive following immediately
     // yield return 0;

     // Find the root game object containing the level data
     zone.m_Root = GameObject.Find("/" + levelName);
     if (zone.m_Root != null)
     {
         Transform terain = zone.m_Root.transform.Find("Terrain");
         if (terain)
             zone.m_Terrain = terain.GetComponent(typeof(Terrain)) as Terrain;

         zone.m_Loaded = true;
     }
     else
     {
         Debug.LogError(levelName + " could not be found after loading level");  
     }

     // Hookup neighboring terrains so there are no seams in the LOD
     for (int yi=Mathf.Max(y-1, 0);yi<Mathf.Min(y+2, m_ZoneCount);yi++)
     {
         for (int xi=Mathf.Max(x-1, 0);xi<Mathf.Min(x+2, m_ZoneCount);xi++)
         {
             Terrain curTerrain = GetLoadedTerrain(xi, yi);
             if (curTerrain != null)
             {
                 Terrain left = GetLoadedTerrain(xi-1, yi);
                 Terrain right = GetLoadedTerrain(xi+1, yi);
                 Terrain top = GetLoadedTerrain(xi, yi+1);
                 Terrain bottom = GetLoadedTerrain(xi, yi-1);
                 curTerrain.SetNeighbors (left, top, right, bottom);
             }
         }
     }

     m_IsLoading = false;
 }

 IEnumerator UnloadZone (int x, int y)
 {
     m_IsUnloading = true;

     Zone zone = m_Zones[m_ZoneCount*y + x];
     zone.m_Loaded = false;

     if (zone.m_Root)
         Destroy(zone.m_Root);
     else
         Debug.LogError("Root for zone has already been unloaded:" + GetPrefix(x, y));

     zone.m_Terrain = null;
     zone.m_Root = null;

     yield return 0;

     if (m_UseWWWCaching || m_UseWWW)
     {
         zone.m_ZoneBundle.Unload(true);
         zone.m_ZoneBundle = null;
     }

     m_ZonesUnloadedSinceLastAssetUnload++;

     m_IsUnloading = false;
 }

 /// Unload assets at some points
 /// AsynchronousOperation op = Resources.GarbageCollectAssets(-1); 

 void OnEnable ()
 {
     ms_Singleton = this;    
 }

 void Awake ()
 {
     ms_Singleton = this;
     m_Zones = new Zone[m_ZoneCount * m_ZoneCount];
     for (int i=0;i<m_Zones.Length;i++)
     {
         m_Zones[i] = new Zone();
     }

     if (m_UseWWWCaching)
     {
         ///////@TODO: REMOVE THIS
         Caching.Authorize ("test", "", 1024*1024*1000, "");
         Caching.CleanCache();
     }

     // Precompute which dongs are loadable
     /*
     for (int y=0;y<m_DongCount;y++)
     {
         for (int x=0;x<m_DongCount;x++)
         {
             Dong dong = m_Dongs[m_DongCount*y + x];
             dong.m_IsLoadable = CachingManifest.singleton.HasDongInZoneType(x, y, ms_ZoneType);
         }
     }
     */

     ms_Singleton = this;
 }

 float GetSqrDistance (Vector3 position, int x, int y)
 {
     float minx = x * m_GridSize;
     float maxx = (x+1) * m_GridSize;
     float miny = y * m_GridSize;
     float maxy = (y+1) * m_GridSize;

     float xDistance = 0.0F;
     float yDistance = 0.0F;

     if (position.x < minx)
         xDistance = Mathf.Abs(minx - position.x);
     else if  (position.x > maxx)
         xDistance = Mathf.Abs(maxx - position.x);

     if (position.z < miny)
         yDistance = Mathf.Abs(miny - position.z);
     else if (position.z > maxy)
         yDistance = Mathf.Abs(maxy - position.z);

     return xDistance * xDistance + yDistance * yDistance;       
 }

 public static void SetPosition (Vector3 position)
 {
     singleton.m_PlayerPosition = position;
 }

 public static void SetPlayerTransform (Transform player)
 {
     singleton.m_PlayerTransform = player;
 }

 void GetClosestZone (Vector3 position, float closestDistance, out int closestX, out int closestY)
 {
     closestX = -1;
     closestY = -1;
     closestDistance = closestDistance * closestDistance;
     for (int y=0;y<m_ZoneCount;y++)
     {
         for (int x=0;x<m_ZoneCount;x++)
         {
             Zone zone = m_Zones[m_ZoneCount*y + x];
             if (!zone.m_Loaded && zone.m_IsLoadable)
             {
                 float sqrDistance = GetSqrDistance(position, x, y);
                 if (sqrDistance < closestDistance)
                 {
                     closestDistance = sqrDistance;
                     closestX = x;
                     closestY = y;
                 }
             }
         }
     }
 }


 void Update ()
 {
     if (m_PlayerTransform)
         m_PlayerPosition = m_PlayerTransform.position;

     if (m_IsLoading || m_IsUnloading)
         return;

     // Unload any zone that is far enough away
     for (int y=0;y<m_ZoneCount;y++)
     {
         for (int x=0;x<m_ZoneCount;x++)
         {
             Zone zone = m_Zones[m_ZoneCount*y + x];
             if (zone.m_Loaded)
             {
                 float sqrDistance = GetSqrDistance(m_PlayerPosition, x, y);
                 if (sqrDistance > m_UnloadDistance * m_UnloadDistance)
                 {
                     StartCoroutine(UnloadZone(x, y));
                     return;
                 }
             }
         }
     }

     // Try loading the closest zone
     int closestX, closestY;
     GetClosestZone(m_PlayerPosition, m_LoadDistance, out closestX, out closestY);

     if (closestX != -1)
         StartCoroutine(LoadZone (closestX, closestY));
 }

 Terrain GetLoadedTerrain (int x, int y)
 {
     if ((x >= 0 && x < m_ZoneCount) && (y >= 0 && y < m_ZoneCount))
     {
         Zone zone = m_Zones[m_ZoneCount*y + x];
         if (zone.m_Loaded)
             return zone.m_Terrain;
     }

     return null;
 }

}

Comment
Add comment · Show 2 · 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 SoloChristian · Oct 12, 2010 at 07:19 PM 0
Share

I forget what I changed to get it working but here is my copy of it.

avatar image JJAPrograms · Feb 19, 2011 at 01:57 PM 0
Share

Thanks, this worked a treat! :D

avatar image
0

Answer by Toni · Oct 13, 2010 at 01:11 PM

Hi Christian,

thanks for the quick answer, but using your file I got new errors...

Assets/Editor/GenerateScenes.cs(53,52): error CS0103: The name `TerrainLighting' does not exist in the current context

and

Assets/Editor/GenerateScenes.cs(53,41): error CS1061: Type UnityEngine.Terrain' does not contain a definition forlighting' and no extension method lighting' of typeUnityEngine.Terrain' could be found (are you missing a using directive or an assembly reference?)

I'm totally lost here...

Thanks in advance,

Toni

Comment
Add comment · Show 2 · 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 Yanger_xy · Jun 13, 2011 at 04:59 AM 0
Share

I also come across this problem, losting...

avatar image The-W.A.T.Z.R · Aug 04, 2014 at 07:39 PM 0
Share

same here

avatar image
0

Answer by ViperCode_ · Apr 16, 2011 at 07:25 PM

Christian, it appears that you have just commented out the line dealing with the "AsynchronousOperation"

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
avatar image
0

Answer by fzzzt · Dec 18, 2011 at 07:21 PM

I wanted to see this demo in Unity 3 so I figured it out. There are two/three compilation errors:

In GenerateScenes.cs, comment out lines 52 and 53:

 //Terrain terrain = terrainGO.GetComponent(typeof(Terrain)) as Terrain;
 //terrain.lighting = TerrainLighting.Lightmap;

In ZoneLoader.cs, change line 130 from:

 AsynchronousOperation async = Application.LoadLevelAdditiveAsynchronous[...]

To:

 AsyncOperation async = Application.LoadLevelAdditiveAsync(levelName);

This works in the free version of Unity also, though it throws errors at runtime due to the lack of LoadLevelAdditiveAsync (and falls back to LoadLevelAdditive I think).

Comment
Add comment · Show 1 · 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 The-W.A.T.Z.R · Aug 04, 2014 at 07:47 PM 0
Share

it dosent work 4 me

  • 1
  • 2
  • ›

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

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

Create a line between two points in 2d - a vehicle will be driving on the lines created 1 Answer

What size terrain for dynamic terrain loading? 0 Answers

Beyond boundary flat extension terrain? 1 Answer

Procedural Object Avoidance 1 Answer

Infinite 2d terrain generation methods 2 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