void OnGUI() { WorldChunkSettings setting = MapEngine.instance.worldChunkSetting; Coord viewer = new Coord(Viewer.instance.bound.center, setting); GUI.color = Color.black; GUI.Label(new Rect(10f, 30f, 250f, 30f), viewer + " - " + Viewer.instance.scale + ": " + GetChunkLevel(Viewer.instance.scale)); float y = 50f; if (/* Display all zones ? */ false) { for (int i = 0; i < this.worldZones.Count; i++) { y = this.OnGUIZone(this.worldZones [i], y); } } else { Bounds viewerBound = Viewer.instance.bound; Coord viewerChunkCoord = new Coord(viewerBound.center, setting); WorldChunk chunk = this.worldChunks [viewerChunkCoord]; for (int i = 0; i < chunk.worldZonesRefs.Count; i++) { y = this.OnGUIZone(chunk.worldZonesRefs[i], y); } } }
public void TestMerged(WorldChunkSettings setting) { if (this.state >= ChunkStates.Merged) { return; //done } bool allZonesMerged = true; bool onlySmallGroundRemaining = true; for (int idx = 0; idx < this.worldZonesRefs.Count; idx++) { WorldZone zone = this.worldZonesRefs [idx]; if (zone.state < WorldZoneStates.Merged) { allZonesMerged = false; if (zone.type != WorldZoneTypes.Ground) { // onlySmallGroundRemaining = false; } } } if (allZonesMerged) { this.OnChunkMerged(); } }
public void UpdateMapShader() { WorldChunkSettings setting = MapEngine.instance.worldChunkSetting; this.mapTextureData.UpdateStartHeights(setting); this.mapTextureData.ApplyOnMaterial(this.chunkMeshMaterial); }
// setting already retrieved when new Chunk are created public WorldChunkData(WorldChunk chunk, WorldChunkSettings setting) { DevNoiseType devNoiseType = MapEndless.instance.devNoiseType; // Get Height Map FastNoise fastNoiseGround = setting.fastNoiseGround.fastNoise; FastNoise fastNoiseRegion = setting.fastNoiseRegion.fastNoise; int length = setting.scaledSize * setting.scaledSize; int chunkOffsetX = chunk.coord.x * setting.scaledSize - (setting.scaledSize / 2); int chunkOffsetY = chunk.coord.y * setting.scaledSize - (setting.scaledSize / 2); this.heightMap = new float[length]; this.regionMap = new float[length]; for (int y = 0; y < setting.scaledSize; y++) { for (int x = 0; x < setting.scaledSize; x++) { // Test and return only a mountain on [1;1] to [9;1] Coord c = new Coord(x, y, setting); if (devNoiseType != DevNoiseType.NoDev) { // Use dev noise this.heightMap [c.idx] = this.getZonesHeightTest(new Coord(c.x + chunkOffsetX, c.y + chunkOffsetY), devNoiseType); } else { // Use fastNoiseGround this.heightMap [c.idx] = (fastNoiseGround.GetNoise(c.x + chunkOffsetX, c.y + chunkOffsetY) + 1f) / 2f; } this.regionMap [c.idx] = (fastNoiseRegion.GetNoise(c.x + chunkOffsetX, c.y + chunkOffsetY) + 1f) / 2f; } } }
public WorldChunk(Coord _coord, GameObject _chunkObject, WorldChunkSettings setting, DisplayModes _displayMode, ChunkStates _requireState) { this.coord = _coord; this.state = ChunkStates.Created; this.displayMode = _displayMode; this.isVisible = false; this.isLoading = false; this.isComputing = false; this.isMeshing = false; this.requireState = _requireState; this.chunkObject = _chunkObject; this.chunkObject.transform.parent = setting.parent; this.chunkObject.transform.localScale = new Vector3(setting.size, .01f, setting.size); this.chunkObject.transform.localPosition = this.coord.ToWorldPosition(setting); MapDisplay.instance.UpdateChunkName(this, setting); // Request Data if (this.requireState >= ChunkStates.Loaded) { this.requestData(setting); } else { MapDisplay.instance.UpdateChunkDisplay(this); } }
static void UpdateVertexesOnRange(WorldChunk chunk, int min_x, int max_x, int min_y, int max_y, int[,] vertexIndicesMap, int meshSize, int borderedSize, float offset, WorldChunkSettings setting) { for (int y = min_y; y < max_y; y++) { for (int x = min_x; x < max_x; x++) { Coord chunkCoord = new Coord(x - 1, y - 1, setting); // It's start with [-1;-1] int vertexIndex = vertexIndicesMap [x, y]; // @TODO We already know the concerned sideChunk (it's `keyValue.Value` on `UpdateChunkMesh` loop // (can be pass throw GetHeightValue to avoid search it on the list) float height = chunk.GetHeightValue(chunkCoord, setting); Vector2 uv = new Vector2((x - 1) / (float)(borderedSize - 2), (y - 1) / (float)(borderedSize - 2)); Vector3 vertexPosition = new Vector3( offset + uv.x * meshSize, height, offset + uv.y * meshSize ); chunk.meshData.AddOrUpdateVertex(vertexPosition, uv, vertexIndex); } } }
public void requestComputed(WorldChunkSettings setting) { // Request Data this.isComputing = true; this.computingTime = Time.time; MapThreading.instance.RequestWorldChunkComputed(this, setting, OnWorldChunkComputedReceived); }
public float GetRegionScaledValue(Coord coord, WorldChunkSettings setting) { Coord scaledCoord = new Coord( coord.x / setting.scaledSize, coord.y / setting.scaledSize, setting); return(this.GetRegionValue(scaledCoord)); }
public Vector3 ToWorldPosition(WorldChunkSettings setting) { // Reverse if required (from Coord X/Y to Unity X/Y 3D World) return(new Vector3( this.x * setting.size * Coord.Right.x, // * Coord.Right.x to reverse world X and chunk X (if required) 0f, this.y * setting.size * Coord.Top.y // * Coord.Top.y to reverse world Y and chunk Y (if required) )); }
public void CreateWorldChunks(WorldChunkSettings settings) { // iterate through generation amount for (int i = 0; i < settings.amount; i++) { // create new chunk CreateWorldChunk(settings); } }
// Merge all zone from this chunk and all sideChunk // Will be called one time and another time reversed (to found fakezone and ground zone who need to be merged with MainGround) void MergeSideChunk(Direction direction, WorldChunk sideChunk, WorldChunkSettings setting) { Direction inverseDirection = Coord.GetDirectionInverse(direction); for (int chunkZone_idx = this.chunkComputed.zones.Count - 1; chunkZone_idx >= 0; chunkZone_idx--) { WorldChunkComputed.WorldChunkZone chunkZone = this.chunkComputed.zones [chunkZone_idx]; if (chunkZone.worldZoneRef.isMainGround) { continue; // Don't merge MainGround into another } // Found a zone who need to be merged on direction (and it's not already done ? we repass here when reverse) if (chunkZone.isDirectionChunkBorder [direction] && chunkZone.missingChunks.Contains(sideChunk.coord)) { bool machingFound = false; for (int sideChunkZone_idx = sideChunk.chunkComputed.zones.Count - 1; sideChunkZone_idx >= 0; sideChunkZone_idx--) { WorldChunkComputed.WorldChunkZone sideChunkZone = sideChunk.chunkComputed.zones [sideChunkZone_idx]; if (!sideChunkZone.isDirectionChunkBorder [inverseDirection]) { continue; } if (!sideChunkZone.missingChunks.Contains(this.coord)) { continue; } if (sideChunkZone.type != chunkZone.type) { continue; } if (this.MergeIfMatchingCoords(chunkZone, direction, sideChunk, sideChunkZone, setting)) { machingFound = true; } } // IT's a fake bordered zone ! Some coord are on the limit of the chunk but no one on the next if (!machingFound && !chunkZone.worldZoneRef.isMainGround) { chunkZone.missingChunks.Remove(sideChunk.coord); chunkZone.isDirectionChunkBorder [direction] = false; chunkZone.directionChunkBorderCoords [direction].Clear(); /* done by sideChunk.SeeMore() * if (chunkZone.worldZoneRef.GetMissingChunks ().Count == 0) { * chunkZone.worldZoneRef.OnMergeCompleted (); * }*/ } } } }
// Get Scaled data (real in game coord) // Size: 50x50 - Scale: 10 -> coord from [0;0] to [50;50] public float GetHeightScaledValue(Coord coord, WorldChunkSettings setting) { //int sizeScaled = setting.size / setting.scale; Coord scaledCoord = new Coord( coord.x / setting.scaledSize, coord.y / setting.scaledSize, setting); return(this.GetHeightValue(scaledCoord)); }
public void Unload(WorldChunkSettings setting) { this.isVisible = false; if (MapDisplay.instance.displayFogOfWar == true) { Renderer renderer = this.chunkObject.GetComponent <Renderer> (); renderer.material.color = Color.gray; } MapDisplay.instance.UpdateChunkName(this, setting); }
public void DeleteWorldChunks(WorldChunkSettings settings) { // while not empty while (settings.chunks.Count != 0) { // destroy gameobject Destroy(settings.chunks [0]); // delete node settings.chunks.RemoveAt(0); } }
public void DeleteWorldChunk(WorldChunkSettings settings, int index) { // check index range if (index > -1) { // destroy gameobject Destroy(settings.chunks [index]); // remove node settings.chunks.RemoveAt(index); } }
public void DeleteWorldChunk(WorldChunkSettings settings, GameObject obj) { // check if null if (obj != null) { // destroy gameobject Destroy(obj); // remove node settings.chunks.Remove(obj); } }
void CreateMeshAndUpdateSideMeshs(WorldChunk chunk, WorldChunkSettings setting) { //GameObject meshObjectContainer = new GameObject(); chunk.meshObject = new GameObject(); MeshRenderer renderer = chunk.meshObject.AddComponent <MeshRenderer> (); MeshFilter filter = chunk.meshObject.AddComponent <MeshFilter> (); filter.mesh = chunk.meshData.CreateMesh(); renderer.material = MapDisplay.instance.chunkMeshMaterial; renderer.material.mainTexture = TextureGenerator.WorldMergingTexture(chunk, setting); // @TODO: Why do I have to do that ? Texture are 1coord too big for mesh, but are good for chunk (on dev cube) float textureScale = 1f + (1f / setting.scaledSize); renderer.material.mainTextureScale = new Vector2(textureScale, textureScale); /* DisplayMeshFilterNormals displayMeshFilterNormals = chunk.meshObject.AddComponent<DisplayMeshFilterNormals> (); * displayMeshFilterNormals.normalLength = setting.size / 10f; * displayMeshFilterNormals.normalColor = Color.black;*/ /* * meshObjectContainer.transform.name = chunk.coord.ToString(); * meshObjectContainer.transform.parent = setting.meshParent; * meshObjectContainer.transform.localPosition = chunk.coord.ToWorldPosition (setting); */ // chunk.meshObject.transform.parent = meshObjectContainer.transform; chunk.meshObject.transform.parent = setting.meshParent; chunk.meshObject.transform.name = chunk.coord.ToString(); chunk.meshObject.transform.localPosition = chunk.coord.ToWorldPosition(setting); //Vector3.zero; // Why ? setting.scaledSize chunk.meshObject.transform.localScale = new Vector3(setting.size / setting.scaledSize, setting.size, setting.size / setting.scaledSize); // If any sides chunks are loaded, update it for (int y = chunk.coord.y - 1; y <= chunk.coord.y + 1; y++) { for (int x = chunk.coord.x - 1; x <= chunk.coord.x + 1; x++) { if (x == chunk.coord.x && y == chunk.coord.y) { continue; } Coord sideCoord = new Coord(x, y); if (chunk.chunkBorders.sidesChunks.ContainsKey(sideCoord)) { WorldChunk sideChunk = chunk.chunkBorders.sidesChunks [sideCoord]; if (sideChunk.state >= ChunkStates.Meshed) { MeshGenerator.UpdateChunkMesh(sideChunk, setting); } } } } }
void UpdateCursor(WorldChunk _chunk, WorldChunkSettings setting, WorldChunkZone zone, Coord coord, Coord lastCoordDirection) { this.countTest++; if (coord.x < 0 || coord.y < 0 || coord.x >= setting.scaledSize || coord.y >= setting.scaledSize) { // Is out of chunk! return; } // First already contains on the current zone (ex: [0;0] -> [0;1] -> [0;0] will append offen) if (zone.coords.Contains(coord)) { return; } // Test zone type (get the type based on heightMap) WorldZoneTypes coordType = _chunk.chunkData.GetZoneType(coord, setting); if (coordType != zone.type) { // It's not the same region (add it only one time) if (!this.HasZone(coord) && !this.availableCoords.Contains(coord)) { this.availableCoords.Add(coord); } return; } // It's a new on the same zone, add zone.AddCoord(coord, setting); // If the coord is on the free coord list (for future next list) if (this.availableCoords.Contains(coord)) { this.availableCoords.Remove(coord); } // Test all sides (but avoid returning on same than previous) if (lastCoordDirection != Coord.Top) { UpdateCursor(_chunk, setting, zone, coord.GetDirection(Direction.Top), Coord.Bottom); } if (lastCoordDirection != Coord.Bottom) { UpdateCursor(_chunk, setting, zone, coord.GetDirection(Direction.Bottom), Coord.Top); } if (lastCoordDirection != Coord.Left) { UpdateCursor(_chunk, setting, zone, coord.GetDirection(Direction.Left), Coord.Right); } if (lastCoordDirection != Coord.Right) { UpdateCursor(_chunk, setting, zone, coord.GetDirection(Direction.Right), Coord.Left); } return; }
public static Texture2D WorldChunkStatesTexture(WorldChunk chunk, WorldChunkSettings setting) { Color loaded = new Color(.2f, .2f, 1f); Color computed = new Color(.2f, 1f, .2f); Color merging = new Color(1f, .2f, .2f); Color merged = new Color(1f, .9f, .2f); Color groundMin = new Color(.25f, .25f, .25f); Color groundMax = new Color(.75f, .75f, .75f); Color[] colourMap = new Color[setting.scaledSize * setting.scaledSize]; for (int y = 0; y < setting.scaledSize; y++) { for (int x = 0; x < setting.scaledSize; x++) { Coord c = new Coord(x, y, setting); float height = chunk.chunkData.GetHeightValue(c); if (chunk.state == ChunkStates.Loaded) { colourMap [y * setting.scaledSize + x] = Color.Lerp(Color.black, Color.white, height) * loaded; } else if (chunk.state >= ChunkStates.Computed) { // idx: y * size + x Color state = computed; if (chunk.state == ChunkStates.Computed && chunk.requireState > ChunkStates.Computed) { state = merging; } else if (chunk.state >= ChunkStates.Merged) { state = merged; } if (height < setting.water) { colourMap [y * setting.scaledSize + x] = Color.white * state; } else if (height > setting.mountain) { colourMap [y * setting.scaledSize + x] = Color.black * state; } else { float delta = (height - setting.water) * (1 / (setting.mountain - setting.water)); colourMap [y * setting.scaledSize + x] = Color.Lerp(groundMax, groundMin, delta) * state; } } } } return(TextureGenerator.TextureFromColorMap(colourMap, setting.scaledSize)); }
public void RequestWorldChunkComputed(WorldChunk chunk, WorldChunkSettings setting, Action <WorldChunkComputed> callback) { ThreadStart threadStart = delegate { // Loading WorldChunkComputed chunkComputed = new WorldChunkComputed(chunk, setting); lock (chunkComputedThreadInQueue) { chunkComputedThreadInQueue.Enqueue(new MapComputingThreadInfo <WorldChunkComputed>(callback, chunkComputed)); } // End Loading.. }; new Thread(threadStart).Start(); }
public void CreateWorldChunk(WorldChunkSettings settings) { // initialize variables int index = settings.chunks.Count; Vector3 position = new Vector3(0, 0, 0); if (settings.chunks.Count > 0) { position = settings.chunks [settings.chunks.Count - 1].transform.position; } // instantiate new object settings.chunks.Add(Instantiate(settings.prefabs[0], position + Vector3.up * settings.offset, new Quaternion(), settings.container)); }
public void RequestWorldChunkData(WorldChunk chunk, WorldChunkSettings setting, Action <WorldChunkData> callback) { ThreadStart threadStart = delegate { // Loading WorldChunkData chunkData = new WorldChunkData(chunk, setting); lock (chunkDataThreadInQueue) { chunkDataThreadInQueue.Enqueue(new MapThreadInfo <WorldChunkData>(callback, chunkData)); } // End Loading.. }; new Thread(threadStart).Start(); }
// This function have to be here because return is based on HeightMap ! And have NO considaration on computed zones // Will be called to create a new zone from this coord public WorldZoneTypes GetZoneType(Coord coord, WorldChunkSettings setting) { float heightValue = this.GetHeightValue(coord, setting); if (heightValue < setting.water) { return(WorldZoneTypes.Water); } else if (heightValue > setting.mountain) { return(WorldZoneTypes.Mountain); } return(WorldZoneTypes.Ground); }
public WorldChunkComputed(WorldChunk _chunk, WorldChunkSettings setting) { // Init attribute this.isCompleted = false; this.zones = new List <WorldChunkZone>(); // List all coord found next to found zones, an easy way to know here to start a new zone this.availableCoords.Add(new Coord(0, 0)); // Init first zone at [0;0] (all chunk have a 00) // Loop to find all zones on the chunk this.FindNewZone(_chunk, setting); this.isCompleted = true; // Before Clean zone (ex: Ground -> MainGround) this.CleanZones(_chunk, setting); }
public void AddCoord(Coord coord, WorldChunkSettings setting) { this.coords.Add(coord); // Test chunks sides for each directions for (int e = 0; e < Coord.directions.Length; e++) { if (coord.IsOnChunkBorder(Coord.directions[e], setting)) { isDirectionChunkBorder [Coord.directions [e]] = true; directionChunkBorderCoords [Coord.directions [e]].Add(coord.GetBorderValue(Coord.directions [e])); // Every coord who are not really bordered will be removed on future } } }
void FindNewZone(WorldChunk _chunk, WorldChunkSettings setting) { // Coord found if (availableCoords.Count > 0) { Coord firstNotInZone = availableCoords [0]; // Create a new zone based on this coord WorldChunkZone zone = new WorldChunkZone(_chunk.chunkData.GetZoneType(firstNotInZone, setting)); this.zones.Add(zone); this.UpdateCursor(_chunk, setting, zone, firstNotInZone, new Coord(0, 0)); // Zone computed, check for next this.FindNewZone(_chunk, setting); } }
public void UpdateSideBorders(WorldChunk chunk, WorldChunkSettings setting) { for (int y = chunk.coord.y - 1; y <= chunk.coord.y + 1; y++) { for (int x = chunk.coord.x - 1; x <= chunk.coord.x + 1; x++) { if (x == chunk.coord.x && y == chunk.coord.y) { continue; } Coord c = new Coord(x, y, setting); // Already found, dont copy again an again if (!this.sidesChunks.ContainsKey(c)) { if (MapEndless.instance.worldChunks.ContainsKey(c)) { WorldChunk sideChunk = MapEndless.instance.worldChunks [c]; if (sideChunk.state >= ChunkStates.Merged) { this.sidesChunks [c] = sideChunk; } } } } } // DEV if (chunk.meshObject != null) { // Do it after all string dev = ""; for (int y = chunk.coord.y - 1; y <= chunk.coord.y + 1; y++) { for (int x = chunk.coord.x - 1; x <= chunk.coord.x + 1; x++) { if (x == chunk.coord.x && y == chunk.coord.y) { continue; } Coord c = new Coord(x, y, setting); if (this.sidesChunks.ContainsKey(c)) { dev += " " + c; } } } chunk.meshObject.transform.name = chunk.coord + ((dev != "") ? (" is normalized with " + dev) : ""); } }
// When data are received from chunk public void OnWorldChunkThreadReceived(WorldChunk _chunk) { // Get the info that a chunk is Loaded. (in case it's not on bound) this.worldChunksInView.Add(_chunk); WorldChunkSettings setting = MapEngine.instance.worldChunkSetting; if (_chunk.state == ChunkStates.Computed) { this.CreateWorldZones(_chunk, setting); // Will be updated after TryMergeZone } if (_chunk.state == ChunkStates.Meshed) { this.CreateMeshAndUpdateSideMeshs(_chunk, setting); } }
public void OnChunkMerged() { WorldChunkSettings setting = MapEngine.instance.worldChunkSetting; this.state = ChunkStates.Merged; if (this.requireState < ChunkStates.Merged) // If all the chunk is merged but wasn't required for (ex: side chunk with not border) { this.requireState = ChunkStates.Merged; } MapDisplay.instance.UpdateChunkDisplay(this); this.isMeshing = true; // Create the first time the chunk borders values this.chunkBorders = new WorldChunkSideBorders(this, setting); // Request Mesh data MapThreading.instance.RequestWorldChunkMeshData(this, this.chunkBorders, setting, OnWorldChunkMeshReceived); }
public static Texture2D WorldZonesMergingTexture(WorldChunk chunk, WorldChunkSettings setting) { Color groundMin = new Color(.25f, .25f, .25f); Color groundMax = new Color(.75f, .75f, .75f); Color[] colourMap = new Color[setting.scaledSize * setting.scaledSize]; bool[] isOnZone = new bool[setting.scaledSize * setting.scaledSize]; for (int idx = 0; idx < chunk.worldZonesRefs.Count; idx++) { // Only display Completed //if (chunk.worldZonesRefs [idx].isCompleted) { // Be sure this Wolrd zone contain this chunk if (chunk.worldZonesRefs [idx].chunkZones.ContainsKey(chunk.coord)) { for (int chunk_zone_idx = 0; chunk_zone_idx < chunk.worldZonesRefs [idx].chunkZones[chunk.coord].Count; chunk_zone_idx++) { WorldChunkComputed.WorldChunkZone zone = chunk.worldZonesRefs [idx].chunkZones[chunk.coord] [chunk_zone_idx]; foreach (Coord c in zone.coords) { if (zone.type == WorldZoneTypes.Water || zone.type == WorldZoneTypes.Mountain) { isOnZone [c.y * setting.scaledSize + c.x] = true; colourMap [c.y * setting.scaledSize + c.x] = zone.worldZoneRef.randomColor; } } } } //} } for (int y = 0; y < setting.scaledSize; y++) { for (int x = 0; x < setting.scaledSize; x++) { if (!isOnZone [y * setting.scaledSize + x]) { Coord c = new Coord(x, y); float height = chunk.chunkData.GetHeightValue(c, setting); float delta = (height - setting.water) * (1 / (setting.mountain - setting.water)); colourMap [y * setting.scaledSize + x] = Color.Lerp(groundMax, groundMin, delta); } } } return(TextureGenerator.TextureFromColorMap(colourMap, setting.scaledSize)); }