Terrain tiling - positioning math

Hi

I’m working on a terrain tiling script I found on this forum which is a very good demo but I needed to make a few changes to it 1) have tile references be stored in a database (complete) 2) make the limited tiling be infinitely repeated in both positive and negative directions.

I’m working on change 2 and while I think I have the which tile is next issue solved I can’t figure out the math to place the tiles beyond the first iteration. I have nine tiles named like so:

0-2 1-2 2-2

0-1 1-1 2-1

0-0 1-0 2-0

Starting in tile 0-0 moving positively along the x axis (through 1-0 and then 2-0) all the tiles position correctly as I’m simply using the first number of the tiles name (x coordinate) to multiple its width for the position. However when you start to move out of 2-0 you should reload the same sequence of tiles in their second iteration (so 0-0 is first, then 1-0 and 2-0) and so on infinitely. Each tile is 2000 width so I know iterations are going up in jumps of 6000 - where I get stuck is going from one iteration to the next and recalculating the position based on which tile is being moved into.

I’ve tried everything I can think of, a counting system for iterations, calculating movement direction etc. to work out the offset I need but it never seems to work. Below (and attached) is my code and I’ve marked where I’m stuck (with several failed attempts) in LoadZone but if you don’t fancy wading through it and know how to do what I’m trying to do some pseudo code would be greatly appreciated as it’s conceptualising and creating the offset formula that has me stuck.

thanks in advance
Garrett

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;

using Object = UnityEngine.Object;
using System.Linq;



public class ZoneLoader : MonoBehaviour
{
	//how far from edge to load or unload asset bundles
	const float   m_LoadDistance = 500.0F;
	const float   m_UnloadDistance = 1000.0F;
	
	//the dimensions square of each asset bundle
	public const float m_GridSize = 2000.0F;
	
	//how many zones in total and the x or y dimension
	//public const int m_ZoneCount = 0;
	//public const int m_ZoneDim = 0;
	
