public static void BuildForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY) { // Build local mesh Vector3[] localMeshVertices = new Vector3[0]; int[] localMeshIndices = new int[0]; BuildLocalMeshForChunk(tileMap, chunk, baseX, baseY, ref localMeshVertices, ref localMeshIndices); // only process when there are more than two triangles // avoids a lot of branches later if (localMeshIndices.Length > 6) { // Remove duplicate verts localMeshVertices = WeldVertices(localMeshVertices, ref localMeshIndices); // Remove duplicate and back-to-back faces // Removes inside faces localMeshIndices = RemoveDuplicateFaces(localMeshIndices); // Merge coplanar faces // Optimize (remove unused vertices, reindex) } if (localMeshVertices.Length > 0) { if (chunk.colliderMesh != null) { GameObject.DestroyImmediate(chunk.colliderMesh); chunk.colliderMesh = null; } if (chunk.meshCollider == null) { chunk.meshCollider = chunk.gameObject.GetComponent <MeshCollider>(); if (chunk.meshCollider == null) { chunk.meshCollider = chunk.gameObject.AddComponent <MeshCollider>(); } } chunk.colliderMesh = tileMap.GetOrCreateMesh(); chunk.colliderMesh.vertices = localMeshVertices; chunk.colliderMesh.triangles = localMeshIndices; chunk.colliderMesh.RecalculateBounds(); if (tileMap.serializeRenderData) { chunk.mesh.RecalculateNormals(); } chunk.meshCollider.sharedMesh = chunk.colliderMesh; } else { chunk.DestroyColliderData(tileMap); } }
public static void BuildForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY) { // Build local mesh Vector3[] localMeshVertices = new Vector3[0]; int[] localMeshIndices = new int[0]; BuildLocalMeshForChunk(tileMap, chunk, baseX, baseY, ref localMeshVertices, ref localMeshIndices); // only process when there are more than two triangles // avoids a lot of branches later if (localMeshIndices.Length > 6) { // Remove duplicate verts localMeshVertices = WeldVertices(localMeshVertices, ref localMeshIndices); // Remove duplicate and back-to-back faces // Removes inside faces localMeshIndices = RemoveDuplicateFaces(localMeshIndices); // Merge coplanar faces // Optimize (remove unused vertices, reindex) } if (localMeshVertices.Length > 0) { if (chunk.colliderMesh != null) { GameObject.DestroyImmediate(chunk.colliderMesh); chunk.colliderMesh = null; } if (chunk.meshCollider == null) { chunk.meshCollider = chunk.gameObject.GetComponent<MeshCollider>(); if (chunk.meshCollider == null) chunk.meshCollider = chunk.gameObject.AddComponent<MeshCollider>(); } chunk.colliderMesh = tileMap.GetOrCreateMesh(); chunk.colliderMesh.vertices = localMeshVertices; chunk.colliderMesh.triangles = localMeshIndices; chunk.colliderMesh.RecalculateBounds(); if (tileMap.serializeRenderData) chunk.mesh.RecalculateNormals(); chunk.meshCollider.sharedMesh = chunk.colliderMesh; } else { chunk.DestroyColliderData(tileMap); } }
public static void BuildForChunk(tk2dTileMap tileMap, SpriteChunk chunk, ColorChunk colorChunk, bool useColor, bool skipPrefabs, int baseX, int baseY) { List <Vector3> meshVertices = new List <Vector3>(); List <Color> meshColors = new List <Color>(); List <Vector2> meshUvs = new List <Vector2>(); //List<int> meshIndices = new List<int>(); int[] spriteIds = chunk.spriteIds; Vector3 tileSize = tileMap.data.tileSize; int spriteCount = tileMap.SpriteCollectionInst.spriteDefinitions.Length; Object[] tilePrefabs = tileMap.data.tilePrefabs; Color32 clearColor = (useColor && tileMap.ColorChannel != null)?tileMap.ColorChannel.clearColor:Color.white; // revert to no color mode (i.e. fill with clear color) when there isn't a color channel, or it is empty if (colorChunk == null || colorChunk.colors.Length == 0) { useColor = false; } int x0, x1, dx; int y0, y1, dy; BuilderUtil.GetLoopOrder(tileMap.data.sortMethod, tileMap.partitionSizeX, tileMap.partitionSizeY, out x0, out x1, out dx, out y0, out y1, out dy); float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); List <int>[] meshIndices = new List <int> [tileMap.SpriteCollectionInst.materials.Length]; for (int j = 0; j < meshIndices.Length; ++j) { meshIndices[j] = new List <int>(); } int colorChunkSize = tileMap.partitionSizeX + 1; for (int y = y0; y != y1; y += dy) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = x0; x != x1; x += dx) { int tile = spriteIds[y * tileMap.partitionSizeX + x]; Vector3 currentPos = new Vector3(tileSize.x * (x + xOffset), tileSize.y * y, 0); if (tile < 0 || tile >= spriteCount) { continue; } if (skipPrefabs && tilePrefabs[tile]) { continue; } var sprite = tileMap.SpriteCollectionInst.spriteDefinitions[tile]; int baseVertex = meshVertices.Count; for (int v = 0; v < sprite.positions.Length; ++v) { if (useColor) { Color tileColorx0y0 = colorChunk.colors[y * colorChunkSize + x]; Color tileColorx1y0 = colorChunk.colors[y * colorChunkSize + x + 1]; Color tileColorx0y1 = colorChunk.colors[(y + 1) * colorChunkSize + x]; Color tileColorx1y1 = colorChunk.colors[(y + 1) * colorChunkSize + (x + 1)]; Vector3 centeredSpriteVertex = sprite.positions[v] - sprite.untrimmedBoundsData[0]; Vector3 alignedSpriteVertex = centeredSpriteVertex + tileMap.data.tileSize * 0.5f; float tileColorX = Mathf.Clamp01(alignedSpriteVertex.x / tileMap.data.tileSize.x); float tileColorY = Mathf.Clamp01(alignedSpriteVertex.y / tileMap.data.tileSize.y); Color color = Color.Lerp( Color.Lerp(tileColorx0y0, tileColorx1y0, tileColorX), Color.Lerp(tileColorx0y1, tileColorx1y1, tileColorX), tileColorY); meshColors.Add(color); } else { meshColors.Add(clearColor); } meshVertices.Add(currentPos + sprite.positions[v]); meshUvs.Add(sprite.uvs[v]); } List <int> indices = meshIndices[sprite.materialId]; for (int i = 0; i < sprite.indices.Length; ++i) { indices.Add(baseVertex + sprite.indices[i]); } } } if (chunk.mesh == null) { chunk.mesh = tileMap.GetOrCreateMesh(); } chunk.mesh.vertices = meshVertices.ToArray(); chunk.mesh.uv = meshUvs.ToArray(); chunk.mesh.colors = meshColors.ToArray(); List <Material> materials = new List <Material>(); int materialId = 0; int subMeshCount = 0; foreach (var indices in meshIndices) { if (indices.Count > 0) { materials.Add(tileMap.SpriteCollectionInst.materials[materialId]); subMeshCount++; } materialId++; } if (subMeshCount > 0) { chunk.mesh.subMeshCount = subMeshCount; chunk.gameObject.renderer.materials = materials.ToArray(); int subMeshId = 0; foreach (var indices in meshIndices) { if (indices.Count > 0) { chunk.mesh.SetTriangles(indices.ToArray(), subMeshId); subMeshId++; } } } chunk.mesh.RecalculateBounds(); if (tileMap.serializeRenderData) { chunk.mesh.RecalculateNormals(); } var meshFilter = chunk.gameObject.GetComponent <MeshFilter>(); meshFilter.sharedMesh = chunk.mesh; }
/// Creates render data for given tilemap public static void CreateRenderData(tk2dTileMap tileMap, bool editMode) { // Create render data if (tileMap.renderData == null) tileMap.renderData = new GameObject(tileMap.name + " Render Data"); tileMap.renderData.transform.position = tileMap.transform.position; float accumulatedLayerZ = 0.0f; // Create all objects int layerId = 0; foreach (var layer in tileMap.Layers) { // We skip offsetting the first one if (layerId != 0) accumulatedLayerZ -= tileMap.data.Layers[layerId].z; if (layer.IsEmpty && layer.gameObject != null) { GameObject.DestroyImmediate(layer.gameObject); layer.gameObject = null; } else if (!layer.IsEmpty && layer.gameObject == null) { var go = layer.gameObject = new GameObject(""); go.transform.parent = tileMap.renderData.transform; } int unityLayer = tileMap.data.Layers[layerId].unityLayer; if (layer.gameObject != null) { #if UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9 if (!editMode && layer.gameObject.active == false) layer.gameObject.SetActiveRecursively(true); #else if (!editMode && layer.gameObject.activeSelf == false) layer.gameObject.SetActive(true); #endif layer.gameObject.name = tileMap.data.Layers[layerId].name; layer.gameObject.transform.localPosition = new Vector3(0, 0, accumulatedLayerZ); layer.gameObject.transform.localRotation = Quaternion.identity; layer.gameObject.transform.localScale = Vector3.one; layer.gameObject.layer = unityLayer; } int x0, x1, dx; int y0, y1, dy; BuilderUtil.GetLoopOrder(tileMap.data.sortMethod, layer.numColumns, layer.numRows, out x0, out x1, out dx, out y0, out y1, out dy); float z = 0.0f; for (int y = y0; y != y1; y += dy) { for (int x = x0; x != x1; x += dx) { var chunk = layer.GetChunk(x, y); bool isEmpty = layer.IsEmpty || chunk.IsEmpty; if (isEmpty && chunk.HasGameData) { chunk.DestroyGameData(tileMap); } else if (!isEmpty && chunk.gameObject == null) { string chunkName = "Chunk " + y.ToString() + " " + x.ToString(); var go = chunk.gameObject = new GameObject(chunkName); go.transform.parent = layer.gameObject.transform; // render mesh MeshFilter meshFilter = go.AddComponent<MeshFilter>(); go.AddComponent<MeshRenderer>(); chunk.mesh = tileMap.GetOrCreateMesh(); meshFilter.mesh = chunk.mesh; // collider mesh chunk.meshCollider = go.AddComponent<MeshCollider>(); chunk.meshCollider.sharedMesh = null; chunk.colliderMesh = null; } if (chunk.gameObject != null) { Vector3 tilePosition = GetTilePosition(tileMap, x * tileMap.partitionSizeX, y * tileMap.partitionSizeY); tilePosition.z += z; chunk.gameObject.transform.localPosition = tilePosition; chunk.gameObject.transform.localRotation = Quaternion.identity; chunk.gameObject.transform.localScale = Vector3.one; chunk.gameObject.layer = unityLayer; // We won't be generating collider data in edit mode, so clear everything if (editMode) { if (chunk.colliderMesh) chunk.DestroyColliderData(tileMap); } } z -= 0.000001f; } } ++layerId; } }
public static void BuildForChunk(tk2dTileMap tileMap, SpriteChunk chunk, ColorChunk colorChunk, bool useColor, bool skipPrefabs, int baseX, int baseY) { List<Vector3> meshVertices = new List<Vector3>(); List<Color> meshColors = new List<Color>(); List<Vector2> meshUvs = new List<Vector2>(); //List<int> meshIndices = new List<int>(); int[] spriteIds = chunk.spriteIds; Vector3 tileSize = tileMap.data.tileSize; int spriteCount = tileMap.spriteCollection.spriteDefinitions.Length; Object[] tilePrefabs = tileMap.data.tilePrefabs; Color32 clearColor = (useColor && tileMap.ColorChannel != null)?tileMap.ColorChannel.clearColor:Color.white; // revert to no color mode (i.e. fill with clear color) when there isn't a color channel, or it is empty if (colorChunk == null || colorChunk.colors.Length == 0) useColor = false; int x0, x1, dx; int y0, y1, dy; BuilderUtil.GetLoopOrder(tileMap.data.sortMethod, tileMap.partitionSizeX, tileMap.partitionSizeY, out x0, out x1, out dx, out y0, out y1, out dy); float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); List<int>[] meshIndices = new List<int>[tileMap.spriteCollection.materials.Length]; for (int j = 0; j < meshIndices.Length; ++j) meshIndices[j] = new List<int>(); int colorChunkSize = tileMap.partitionSizeX + 1; for (int y = y0; y != y1; y += dy) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = x0; x != x1; x += dx) { int tile = spriteIds[y * tileMap.partitionSizeX + x]; Vector3 currentPos = new Vector3(tileSize.x * (x + xOffset), tileSize.y * y, 0); if (tile < 0 || tile >= spriteCount) continue; if (skipPrefabs && tilePrefabs[tile]) continue; var sprite = tileMap.spriteCollection.spriteDefinitions[tile]; int baseVertex = meshVertices.Count; for (int v = 0; v < sprite.positions.Length; ++v) { if (useColor) { Color tileColorx0y0 = colorChunk.colors[y * colorChunkSize + x]; Color tileColorx1y0 = colorChunk.colors[y * colorChunkSize + x + 1]; Color tileColorx0y1 = colorChunk.colors[(y + 1) * colorChunkSize + x]; Color tileColorx1y1 = colorChunk.colors[(y + 1) * colorChunkSize + (x + 1)]; Vector3 centeredSpriteVertex = sprite.positions[v] - sprite.untrimmedBoundsData[0]; Vector3 alignedSpriteVertex = centeredSpriteVertex + tileMap.data.tileSize * 0.5f; float tileColorX = Mathf.Clamp01(alignedSpriteVertex.x / tileMap.data.tileSize.x); float tileColorY = Mathf.Clamp01(alignedSpriteVertex.y / tileMap.data.tileSize.y); Color color = Color.Lerp( Color.Lerp(tileColorx0y0, tileColorx1y0, tileColorX), Color.Lerp(tileColorx0y1, tileColorx1y1, tileColorX), tileColorY); meshColors.Add(color); } else { meshColors.Add(clearColor); } meshVertices.Add(currentPos + sprite.positions[v]); meshUvs.Add(sprite.uvs[v]); } List<int> indices = meshIndices[sprite.materialId]; for (int i = 0; i < sprite.indices.Length; ++i) indices.Add(baseVertex + sprite.indices[i]); } } if (chunk.mesh == null) chunk.mesh = tileMap.GetOrCreateMesh(); chunk.mesh.vertices = meshVertices.ToArray(); chunk.mesh.uv = meshUvs.ToArray(); chunk.mesh.colors = meshColors.ToArray(); List<Material> materials = new List<Material>(); int materialId = 0; int subMeshCount = 0; foreach (var indices in meshIndices) { if (indices.Count > 0) { materials.Add(tileMap.spriteCollection.materials[materialId]); subMeshCount++; } materialId++; } if (subMeshCount > 0) { chunk.mesh.subMeshCount = subMeshCount; chunk.gameObject.renderer.materials = materials.ToArray(); int subMeshId = 0; foreach (var indices in meshIndices) { if (indices.Count > 0) { chunk.mesh.SetTriangles(indices.ToArray(), subMeshId); subMeshId++; } } } chunk.mesh.RecalculateBounds(); if (tileMap.serializeRenderData) chunk.mesh.RecalculateNormals(); var meshFilter = chunk.gameObject.GetComponent<MeshFilter>(); meshFilter.sharedMesh = chunk.mesh; }
/// Creates render data for given tilemap public static void CreateRenderData(tk2dTileMap tileMap, bool editMode) { // Create render data if (tileMap.renderData == null) { tileMap.renderData = new GameObject(tileMap.name + " Render Data"); } tileMap.renderData.transform.position = tileMap.transform.position; float accumulatedLayerZ = 0.0f; // Create all objects int layerId = 0; foreach (var layer in tileMap.Layers) { // We skip offsetting the first one if (layerId != 0) { accumulatedLayerZ -= tileMap.data.Layers[layerId].z; } if (layer.IsEmpty && layer.gameObject != null) { GameObject.DestroyImmediate(layer.gameObject); layer.gameObject = null; } else if (!layer.IsEmpty && layer.gameObject == null) { var go = layer.gameObject = new GameObject(""); go.transform.parent = tileMap.renderData.transform; } int unityLayer = tileMap.data.Layers[layerId].unityLayer; if (layer.gameObject != null) { #if UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9 if (!editMode && layer.gameObject.active == false) { layer.gameObject.SetActiveRecursively(true); } #else if (!editMode && layer.gameObject.activeSelf == false) { layer.gameObject.SetActive(true); } #endif layer.gameObject.name = tileMap.data.Layers[layerId].name; layer.gameObject.transform.localPosition = new Vector3(0, 0, accumulatedLayerZ); layer.gameObject.transform.localRotation = Quaternion.identity; layer.gameObject.transform.localScale = Vector3.one; layer.gameObject.layer = unityLayer; } int x0, x1, dx; int y0, y1, dy; BuilderUtil.GetLoopOrder(tileMap.data.sortMethod, layer.numColumns, layer.numRows, out x0, out x1, out dx, out y0, out y1, out dy); float z = 0.0f; for (int y = y0; y != y1; y += dy) { for (int x = x0; x != x1; x += dx) { var chunk = layer.GetChunk(x, y); bool isEmpty = layer.IsEmpty || chunk.IsEmpty; if (isEmpty && chunk.HasGameData) { chunk.DestroyGameData(tileMap); } else if (!isEmpty && chunk.gameObject == null) { string chunkName = "Chunk " + y.ToString() + " " + x.ToString(); var go = chunk.gameObject = new GameObject(chunkName); go.transform.parent = layer.gameObject.transform; // render mesh MeshFilter meshFilter = go.AddComponent <MeshFilter>(); go.AddComponent <MeshRenderer>(); chunk.mesh = tileMap.GetOrCreateMesh(); meshFilter.mesh = chunk.mesh; // collider mesh chunk.meshCollider = go.AddComponent <MeshCollider>(); chunk.meshCollider.sharedMesh = null; chunk.colliderMesh = null; } if (chunk.gameObject != null) { Vector3 tilePosition = GetTilePosition(tileMap, x * tileMap.partitionSizeX, y * tileMap.partitionSizeY); tilePosition.z += z; chunk.gameObject.transform.localPosition = tilePosition; chunk.gameObject.transform.localRotation = Quaternion.identity; chunk.gameObject.transform.localScale = Vector3.one; chunk.gameObject.layer = unityLayer; // We won't be generating collider data in edit mode, so clear everything if (editMode) { if (chunk.colliderMesh) { chunk.DestroyColliderData(tileMap); } } } z -= 0.000001f; } } ++layerId; } }