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 <Vector2> meshUv2s = 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; tk2dSpriteDefinition firstSprite = tileMap.SpriteCollectionInst.FirstValidDefinition; bool buildNormals = (firstSprite != null && firstSprite.normals != null && firstSprite.normals.Length > 0); bool generateUv2 = tileMap.data.generateUv2; var colorMode = tileMap.data.colorMode; 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 spriteId = spriteIds[y * tileMap.partitionSizeX + x]; int tile = BuilderUtil.GetTileFromRawTile(spriteId); bool flipH = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipX); bool flipV = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipY); bool rot90 = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.Rot90); 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) { Vector3 flippedPos = BuilderUtil.ApplySpriteVertexTileFlags(tileMap, sprite, sprite.positions[v], flipH, flipV, rot90); if (useColor && colorChunk != null) { 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)]; switch (colorMode) { case tk2dTileMapData.ColorMode.Interpolate: { Vector3 centeredSpriteVertex = flippedPos - 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); break; } case tk2dTileMapData.ColorMode.Solid: { meshColors.Add(tileColorx0y0); break; } } } else { meshColors.Add(clearColor); } if (generateUv2) { if (sprite.normalizedUvs.Length == 0) { meshUv2s.Add(Vector2.zero); } else { meshUv2s.Add(sprite.normalizedUvs[v]); } } meshVertices.Add(currentPos + flippedPos); meshUvs.Add(sprite.uvs[v]); } bool reverseIndices = false; // flipped? if (flipH) { reverseIndices = !reverseIndices; } if (flipV) { reverseIndices = !reverseIndices; } List <int> indices = meshIndices[sprite.materialId]; for (int i = 0; i < sprite.indices.Length; ++i) { int j = reverseIndices ? (sprite.indices.Length - 1 - i) : i; indices.Add(baseVertex + sprite.indices[j]); } } } if (chunk.mesh == null) { chunk.mesh = tk2dUtil.CreateMesh(); } chunk.mesh.Clear(); chunk.mesh.vertices = meshVertices.ToArray(); chunk.mesh.uv = meshUvs.ToArray(); if (generateUv2) { chunk.mesh.uv2 = meshUv2s.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.materialInsts[materialId]); subMeshCount++; } materialId++; } if (subMeshCount > 0) { chunk.mesh.subMeshCount = subMeshCount; chunk.gameObject.GetComponent <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 (buildNormals) { chunk.mesh.RecalculateNormals(); } var meshFilter = chunk.gameObject.GetComponent <MeshFilter>(); meshFilter.sharedMesh = chunk.mesh; }
// Builds an unoptimized mesh for this chunk static void BuildLocalMeshForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY, ref Vector2[] vertices, ref int[] indices) { List <Vector2> verts = new List <Vector2>(); List <int> inds = new List <int>(); Vector2[] boxPos = new Vector2[4]; // used for box collider int[] boxInds = { 0, 1, 1, 2, 2, 3, 3, 0 }; int[] boxIndsFlipped = { 0, 3, 3, 2, 2, 1, 1, 0 }; int spriteCount = tileMap.SpriteCollectionInst.spriteDefinitions.Length; Vector2 tileSize = new Vector3(tileMap.data.tileSize.x, tileMap.data.tileSize.y); var tilePrefabs = tileMap.data.tilePrefabs; float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); var chunkData = chunk.spriteIds; for (int y = 0; y < tileMap.partitionSizeY; ++y) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = 0; x < tileMap.partitionSizeX; ++x) { int spriteId = chunkData[y * tileMap.partitionSizeX + x]; int spriteIdx = BuilderUtil.GetTileFromRawTile(spriteId); Vector2 currentPos = new Vector2(tileSize.x * (x + xOffset), tileSize.y * y); if (spriteIdx < 0 || spriteIdx >= spriteCount) { continue; } if (tilePrefabs[spriteIdx]) { continue; } bool flipH = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipX); bool flipV = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipY); bool rot90 = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.Rot90); bool reverseIndices = false; if (flipH) { reverseIndices = !reverseIndices; } if (flipV) { reverseIndices = !reverseIndices; } tk2dSpriteDefinition spriteData = tileMap.SpriteCollectionInst.spriteDefinitions[spriteIdx]; int baseVertexIndex = verts.Count; if (spriteData.colliderType == tk2dSpriteDefinition.ColliderType.Box) { Vector3 origin = spriteData.colliderVertices[0]; Vector3 extents = spriteData.colliderVertices[1]; Vector3 min = origin - extents; Vector3 max = origin + extents; boxPos[0] = new Vector2(min.x, min.y); boxPos[1] = new Vector2(max.x, min.y); boxPos[2] = new Vector2(max.x, max.y); boxPos[3] = new Vector2(min.x, max.y); for (int i = 0; i < 4; ++i) { verts.Add(BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, boxPos[i], flipH, flipV, rot90) + currentPos); } int[] boxIndices = reverseIndices ? boxIndsFlipped : boxInds; for (int i = 0; i < 8; ++i) { inds.Add(baseVertexIndex + boxIndices[i]); } } else if (spriteData.colliderType == tk2dSpriteDefinition.ColliderType.Mesh) { foreach (tk2dCollider2DData dat in spriteData.edgeCollider2D) { baseVertexIndex = verts.Count; foreach (Vector2 pos in dat.points) { verts.Add(BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, pos, flipH, flipV, rot90) + currentPos); } int numVerts = dat.points.Length; if (reverseIndices) { for (int i = numVerts - 1; i > 0; --i) { inds.Add(baseVertexIndex + i); inds.Add(baseVertexIndex + i - 1); } } else { for (int i = 0; i < numVerts - 1; ++i) { inds.Add(baseVertexIndex + i); inds.Add(baseVertexIndex + i + 1); } } } foreach (tk2dCollider2DData dat in spriteData.polygonCollider2D) { baseVertexIndex = verts.Count; foreach (Vector2 pos in dat.points) { verts.Add(BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, pos, flipH, flipV, rot90) + currentPos); } int numVerts = dat.points.Length; if (reverseIndices) { for (int i = numVerts; i > 0; --i) { inds.Add(baseVertexIndex + (i % numVerts)); inds.Add(baseVertexIndex + i - 1); } } else { for (int i = 0; i < numVerts; ++i) { inds.Add(baseVertexIndex + i); inds.Add(baseVertexIndex + (i + 1) % numVerts); } } } } } } vertices = verts.ToArray(); indices = inds.ToArray(); }
// Builds an unoptimized mesh for this chunk static void BuildLocalMeshForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY, ref Vector3[] vertices, ref int[] indices) { List <Vector3> vertexList = new List <Vector3>(); List <int> indexList = new List <int>(); int spriteCount = tileMap.SpriteCollectionInst.spriteDefinitions.Length; Vector3 tileSize = tileMap.data.tileSize; var tilePrefabs = tileMap.data.tilePrefabs; float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); var chunkData = chunk.spriteIds; for (int y = 0; y < tileMap.partitionSizeY; ++y) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = 0; x < tileMap.partitionSizeX; ++x) { int spriteId = chunkData[y * tileMap.partitionSizeX + x]; int spriteIdx = BuilderUtil.GetTileFromRawTile(spriteId); Vector3 currentPos = new Vector3(tileSize.x * (x + xOffset), tileSize.y * y, 0); if (spriteIdx < 0 || spriteIdx >= spriteCount) { continue; } if (tilePrefabs[spriteIdx]) { continue; } bool flipH = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipX); bool flipV = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipY); bool rot90 = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.Rot90); bool reverseIndices = false; if (flipH) { reverseIndices = !reverseIndices; } if (flipV) { reverseIndices = !reverseIndices; } var spriteData = tileMap.SpriteCollectionInst.spriteDefinitions[spriteIdx]; int baseVertexIndex = vertexList.Count; if (spriteData.colliderType == tk2dSpriteDefinition.ColliderType.Box) { Vector3 origin = spriteData.colliderVertices[0]; Vector3 extents = spriteData.colliderVertices[1]; Vector3 min = origin - extents; Vector3 max = origin + extents; Vector3[] pos = new Vector3[8]; pos[0] = new Vector3(min.x, min.y, min.z); pos[1] = new Vector3(min.x, min.y, max.z); pos[2] = new Vector3(max.x, min.y, min.z); pos[3] = new Vector3(max.x, min.y, max.z); pos[4] = new Vector3(min.x, max.y, min.z); pos[5] = new Vector3(min.x, max.y, max.z); pos[6] = new Vector3(max.x, max.y, min.z); pos[7] = new Vector3(max.x, max.y, max.z); for (int i = 0; i < 8; ++i) { Vector3 flippedPos = BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, pos[i], flipH, flipV, rot90); vertexList.Add(flippedPos + currentPos); } // int[] indicesBack = { 0, 1, 2, 2, 1, 3, 6, 5, 4, 7, 5, 6, 3, 7, 6, 2, 3, 6, 4, 5, 1, 4, 1, 0 }; int[] indicesFwd = { 2, 1, 0, 3, 1, 2, 4, 5, 6, 6, 5, 7, 6, 7, 3, 6, 3, 2, 1, 5, 4, 0, 1, 4 }; var srcIndices = indicesFwd; for (int i = 0; i < srcIndices.Length; ++i) { int j = reverseIndices ? (srcIndices.Length - 1 - i) : i; indexList.Add(baseVertexIndex + srcIndices[j]); } } else if (spriteData.colliderType == tk2dSpriteDefinition.ColliderType.Mesh) { for (int i = 0; i < spriteData.colliderVertices.Length; ++i) { Vector3 flippedPos = BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, spriteData.colliderVertices[i], flipH, flipV, rot90); vertexList.Add(flippedPos + currentPos); } var srcIndices = spriteData.colliderIndicesFwd; for (int i = 0; i < srcIndices.Length; ++i) { int j = reverseIndices ? (srcIndices.Length - 1 - i) : i; indexList.Add(baseVertexIndex + srcIndices[j]); } } } } vertices = vertexList.ToArray(); indices = indexList.ToArray(); }
public static void BuildPolygonCollidersForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY) { // Clear colliders EdgeCollider2D[] edgeColliders = chunk.gameObject.GetComponents <EdgeCollider2D>(); foreach (var ec in edgeColliders) { tk2dUtil.DestroyImmediate(ec); } chunk.edgeColliders.Clear(); PolygonCollider2D[] polyColliders = chunk.gameObject.GetComponents <PolygonCollider2D>(); foreach (var pc in polyColliders) { tk2dUtil.DestroyImmediate(pc); } Vector2[] boxPos = new Vector2[4]; // used for box collider List <List <Vector2> > paths = new List <List <Vector2> >(); int spriteCount = tileMap.SpriteCollectionInst.spriteDefinitions.Length; Vector2 tileSize = new Vector3(tileMap.data.tileSize.x, tileMap.data.tileSize.y); var tilePrefabs = tileMap.data.tilePrefabs; float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); List <Vector2> cachedPoints = new List <Vector2>(); var chunkData = chunk.spriteIds; for (int y = 0; y < tileMap.partitionSizeY; ++y) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = 0; x < tileMap.partitionSizeX; ++x) { int spriteId = chunkData[y * tileMap.partitionSizeX + x]; int spriteIdx = BuilderUtil.GetTileFromRawTile(spriteId); Vector2 currentPos = new Vector2(tileSize.x * (x + xOffset), tileSize.y * y); if (spriteIdx < 0 || spriteIdx >= spriteCount) { continue; } if (tilePrefabs[spriteIdx]) { continue; } bool flipH = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipX); bool flipV = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.FlipY); bool rot90 = BuilderUtil.IsRawTileFlagSet(spriteId, tk2dTileFlags.Rot90); bool reverseIndices = false; if (flipH) { reverseIndices = !reverseIndices; } if (flipV) { reverseIndices = !reverseIndices; } tk2dSpriteDefinition spriteData = tileMap.SpriteCollectionInst.spriteDefinitions[spriteIdx]; if (spriteData.colliderType == tk2dSpriteDefinition.ColliderType.Box) { Vector3 origin = spriteData.colliderVertices[0]; Vector3 extents = spriteData.colliderVertices[1]; Vector3 min = origin - extents; Vector3 max = origin + extents; boxPos[0] = new Vector2(min.x, min.y); boxPos[1] = new Vector2(max.x, min.y); boxPos[2] = new Vector2(max.x, max.y); boxPos[3] = new Vector2(min.x, max.y); List <Vector2> thisList = new List <Vector2>(); int start = reverseIndices ? 3 : 0; int end = reverseIndices ? -1 : 4; int inc = reverseIndices ? -1 : 1; for (int i = start; i != end; i += inc) { thisList.Add(BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, boxPos[i], flipH, flipV, rot90) + currentPos); } paths.Add(thisList); } else if (spriteData.colliderType == tk2dSpriteDefinition.ColliderType.Mesh) { cachedPoints.Clear(); List <Vector2> points = new List <Vector2>(); foreach (tk2dCollider2DData dat in spriteData.polygonCollider2D) { foreach (Vector2 pos in dat.points) { cachedPoints.Add(BuilderUtil.ApplySpriteVertexTileFlags(tileMap, spriteData, pos, flipH, flipV, rot90) + currentPos); } int numVerts = dat.points.Length; if (reverseIndices) { for (int i = cachedPoints.Count - 1; i >= 0; --i) { points.Add(cachedPoints[i]); } } else { for (int i = 0; i < numVerts; ++i) { points.Add(cachedPoints[i]); } } } paths.Add(points); } } } int numPathsPerObject = 64; int startPath = 0; int pathsRemaining = paths.Count; while (pathsRemaining > 0) { int pathsThisRound = Mathf.Min(numPathsPerObject, pathsRemaining); PolygonCollider2D newPc = chunk.gameObject.AddComponent <PolygonCollider2D>(); newPc.pathCount = pathsThisRound; for (int i = 0; i < pathsThisRound; ++i) { newPc.SetPath(i, paths[startPath + i].ToArray()); } startPath += pathsThisRound; pathsRemaining -= pathsThisRound; } }