	static int m_ZoneCount = 0;
	static int m_ZoneDim = 0;
	
	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;
		}
	}
	
	//loading and unloading state variables
	bool          m_IsLoading = false;
	bool          m_IsUnloading = false;
	
	//use web downloading and caching
	bool          m_UseWWW = true;
	bool          m_UseWWWCaching = false;
	int           m_CacheVersion = 1;
	
	Vector3       m_PlayerPosition;
	Transform     m_PlayerTransform;
	
	float m_ZoneX, m_ZoneY, m_ActualZoneX, m_ActualZoneY;
	string m_ZoneName;
	
	float xposoffset, yposoffset, xfactor, yfactor;
	float xdirection, ydirection;
	
	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;
	}
	
	
	//depending on whether this is being run in the Unity editor or as a standalone player create a pathway to the asset bundles
	//in theory if these asset bundles are online this should still work you just need to change the pathway to a http one
	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_ZoneDim * m_ZoneDim];
	//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);
	}
	
	
	//figure out the name of the next Map to be loaded or unloaded 
	//map names must use a format of "Map_" followed by its x and y coordinate - e.g. "Map_0-0".
	static public string GetPrefix (int x, int y)
	{
		return GetPrefix("Map_", "", x, y);	
	}
	
	
	
	//ZoneLoader zone coroutine
	IEnumerator LoadZone (int LoadX, int LoadY, float ZoneX, float ZoneY)
	{
		////@TODO: if (!Application.CanStreamedLevelBeLoaded (GetPrefix(x, y)))
		
		//GetCurrentZone (m_PlayerPosition);
		
		//Debug.Log ("1: m_ZoneX = " + m_ZoneX + ", m_ZoneY = " + m_ZoneY);
		
		//if already loading halt here
		if (m_IsLoading)
		{
			Debug.LogError("Already loading zone");
			yield break;
		}
		
		//based on the passed terrain name to load get its key from the TerrainKeysDatabase
		int key;
		int.TryParse(UpdateZone.TerrainKeysDatabase[LoadX + "-" + LoadY], out key);
			
		//get current zone
		Zone zone = m_Zones[key];
		
		//zone cant be loaded so halt here
		if (!zone.m_IsLoadable) yield break;

		//get prefix
		string levelName = GetPrefix(LoadX, LoadY);
		
		//if zone not loaded
		if (!zone.m_Loaded)
		{
			//Debug.Log("Loading zone = " + GetPrefix(x, y));
					
			//set loading variable to true
			m_IsLoading = true;
		
			//if using web downloading or caching
			if (m_UseWWWCaching || m_UseWWW)
			{
				//create the url to the asset bundle
				string fullUrl = GetBaseUrl() + levelName + ".unity3d";

				//if using web caching
				if (m_UseWWWCaching)
					//load from cache or download
					zone.m_ZoneDownload = WWW.LoadFromCacheOrDownload (fullUrl, m_CacheVersion);
				else
					//create a new instance download
					zone.m_ZoneDownload = new WWW (fullUrl);
			
				//return the result
				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 asset bundle level
			//AsynchronousOperation async = Application.LoadLevelAdditiveAsynchronous(levelName);
			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 it exists
		if (zone.m_Root != null)
		{
			//load the new terrain
			Transform terain = zone.m_Root.transform.Find("Terrain");
	        if (terain)
			{
				
				
				
				
				///////////
				//calculating the position here does not work
				
				//offset for x and y
				float xoffset = 0;
				float yoffset = 0;
		

				/*
				if (m_ZoneX >= m_ZoneDim)
				{
					xoffset = m_GridSize * m_ZoneX;
				}
				
				if (m_ZoneY >= m_ZoneDim)
				{
					yoffset = m_GridSize * m_ZoneY;
				}
				*/
				
				//m_ZoneX, m_ZoneY
				
				/*
				//if position x is greater than the dimensions of total zones
				if (Mathf.Ceil(m_PlayerPosition.x / m_GridSize) >= m_ZoneDim)
				{
					//based on x position calculate x offset
					xoffset = m_GridSize * (m_ZoneX + 1);
				}

				//if position x is greater than the dimensions of total zones
				if (Mathf.Ceil(m_PlayerPosition.z / m_GridSize) >= m_ZoneDim)
				{
					//based on x position calculate x offset
					yoffset =  m_GridSize * (m_ZoneY + 1);
				}
				*/	
				
				//xoffset
				//yoffset
					
				
				
				
				


			
				xoffset = 0;
				yoffset = 0;
							
				//going x+
				if (xdirection == +1)
				{
					if (m_ZoneX + 1 == m_ZoneDim)
					{
						xoffset = (m_GridSize * m_ZoneDim) * (xfactor + 1);
					}
					else
					{
						xoffset = (m_GridSize * m_ZoneDim) * xfactor;
					}
				}
				
				//going x-
				if (xdirection == -1)
				{
					if (m_ZoneX == 0)
					{
						xoffset = (m_GridSize * m_ZoneDim) * (xfactor + 1);
					}
					else
					{
						xoffset = (m_GridSize * m_ZoneDim) * xfactor;
					}
				}
				
				//going y+
				if (LoadY > m_ZoneX)
				{
					ydirection = +1;	
				}
				
				//going y-
				if (LoadY < m_ZoneX)
				{
					ydirection = -1;
				}
		
				
				//all we care about here is loading 1 zone 
				//LoadX, LoadY

				
				
				//Limits of x axis
				if ((m_ZoneX == 0) || (m_ZoneX == m_ZoneDim - 1))
				{
					
					if (m_ZoneX == 0)
					{

					}
					
					if (m_ZoneX == m_ZoneDim - 1)
					{
						//xoffset = xposoffset - m_GridSize;
						Debug.Log ("margin right");
					}
				}
				else
				{
					Debug.Log ("centre");
				}
				
				
			//xposoffset
			//yposoffset
				
				
				
				

				

				
				//Debug.Log ("xtempfactor = " + xtempfactor + ", ytempfactor = " + ytempfactor);

				//xoffset = (m_GridSize * m_ZoneDim) * xtempfactor;
				//yoffset = (m_GridSize * m_ZoneDim) * ytempfactor;
				
				//Debug.Log ("xdirection = " + xdirection + ", ydirection = " + ydirection);
				//Debug.Log ("1: m_ZoneX = " + m_ZoneX + ", m_ZoneY = " + m_ZoneY);
				//Debug.Log ("1: LoadX = " + LoadX + ", LoadY = " + LoadY);
				Debug.Log ("xoffset = " + xoffset + ", yoffset = " + yoffset);
				

				//Debug.Log ("00: xPos = " + xPos + ", yPos = " + yPos);
				//Debug.Log ("00: sqrDistance = " + sqrDistance + ", closestDistance = " + closestDistance);

				
				//multiple the x and y indexs by the grid size and add the offset
				float xPos = (LoadX * m_GridSize) + xoffset;
				float yPos = (LoadY * m_GridSize) + yoffset;
				
				
				///////////
				
				
				
				
				
				
				
				//get the terrain component
				zone.m_Terrain = terain.GetComponent(typeof(Terrain)) as Terrain;
						
				//hide zone temporarily
				zone.m_Terrain.enabled = false;
						
				//there is a flash here just before the terrain is positioned
				//to fix you could manually set terrains at a minus Y position 
				//so they are initially out of view
						
				//its actually x and z you are positioning by
				zone.m_Terrain.transform.position = new Vector3(xPos, 0, yPos);
			
				//as you load a terrain set a few of its details (delete this later once zones are designed)
				zone.m_Terrain.treeCrossFadeLength = 200;
				zone.m_Terrain.detailObjectDistance = 400;
				
				//show zone temporarily
				zone.m_Terrain.enabled = true;

				//Debug.Log ("Zone = " + GetPrefix(x, y) + ": xoffset = " + xoffset + ", yoffset = " + yoffset);
				//Debug.Log ("Zone = " + GetPrefix(x, y) + ": xPos = " + xPos + ", yPos = " + yPos);
				//Debug.Log ("Loaded and placed Zone = " + GetPrefix(LoadX, LoadY) + " at " + zone.m_Terrain.transform.position);
			}

			//zone loaded
			zone.m_Loaded = true;
		}
		else
		{
			//else generate an error
			Debug.LogError(levelName + " could not be found after loading level");
		}
		
		
		/*
		//current terrains info
		Terrain curTerrain = GetLoadedTerrain(x, y);
		
		//get the current terrain from TerrainDatabase
		var CurrentTerrain = UpdateZone.TerrainDatabase[x.ToString() + "-" + y.ToString()];
	
		//four adjacent terrains, set them up as null (otherwise the code below produces an error)
		Terrain left = null, right = null, top = null, bottom = null;
		
		//loop through each entry in the current terrain
		foreach (KeyValuePair<string, string> TerrainValues in CurrentTerrain) 
		{
			//if the value isn't set to the string void (i.e. the direction != void)
			if (TerrainValues.Value != "void")
			{
				//Debug.Log ("key = " + TerrainValues.Key + ", value = " + TerrainValues.Value);
				
				//split each grid name into x and y positions
				string[] splitstring = TerrainValues.Value.Split('-');
			
				//convert each x and y string to integers
				int xi, yi;
				int.TryParse(splitstring[0], out xi);
				int.TryParse(splitstring[1], out yi);
			
				//get the terrain info for only N, E, S and W
				if (TerrainValues.Key == "N")
				{
					top = GetLoadedTerrain(xi, yi);
					//Debug.Log("N");
				}
				
				if (TerrainValues.Key == "E")
				{
					right = GetLoadedTerrain(xi, yi);
					//Debug.Log("E");
				}
			
				if (TerrainValues.Key == "S")
				{
					bottom = GetLoadedTerrain(xi, yi);
					//Debug.Log("S");
				}
			
				if (TerrainValues.Key == "W")
				{
					left = GetLoadedTerrain(xi, yi);
					//Debug.Log("W");
				}
			}
		}
		
		//set the neighbouring terrains
		curTerrain.SetNeighbors(left, top, right, bottom);
		//Debug.Log (levelName + " - neighbours set");
		*/


		
		//set loading variable to false
		m_IsLoading = false;
	}

	
	//unload zone coroutine
	IEnumerator UnloadZone (int UnloadX, int UnloadY)
	{
		//set unloading to true
		m_IsUnloading = true;

		//based on the passed terrain name to load get its key from the TerrainKeysDatabase
		int key;
		int.TryParse(UpdateZone.TerrainKeysDatabase[UnloadX + "-" + UnloadY], out key);
			
		//get current zone
		Zone zone = m_Zones[key];
		
		//set loaded to false
		zone.m_Loaded = false;
			
		if (zone.m_Root)
			Destroy(zone.m_Root);
        else
			Debug.LogError("Root for zone has already been unloaded:" + GetPrefix(UnloadX, UnloadY));
		
		//set terrain and root to null
		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;
		}
				
		//Debug.Log ("Unloaded zone = " + GetPrefix(UnloadX, UnloadY));

		m_ZonesUnloadedSinceLastAssetUnload++;
		
		//set unloading to false
		m_IsUnloading = false;
	}
	
	
	/// Unload assets at some points
	//AsyncOperation op = Resources.GarbageCollectAssets(-1); 

	
	void OnEnable ()
	{
		ms_Singleton = this;	
	}
	
	
	void Awake ()
	{	

	}

	
	
	//squared distance
	float GetSqrDistance (Vector3 position, int x, int y)
	{
		//Debug.Log ("position.x = " + position.x + ", position.z = " + position.z);

		float minx = x * m_GridSize;
		float maxx = (x+1) * m_GridSize;
		float miny = y * m_GridSize;
		float maxy = (y+1) * m_GridSize;

		//offset for x and y
		float xoffset = 0;
		float yoffset = 0;
	
		
		
		
		//if (m_ZoneX >= m_ZoneDim - 1)
		//{
		//xoffset = (m_GridSize * m_ZoneDim) * factor;
		//yoffset = (m_GridSize * m_ZoneDim) * factor;
		//}
		
		
		//if position x is greater than the dimensions of total zones
		if (Mathf.Ceil(position.x / m_GridSize) >= m_ZoneDim)
		{
			//based on x position calculate x offset
			xoffset = m_GridSize * m_ZoneX;
		}

		//if position x is greater than the dimensions of total zones and current y is next to current Y Zone
		if (Mathf.Ceil(position.z / m_GridSize) >= m_ZoneDim)
		{
			//based on x position calculate x offset
			yoffset = m_GridSize * m_ZoneY;
		}
		
		
		//if (x == 0  y == 0)
		//{
			//Debug.Log ("00: xoffset = " + xoffset + ", yoffset = " + yoffset);
		//}


		/*
		float multiplyby = 1.0f;
				
		if (m_PlayerPosition.z < 1000)
		{
			multiplyby = -1.0f;
		}
		*/
		
		
		
		float xDistance = 0.0F;
		float yDistance = 0.0F;
		
		if (position.x < minx)
			xDistance = Mathf.Abs(minx - position.x) - xoffset;
		else if  (position.x > maxx)
			xDistance = Mathf.Abs(maxx - position.x) - xoffset;

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

		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;
	}

	

	//get each zones x and y from database
	void GetZoneIndexName (string ZoneXY, out int x, out int y)
	{
		//split the key by -
		string[] splitstring = ZoneXY.Split('-');

		//convert each x and y string to integers
		int.TryParse(splitstring[0], out x);
		int.TryParse(splitstring[1], out y);
	}

	
	//get zones in range
	void GetCurrentZone (Vector3 position)
	{
			//calculate what zone the user should be over
			m_ZoneX = Mathf.Floor(position.x / m_GridSize);
			m_ZoneY	= Mathf.Floor(position.z / m_GridSize);
			
			//calculate based on where the user is what both database indexs are
			m_ActualZoneX = m_ZoneX;
			m_ActualZoneY = m_ZoneY;
			
			xfactor = Mathf.Floor(m_ZoneX / m_ZoneDim);
			yfactor = Mathf.Floor(m_ZoneY / m_ZoneDim);
			if (m_ZoneX >= m_ZoneDim) m_ActualZoneX = m_ZoneX - (m_ZoneDim * xfactor);
			if (m_ZoneY >= m_ZoneDim) m_ActualZoneY = m_ZoneY - (m_ZoneDim * yfactor);
			m_ZoneName = m_ActualZoneX + "-" + m_ActualZoneY;
		

				xdirection = 0;
				ydirection = 0;
				
				if (FPSWalkerEnhanced.moveDirection.x > 0)
				{
					xdirection = +1;
				}
				
				if (FPSWalkerEnhanced.moveDirection.x < 0)
				{
					xdirection = -1;
				}
				
				if (FPSWalkerEnhanced.moveDirection.z > 0)
				{
					ydirection = +1;
				}
				
				if (FPSWalkerEnhanced.moveDirection.z < 0)
				{
					ydirection = -1;
				}
		
		
		//Debug.Log ("Current zone function: m_ZoneX = " + m_ZoneX + ", m_ZoneY = " + m_ZoneY);
		
	}
	
	
	
	//get zones in range
	void GetClosestZone (Vector3 position, float closestDistance, out int closestX, out int closestY)
	{
		//error if the current zone is not in range
		closestX = -1;
		closestY = -1;
		
		//closestDistance = closestDistance * closestDistance;
	
		//loop through the database keys
		foreach (KeyValuePair<string, string> entry in UpdateZone.TerrainKeysDatabase) 
		{
			GetCurrentZone (position);
			
			//limit what's checked (to nine zones), only the current zone or zones in the current zone
			if ((entry.Key == m_ZoneName) || (UpdateZone.TerrainZonesDatabase[m_ZoneName].ContainsValue(entry.Key)))
			{
				//parse out the zones index, x and y from the database
				int key, x, y;
				int.TryParse(entry.Value, out key);
				GetZoneIndexName(entry.Key, out x, out y);

				//Debug.Log ("key = " + key + ", x = " + x + ", y = " + y);
			
				//use the same index as the database access loaded zones
				Zone zone = m_Zones[key];

				//if current zone is not loaded and is loadable
				if (!zone.m_Loaded  zone.m_IsLoadable)
				{
					//get the square distance of the user from zone
					float sqrDistance = GetSqrDistance(position, x, y);
		
					//calculate closest distance
					//closestDistance = (m_LoadDistance + xoffset) * (m_LoadDistance + yoffset);
					closestDistance = m_LoadDistance * m_LoadDistance;
				
				if (x == 0  y == 0)
				{
					//Debug.Log ("00: sqrDistance = " + sqrDistance + ", closestDistance = " + closestDistance);
				}
				
					
					
					
					
					
					
					
					
					
				
					//if square distance is less than closest distance			
					if (sqrDistance < closestDistance)
					{
						//closestDistance = m_LoadDistance;
						Debug.Log ("Zone in range = " + GetPrefix(x, y));
						//return the x and y coordinates
						closestX = x;
						closestY = y;
					}
				}
			}
		}
	}
	
	
	
	//get zones out of range
	void GetOutofrangeZone (Vector3 position, float farthestDistance, out int farthestX, out int farthestY)
	{
		//error if the current zone is not out of range
		farthestX = -1;
		farthestY = -1;
	
		//farthestDistance = farthestDistance * farthestDistance;
		
		//loop through the current zones database entry's terrains
		foreach (KeyValuePair<string, string> entry in UpdateZone.TerrainKeysDatabase) 
		{
			GetCurrentZone (position);
			
			//limit what's checked (to nine zones), only the current zone or zones in the current zone
			if ((entry.Key == m_ZoneName) || (UpdateZone.TerrainZonesDatabase[m_ZoneName].ContainsValue(entry.Key)))
			{
				//parse out the zones index, x and y from the database
				int key, x, y;
				int.TryParse(entry.Value, out key);
				GetZoneIndexName(entry.Key, out x, out y);
			
				//Debug.Log ("key = " + key + ", x = " + x + ", y = " + y);
			
				//use the same index as the database access loaded zones
				Zone zone = m_Zones[key];

				//if (zone.m_Loaded) Debug.Log ("Zone " + GetPrefix(x, y) + " is loaded");

				//if zone is loaded
				if (zone.m_Loaded)
				{
					//get the square distance of each grid location
					float sqrDistance = GetSqrDistance(position, x, y);

					//offset for x and y
					float xoffset = 0;
					float yoffset = 0;
				
					//if position x is greater than the dimensions of total zones
					if (Mathf.Ceil(position.x / m_GridSize) >= m_ZoneDim)
					{
						//based on x position calculate x offset
						xoffset = Mathf.Ceil(position.x / m_GridSize) * m_GridSize;
					}

					//if position x is greater than the dimensions of total zones
					if (Mathf.Ceil(position.z / m_GridSize) >= m_ZoneDim)
					{
						//based on x position calculate x offset
						yoffset = Mathf.Ceil(position.z / m_GridSize) * m_GridSize;
					}
						
					//calculate closest distance
					farthestDistance = (m_UnloadDistance + xoffset) * (m_UnloadDistance + yoffset);

					//if square distance is greater than unload distance			
					if (sqrDistance > farthestDistance)
					{
						//Debug.Log ("Zone: " + GetPrefix(x, y) + " sqrDistance = " + sqrDistance + ", m_UnloadDistance = " + (m_UnloadDistance * m_UnloadDistance));
	
						//farthestDistance = sqrDistance;
						//return the x and y coordinates
						farthestX = x;
						farthestY = y;
					}
				}
			}
		}
	}

	
	
	void Update ()
	{
		//check that the TerrainDatabase Dictionary has loaded
		//"starting", "database loaded", "database converted", "first zones loade
		if (UpdateZone.LoadedState == 3)
		{
			ms_Singleton = this;
			
			//count how many items in the database and how many dimensions (x, Y) there are
			m_ZoneCount = UpdateZone.TerrainKeysDatabase.Count;
			m_ZoneDim = Mathf.FloorToInt(Mathf.Sqrt(m_ZoneCount));
			//Debug.Log ("m_ZoneCount = " + m_ZoneCount);
			//Debug.Log ("m_ZoneDim = " + m_ZoneDim);
			
			//make an array of zones based on the count of database entries
			m_Zones = new Zone[m_ZoneCount];
			
			//loop through array and populate it with a new zone
			for (int i = 0; i < m_Zones.Length; i++)
			{
				m_Zones[i] = new Zone();
			}

			//not sure why this is here?
			ms_Singleton = this;
			
			//4 = "starting"
			UpdateZone.LoadedState = 4;
		}
		

		//wait until everything is ready
		if (UpdateZone.LoadedState == 4)
		{
			//get the users position
			if (m_PlayerTransform) m_PlayerPosition = m_PlayerTransform.position;
		


			//if loading or unloading stop here
			if (m_IsLoading || m_IsUnloading) return;
		
			//get the farthest zones returning x and y coordinates for each
			int farthestX = -1, farthestY = -1;
			//Debug.Log ("Before range test: " + farthestX + ", " + farthestY);
			GetOutofrangeZone(m_PlayerPosition, m_UnloadDistance, out farthestX, out farthestY);
			//Debug.Log ("After range test: " + farthestX + ", " + farthestY);
			
			//if the returning x position is not -1 start the unload coroutine
			if (farthestX != -1) StartCoroutine(UnloadZone(farthestX, farthestY));

			//get the closest zones returning x and y coordinates for each
			int closestX, closestY;
			GetClosestZone(m_PlayerPosition, m_LoadDistance, out closestX, out closestY);
			
			//if the returning x position is not -1 start the load coroutine
			if (closestX != -1) StartCoroutine(LoadZone (closestX, closestY, m_ZoneX, m_ZoneY));
		}
	}

	
	Terrain GetLoadedTerrain (int x, int y)
	{
		//Debug.Log ("m_ZoneCount = " + m_ZoneCount);
		//Debug.Log ("m_ZoneDim = " + m_ZoneDim);
		
		
		//if (x >= 0  x < m_ZoneDim) Debug.Log ("x = " + x);
		//if (y >= 0  y < m_ZoneDim) Debug.Log ("y = " + y);
			
		if ((x >= 0  x < m_ZoneDim)  (y >= 0  y < m_ZoneDim))
		{
			//Zone zone = m_Zones[m_ZoneCount*y + x];
			Zone zone = m_Zones[x + y];
			//Debug.Log ("Zone: " + x + ", " + y + " loaded");
			if (zone.m_Loaded) return zone.m_Terrain;
		}
		
		return null;
	}
	
}

1356605–67171–$ZoneLoader.cs.zip (6.36 KB)

bump, nobody?

i’m tired and don’t get your coordinate system but incase the “-” is just the “delimiter” change it to avoid confusion with negative coordinates.

usually when you post code you should reduce it to a minimum required example. it seems your database connection and singleton implementation is not connected to your problem / question so why should someone read over it. thats the reason why i don’t responded initially. people should spent more attention to forum “rules” and netiquette.

i also don’t understand your question. you want to know which tile (0-0, 1-0, 2-0) is clicked from the x coordinate of the mouseclick? then you could simply use the % operator (modulo).

float remainder = x % 6000.0f;
int xtile = (int)(remainder / 2000.0f);

for example you have an x position of 15000. the remainder is 3000 and the tile is 1 (second tile, zero based index).

yes the “-” is just a delimiter.

a little bit difficult to post less than what I did because of how it works/is all interconnected. My explanation was as minimal as possible and that’s probably why you don’t understand the question (I explained it in too short of detail).

No there are no mouse clicks, this is a tiling script that places tiles as you move the camera through the space along x and z coordinates. Each tile is 2000 wide and long. The names of the tiles are it’s x-y coordinates (positions are then calculated based on this: x * 2000 etc.). The main issues I’m having are complicated by the fact that leaving edge tiles (i.e. going out of the set of 9) will repeat the set of 9 again. So for example if I move out of 2-0 going along the x axis I will arrive again in 0-0, like so:

0-2 1-2 2-2        0-2 1-2 2-2

0-1 1-1 2-1        0-1 1-1 2-1

0-0 1-0 2-0   ->   0-0 1-0 2-0

Essentially I’m trying to give the impression that the camera has moved around a globe (west to east) and arrived back on the east.

The main issues I’m having are knowing when I approach the edge of a tile on the edge of the set and calculating the offset for the new tiles square distance (in the function: GetSqrDistance) and then calculating the offset for the position (in the function: LoadZone).

Ultimately the camera will need to move in all directions (x and y) like so:

0-2 1-2 2-2        0-2 1-2 2-2

0-1 1-1 2-1        0-1 1-1 2-1

0-0 1-0 2-0   <-   0-0 1-0 2-0

but if I could get x positive positions working on its own I could then easily get y positive positions working (and then hopefully both negative positions).

It looks like you need to understand modulo arithmetic. Perhaps that phrase will help you on Google. Exiguous tried to explain.

To learn what tile you’re in, from a given coordinate, you would first divide down.

zoneX = worldX / 2000.0f # number of world units in each zone

If you went too far to the east, you’d still get coordinates like zoneX = 4. Then you would ensure the zone tile number never exceeded your actual number of zones.

zoneX = zoneX % 3 # number of zones wide before the world repeats

This is the same math that makes your clock go from zero minutes to 59 minutes, then wrap around.

Hours = Minutes / 60
Hours = Hours % 24
Minutes = Minutes % 60

interesting that i only “tried”. from my point of view i did, even with an example. probably the language barrier is higher than i expected.

i can’t believe that. the examples i posted are clearly unnecessary for your question/problem. and i (and probably others) simply refuse to wade through your whole file.

Yes modulo would certainly have made my math more simple. I was using Mathf.Floor(ZoneX / 3) to do get the actual zone (all in the function GetCurrentZone).

I thought you explained modulo just fine, Halley just did it in more detail. Regardless of this modulo isn’t the answer to the problem, it helps but I had been getting those values in my original script.

You don’t have to. All I asked for in my original post was an explanation of how to conceive of solving the problem, preferably in English, perhaps some pseudo code but I wasn’t necessarily looking for a scripted solution. I posted two detailed explanations of the problem, the second because you said you didn’t understand the first. The script I attached was to help contextualise the problem and how I was attempting to solve it.

Anyway I have found a solution late last night to exactly this script here: http://answers.unity3d.com/questions/302316/loadleveladditiveasync-at-position.html. I’m going through the script this morning to see how my problem has been solved so I can then read apt it to my database variant. Many thanks both for your help.

You did fine. Just as it takes two to tango, it takes someone understanding the words to call it a success. No slight to you.