public void DestroyColliderData(tk2dTileMap tileMap) { if (this.colliderMesh != null) { tileMap.DestroyMesh(this.colliderMesh); } if (((this.meshCollider != null) && (this.meshCollider.sharedMesh != null)) && (this.meshCollider.sharedMesh != this.colliderMesh)) { tileMap.DestroyMesh(this.meshCollider.sharedMesh); } if (this.meshCollider != null) { tk2dUtil.DestroyImmediate(this.meshCollider); } this.meshCollider = null; this.colliderMesh = null; if (this.edgeColliders.Count > 0) { for (int i = 0; i < this.edgeColliders.Count; i++) { tk2dUtil.DestroyImmediate(this.edgeColliders[i]); } this.edgeColliders.Clear(); } }
//////////////////////////////////////////////////////////////////////////////////////////////// /// Static and helper functions //////////////////////////////////////////////////////////////////////////////////////////////// public static bool Import(tk2dTileMap tileMap, Format format) { var importer = new Importer(); string ext = ""; switch (format) { case Format.TMX: if (!importer.CheckZlib()) return false; ext = "tmx"; break; } string path = EditorUtility.OpenFilePanel("Import tilemap", "", ext); if (path.Length == 0) return false; string message = ""; switch (format) { case Format.TMX: message = importer.ImportTMX(path); break; } if (message.Length != 0) { EditorUtility.DisplayDialog("Tilemap failed to import", message, "Ok"); return false; } importer.PopulateTilemap(tileMap); return true; }
public static void Build(tk2dTileMap tileMap) { int numLayers = tileMap.Layers.Length; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; if (layer.IsEmpty || !tileMap.data.Layers[layerId].generateCollider) continue; for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); if (chunk.IsEmpty) continue; BuildForChunk(tileMap, chunk, baseX, baseY); } } } }
public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; float maxScreenWidth = Screen.width - 16; if (width > maxScreenWidth) { height = height * maxScreenWidth / width; width = maxScreenWidth; } Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { tileMap.spriteCollection.materials[0].SetPass(0); Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.spriteCollection.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix); } return rect; }
public static void Build(tk2dTileMap tileMap, bool forceBuild) { bool incremental = !forceBuild; int numLayers = tileMap.Layers.Length; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; if (layer.IsEmpty || !tileMap.data.Layers[layerId].generateCollider) continue; for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); if (incremental && !chunk.Dirty) continue; if (chunk.IsEmpty) continue; BuildForChunk(tileMap, chunk, baseX, baseY); PhysicMaterial material = tileMap.data.Layers[layerId].physicMaterial; if (chunk.meshCollider != null) { chunk.meshCollider.sharedMaterial = material; } } } } }
// Returns index of newly added layer public static int AddNewLayer(tk2dTileMap tileMap) { var existingLayers = tileMap.data.Layers; // find a unique hash bool duplicateHash = false; int hash; do { duplicateHash = false; hash = Random.Range(0, int.MaxValue); foreach (var layer in existingLayers) if (layer.hash == hash) duplicateHash = true; } while (duplicateHash == true); var newLayer = new tk2dRuntime.TileMap.LayerInfo(); newLayer.name = "New Layer"; newLayer.hash = hash; newLayer.z = 0.1f; tileMap.data.tileMapLayers.Add(newLayer); // remap tilemap tk2dRuntime.TileMap.BuilderUtil.InitDataStore(tileMap); return tileMap.data.NumLayers - 1; }
public static void ResizeTileMap(tk2dTileMap tileMap, int width, int height, int partitionSizeX, int partitionSizeY) { int w = Mathf.Clamp(width, 1, MaxWidth); int h = Mathf.Clamp(height, 1, MaxHeight); tk2dRuntime.TileMap.BuilderUtil.InitDataStore(tileMap); // copy into new tilemap Layer[] layers = new Layer[tileMap.Layers.Length]; for (int layerId = 0; layerId < tileMap.Layers.Length; ++layerId) { var srcLayer = tileMap.Layers[layerId]; layers[layerId] = new Layer(srcLayer.hash, width, height, partitionSizeX, partitionSizeY); var destLayer = layers[layerId]; if (srcLayer.IsEmpty) continue; int hcopy = Mathf.Min(tileMap.height, h); int wcopy = Mathf.Min(tileMap.width, w); for (int y = 0; y < hcopy; ++y) { for (int x = 0; x < wcopy; ++x) { destLayer.SetTile(x, y, srcLayer.GetTile(x, y)); } } destLayer.Optimize(); } // copy new colors bool copyColors = (tileMap.ColorChannel != null && !tileMap.ColorChannel.IsEmpty); ColorChannel targetColors = new ColorChannel(width, height, partitionSizeX, partitionSizeY); if (copyColors) { int hcopy = Mathf.Min(tileMap.height, h) + 1; int wcopy = Mathf.Min(tileMap.width, w) + 1; for (int y = 0; y < hcopy; ++y) { for (int x = 0; x < wcopy; ++x) { targetColors.SetColor(x, y, tileMap.ColorChannel.GetColor(x, y)); } } targetColors.Optimize(); } tileMap.ColorChannel = targetColors; tileMap.Layers = layers; tileMap.width = w; tileMap.height = h; tileMap.partitionSizeX = partitionSizeX; tileMap.partitionSizeY = partitionSizeY; tk2dRuntime.TileMap.BuilderUtil.CleanRenderData(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 !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) foreach (EdgeCollider2D c2d in chunk.edgeColliders) { if (c2d != null) { tk2dUtil.DestroyImmediate(c2d); } } chunk.edgeColliders.Clear(); #endif if (localMeshVertices.Length > 0) { if (chunk.colliderMesh != null) { tk2dUtil.DestroyImmediate(chunk.colliderMesh); chunk.colliderMesh = null; } if (chunk.meshCollider == null) { chunk.meshCollider = chunk.gameObject.GetComponent<MeshCollider>(); if (chunk.meshCollider == null) chunk.meshCollider = tk2dUtil.AddComponent<MeshCollider>(chunk.gameObject); } chunk.colliderMesh = tk2dUtil.CreateMesh(); chunk.colliderMesh.vertices = localMeshVertices; chunk.colliderMesh.triangles = localMeshIndices; chunk.colliderMesh.RecalculateBounds(); chunk.meshCollider.sharedMesh = chunk.colliderMesh; } else { chunk.DestroyColliderData(tileMap); } }
public static void MoveLayer(tk2dTileMap tileMap, int layer, int direction) { tk2dRuntime.TileMap.BuilderUtil.CleanRenderData(tileMap); var tmp = tileMap.data.tileMapLayers[layer]; tileMap.data.tileMapLayers[layer] = tileMap.data.tileMapLayers[layer + direction]; tileMap.data.tileMapLayers[layer + direction] = tmp; tk2dRuntime.TileMap.BuilderUtil.InitDataStore(tileMap); }
public void DestroyGameData(tk2dTileMap tileMap) { if (mesh != null) tileMap.DestroyMesh(mesh); if (gameObject != null) GameObject.DestroyImmediate(gameObject); gameObject = null; mesh = null; DestroyColliderData(tileMap); }
public static void DeleteLayer(tk2dTileMap tileMap, int layerToDelete) { // Just in case if (tileMap.data.NumLayers <= 1) return; tk2dRuntime.TileMap.BuilderUtil.CleanRenderData(tileMap); tileMap.data.tileMapLayers.RemoveAt(layerToDelete); tk2dRuntime.TileMap.BuilderUtil.InitDataStore(tileMap); }
public void DestroyColliderData(tk2dTileMap tileMap) { if (colliderMesh != null) tileMap.DestroyMesh(colliderMesh); if (meshCollider != null && meshCollider.sharedMesh != null && meshCollider.sharedMesh != colliderMesh) tileMap.DestroyMesh(meshCollider.sharedMesh); if (meshCollider != null) GameObject.DestroyImmediate(meshCollider); meshCollider = null; colliderMesh = null; }
public static void Build(tk2dTileMap tileMap, bool editMode, bool forceBuild) { bool skipPrefabs = !editMode; bool flag2 = !forceBuild; int numLayers = tileMap.data.NumLayers; for (int i = 0; i < numLayers; i++) { Layer layer = tileMap.Layers[i]; if (!layer.IsEmpty) { LayerInfo info = tileMap.data.Layers[i]; bool useColor = !tileMap.ColorChannel.IsEmpty && tileMap.data.Layers[i].useColor; bool useSortingLayers = tileMap.data.useSortingLayers; for (int j = 0; j < layer.numRows; j++) { int baseY = j * layer.divY; for (int k = 0; k < layer.numColumns; k++) { int baseX = k * layer.divX; SpriteChunk chunk = layer.GetChunk(k, j); ColorChunk colorChunk = tileMap.ColorChannel.GetChunk(k, j); bool flag5 = (colorChunk != null) && colorChunk.Dirty; if ((!flag2 || flag5) || chunk.Dirty) { if (chunk.mesh != null) { chunk.mesh.Clear(); } if (!chunk.IsEmpty) { if (editMode || (!editMode && !info.skipMeshGeneration)) { BuildForChunk(tileMap, chunk, colorChunk, useColor, skipPrefabs, baseX, baseY); if ((chunk.gameObject != null) && useSortingLayers) { Renderer renderer = chunk.gameObject.renderer; if (renderer != null) { renderer.sortingLayerName = info.sortingLayerName; renderer.sortingOrder = info.sortingOrder; } } } if (chunk.mesh != null) { tileMap.TouchMesh(chunk.mesh); } } } } } } } }
static GameObject GetExistingTilePrefabInstance(tk2dTileMap tileMap, int tileX, int tileY, int tileLayer) { int n = tileMap.GetTilePrefabsListCount(); for (int i = 0; i < n; ++i) { int x, y, layer; GameObject instance; tileMap.GetTilePrefabsListItem(i, out x, out y, out layer, out instance); if (x == tileX && y == tileY && layer == tileLayer) return instance; } return null; }
public void DestroyGameData(tk2dTileMap tilemap) { foreach (SpriteChunk chunk in this.spriteChannel.chunks) { if (chunk.HasGameData) { chunk.DestroyColliderData(tilemap); chunk.DestroyGameData(tilemap); } } }
public static void BuildForChunk(tk2dTileMap tileMap, SpriteChunk chunk) { // Build local mesh Vector3[] localMeshVertices = new Vector3[0]; int[] localMeshIndices = new int[0]; BuildLocalMeshForChunk(tileMap, chunk, 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); } }
/* Farseer user data string to give to each box collider fixture. */ //private string userData = "Environment"; // TODO: implement. /* Farseer user tag string to give to each box collider fixture. */ //private string userTag = "Environment"; // TODO: implement. /* This is called first in the Unity execution order of events, adding new Farseer colliders * to the tilemap before the Farseer physics engine begins. */ void Awake() { tilemap = GetComponent<tk2dTileMap>(); spriteDefinitions = tilemap.SpriteCollectionInst.spriteDefinitions; tileWidth = tilemap.data.tileSize.x; tileHeight = tilemap.data.tileSize.y; maxTilesY = Mathf.Min(tilemap.partitionSizeY, tilemap.height); maxTilesX = Mathf.Min(tilemap.partitionSizeX, tilemap.width); GenerateColliders(); }
public static int FindOrCreateLayer(tk2dTileMap tileMap, string name) { int index = 0; foreach (var v in tileMap.data.Layers) { if (v.name == name) return index; ++index; } index = AddNewLayer(tileMap); tileMap.data.Layers[index].name = name; return index; }
public tk2dTileMapSceneGUI(ITileMapEditorHost host, tk2dTileMap tileMap, tk2dTileMapEditorData editorData) { this.host = host; this.tileMap = tileMap; this.editorData = editorData; this.tileMapData = tileMap.data; // create default brush if (tileMap.spriteCollection && this.editorData) { this.editorData.InitBrushes(tileMap.spriteCollection); EditorUtility.SetDirty(this.editorData); } }
public void DestroyGameData(tk2dTileMap tileMap) { if (this.mesh != null) { tileMap.DestroyMesh(this.mesh); } if (this.gameObject != null) { tk2dUtil.DestroyImmediate(this.gameObject); } this.gameObject = null; this.mesh = null; this.DestroyColliderData(tileMap); }
/// Deletes all generated instances public static void CleanRenderData(tk2dTileMap tileMap) { if (tileMap.renderData == null) return; // To Do: Move all prefabs to the "Prefabs" object. (Then don't add to children list) // Build a list of all children // All children will appear after the parent int currentProcessedChild = 0; List<Transform> children = new List<Transform>(); children.Add(tileMap.renderData.transform); while (currentProcessedChild < children.Count) { var thisChild = children[currentProcessedChild++]; int childCount = thisChild.childCount; for (int i = 0; i < childCount; ++i) children.Add(thisChild.GetChild(i)); } currentProcessedChild = children.Count - 1; while (currentProcessedChild > 0) // skip very first as it is the root object { var go = children[currentProcessedChild--].gameObject; MeshFilter mf = go.GetComponent<MeshFilter>(); if (mf != null) { if (mf.sharedMesh != null && !EditorUtility.IsPersistent(mf.sharedMesh)) { Mesh mesh = mf.sharedMesh; mf.sharedMesh = null; tileMap.DestroyMesh(mesh); } } MeshCollider meshCollider = go.GetComponent<MeshCollider>(); if (meshCollider) { if (meshCollider.sharedMesh != null && !EditorUtility.IsPersistent(meshCollider.sharedMesh)) { Mesh mesh = meshCollider.sharedMesh; meshCollider.sharedMesh = null; tileMap.DestroyMesh(mesh); } } GameObject.DestroyImmediate(go); } }
/// Spawns all prefabs for a given tilemap /// Expects populated chunks to have valid GameObjects public static void SpawnPrefabs(tk2dTileMap tileMap, bool forceBuild) { // Restart these lists that will be stored in the tileMap tilePrefabsList TilePrefabsX = new List <int>(); TilePrefabsY = new List <int>(); TilePrefabsLayer = new List <int>(); TilePrefabsInstance = new List <GameObject>(); int[] prefabCounts = new int[tileMap.data.tilePrefabs.Length]; int numLayers = tileMap.Layers.Length; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; var layerData = tileMap.data.Layers[layerId]; // We skip offsetting the first one if (layer.IsEmpty || layerData.skipMeshGeneration) { continue; } for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); if (chunk.IsEmpty) { continue; } if (!forceBuild && !chunk.Dirty) { continue; } SpawnPrefabsForChunk(tileMap, chunk, baseX, baseY, layerId, prefabCounts); } } } tileMap.SetTilePrefabsList(TilePrefabsX, TilePrefabsY, TilePrefabsLayer, TilePrefabsInstance); }
public static Vector3 ApplySpriteVertexTileFlags(tk2dTileMap tileMap, tk2dSpriteDefinition spriteDef, Vector3 pos, bool flipH, bool flipV, bool rot90) { float cx = tileMap.data.tileOrigin.x + 0.5f * tileMap.data.tileSize.x; float cy = tileMap.data.tileOrigin.y + 0.5f * tileMap.data.tileSize.y; float dx = pos.x - cx; float dy = pos.y - cy; if (rot90) { float tmp = dx; dx = dy; dy = -tmp; } if (flipH) dx *= -1.0f; if (flipV) dy *= -1.0f; pos.x = cx + dx; pos.y = cy + dy; return pos; }
public void DestroyColliderData(tk2dTileMap tileMap) { if (colliderMesh != null) { tileMap.DestroyMesh(colliderMesh); } if (meshCollider != null && meshCollider.sharedMesh != null && meshCollider.sharedMesh != colliderMesh) { tileMap.DestroyMesh(meshCollider.sharedMesh); } if (meshCollider != null) { GameObject.DestroyImmediate(meshCollider); } meshCollider = null; colliderMesh = null; }
static void Create() { tk2dSpriteCollectionData sprColl = null; if (sprColl == null) { // try to inherit from other TileMaps in scene tk2dTileMap sceneTileMaps = GameObject.FindObjectOfType(typeof(tk2dTileMap)) as tk2dTileMap; if (sceneTileMaps) { sprColl = sceneTileMaps.Editor__SpriteCollection; } } if (sprColl == null) { tk2dSpriteCollectionIndex[] spriteCollections = tk2dEditorUtility.GetOrCreateIndex().GetSpriteCollectionIndex(); foreach (var v in spriteCollections) { if (v.managedSpriteCollection) continue; // don't wanna pick a managed one GameObject scgo = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(v.spriteCollectionDataGUID), typeof(GameObject)) as GameObject; var sc = scgo.GetComponent<tk2dSpriteCollectionData>(); if (sc != null && sc.spriteDefinitions != null && sc.spriteDefinitions.Length > 0 && sc.allowMultipleAtlases == false) { sprColl = sc; break; } } if (sprColl == null) { EditorUtility.DisplayDialog("Create TileMap", "Unable to create sprite as no SpriteCollections have been found.", "Ok"); return; } } GameObject go = tk2dEditorUtility.CreateGameObjectInScene("TileMap"); go.transform.position = Vector3.zero; go.transform.rotation = Quaternion.identity; tk2dTileMap tileMap = go.AddComponent<tk2dTileMap>(); tileMap.BeginEditMode(); Selection.activeGameObject = go; Undo.RegisterCreatedObjectUndo(go, "Create TileMap"); }
public static void Build(tk2dTileMap tileMap, bool editMode, bool forceBuild) { bool skipPrefabs = editMode?false:true; bool incremental = !forceBuild; int numLayers = tileMap.data.NumLayers; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; if (layer.IsEmpty) continue; var layerData = tileMap.data.Layers[layerId]; bool useColor = !tileMap.ColorChannel.IsEmpty && tileMap.data.Layers[layerId].useColor; for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); ColorChunk colorChunk = tileMap.ColorChannel.GetChunk(cellX, cellY); bool colorChunkDirty = (colorChunk != null) && colorChunk.Dirty; if (incremental && !colorChunkDirty && !chunk.Dirty) continue; if (chunk.mesh != null) chunk.mesh.Clear(); if (chunk.IsEmpty) continue; if (editMode || (!editMode && !layerData.skipMeshGeneration)) BuildForChunk(tileMap, chunk, colorChunk, useColor, skipPrefabs, baseX, baseY); if (chunk.mesh != null) tileMap.TouchMesh(chunk.mesh); } } } }
/// Deletes all generated instances public static void CleanRenderData(tk2dTileMap tileMap) { if (tileMap.renderData == null) return; // Build a list of all children // All children will appear after the parent int currentProcessedChild = 0; List<Transform> children = new List<Transform>(); children.Add(tileMap.renderData.transform); while (currentProcessedChild < children.Count) { var thisChild = children[currentProcessedChild++]; int childCount = thisChild.GetChildCount(); for (int i = 0; i < childCount; ++i) children.Add(thisChild.GetChild(i)); } currentProcessedChild = children.Count - 1; while (currentProcessedChild > 0) // skip very first as it is the root object { var go = children[currentProcessedChild--].gameObject; MeshFilter mf = go.GetComponent<MeshFilter>(); if (mf != null) { Mesh mesh = mf.sharedMesh; mf.sharedMesh = null; tileMap.DestroyMesh(mesh); } MeshCollider meshCollider = go.GetComponent<MeshCollider>(); if (meshCollider) { Mesh mesh = meshCollider.sharedMesh; meshCollider.sharedMesh = null; tileMap.DestroyMesh(mesh); } GameObject.DestroyImmediate(go); } tileMap.buildKey++; // force a rebuild }
void PopulateTilemap(tk2dTileMap tileMap) { tk2dEditor.TileMap.TileMapUtility.ResizeTileMap(tileMap, width, height, tileMap.partitionSizeX, tileMap.partitionSizeY); foreach (var layer in layers) { int index = tk2dEditor.TileMap.TileMapUtility.FindOrCreateLayer(tileMap, layer.name); var target = tileMap.Layers[index]; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int tile = (int)(layer.tiles[y * width + x] & ~(0xE0000000)); // ignore flipping target.SetTile(x, height - 1 - y, tile - 1); } } target.Optimize(); } }
/// Spawns all prefabs for a given chunk /// Expects the chunk to have a valid GameObject public static void SpawnPrefabsForChunk(tk2dTileMap tileMap, SpriteChunk chunk) { var chunkData = chunk.spriteIds; var tilePrefabs = tileMap.data.tilePrefabs; Vector3 tileSize = tileMap.data.tileSize; int[] prefabCounts = new int[tilePrefabs.Length]; var parent = chunk.gameObject.transform; for (int y = 0; y < tileMap.partitionSizeY; ++y) { for (int x = 0; x < tileMap.partitionSizeX; ++x) { int tile = chunkData[y * tileMap.partitionSizeX + x]; if (tile < 0 || tile >= tilePrefabs.Length) { continue; } Vector3 currentPos = new Vector3(tileSize.x * x, tileSize.y * y, 0); Object prefab = tilePrefabs[tile]; if (prefab != null) { prefabCounts[tile]++; #if UNITY_EDITOR && !(UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4) GameObject go = UnityEditor.PrefabUtility.InstantiatePrefab(prefab) as GameObject; #else GameObject go = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity) as GameObject; #endif if (go) { go.name = prefab.name + " " + prefabCounts[tile].ToString(); // Position after transforming, as it is in local space go.transform.parent = parent; go.transform.localPosition = currentPos; go.transform.localRotation = Quaternion.identity; go.transform.localScale = Vector3.one; } } } } }
public void Init(Grid <int> layout, int variant) { Variant = variant; Layout = layout; tileMap = GetComponent <tk2dTileMap>(); tileMap.renderData.transform.localScale = new Vector3(0.5f, 0.5f, 1); Refresh(); tileMap.renderData.transform.parent = transform; var collider = GetComponent <BoxCollider2D>(); collider.size *= tileMap.renderData.transform.localScale.x; collider.center *= tileMap.renderData.transform.localScale.x; Cursor = transform.FindChild("Selector").gameObject; Cursor.transform.localPosition = tileMap.data.tileSize * tileMap.renderData.transform.localScale.x; }
public tk2dTileMapSceneGUI(ITileMapEditorHost host, tk2dTileMap tileMap, tk2dTileMapEditorData editorData) { this.host = host; this.tileMap = tileMap; this.editorData = editorData; this.tileMapData = tileMap.data; // create default brush if (tileMap.SpriteCollectionInst && this.editorData) { this.editorData.InitBrushes(tileMap.SpriteCollectionInst); EditorUtility.SetDirty(this.editorData); } scratchpadGUI = new tk2dScratchpadGUI(this, BrushRenderer, WorkingBrush); if (editorData != null) { scratchpadGUI.SetActiveScratchpads(editorData.scratchpads); } }
private void ExpandRoom(PaydayDrillItem drillItem, RoomHandler r) { Dungeon dungeon = GameManager.Instance.Dungeon; AkSoundEngine.PostEvent("Play_OBJ_stone_crumble_01", GameManager.Instance.gameObject); tk2dTileMap tk2dTileMap = null; HashSet <IntVector2> hashSet = new HashSet <IntVector2>(); for (int i = -5; i < r.area.dimensions.x + 5; i++) { for (int j = -5; j < r.area.dimensions.y + 5; j++) { IntVector2 intVector = r.area.basePosition + new IntVector2(i, j); CellData cellData = (!dungeon.data.CheckInBoundsAndValid(intVector)) ? null : dungeon.data[intVector]; if (cellData != null && cellData.type == CellType.WALL && cellData.HasTypeNeighbor(dungeon.data, CellType.FLOOR)) { hashSet.Add(cellData.position); } } } foreach (IntVector2 key in hashSet) { CellData cellData2 = dungeon.data[key]; cellData2.breakable = true; cellData2.occlusionData.overrideOcclusion = true; cellData2.occlusionData.cellOcclusionDirty = true; tk2dTileMap = dungeon.DestroyWallAtPosition(key.x, key.y, true); if (UnityEngine.Random.value < 0.25f) { drillItem.VFXDustPoof.SpawnAtPosition(key.ToCenterVector3((float)key.y), 0f, null, null, null, null, false, null, null, false); } r.Cells.Add(cellData2.position); r.CellsWithoutExits.Add(cellData2.position); r.RawCells.Add(cellData2.position); } Pixelator.Instance.MarkOcclusionDirty(); Pixelator.Instance.ProcessOcclusionChange(r.Epicenter, 1f, r, false); if (tk2dTileMap) { dungeon.RebuildTilemap(tk2dTileMap); } }
public static void Build(tk2dTileMap tileMap, bool forceBuild) { bool incremental = !forceBuild; int numLayers = tileMap.Layers.Length; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; if (layer.IsEmpty || !tileMap.data.Layers[layerId].generateCollider) { continue; } for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); if (incremental && !chunk.Dirty) { continue; } if (chunk.IsEmpty) { continue; } BuildForChunk(tileMap, chunk, baseX, baseY); PhysicMaterial material = tileMap.data.Layers[layerId].physicMaterial; if (chunk.meshCollider != null) { chunk.meshCollider.sharedMaterial = material; } } } } }
public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow, Rect inRect) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); Rect visibleRect = tk2dSpriteThumbnailCache.VisibleRect; visibleRect = inRect; Vector4 clipRegion = new Vector4(visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", Color.white); customMaterial.SetVector("_Clip", clipRegion); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.SpriteCollectionInst.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix, i); } } return(rect); }
/// Deletes all generated instances public static void CleanRenderData(tk2dTileMap tileMap) { if (tileMap.renderData == null) { return; } // Build a list of all children // All children will appear after the parent int currentProcessedChild = 0; List <Transform> children = new List <Transform>(); children.Add(tileMap.renderData.transform); while (currentProcessedChild < children.Count) { var thisChild = children[currentProcessedChild++]; int childCount = thisChild.GetChildCount(); for (int i = 0; i < childCount; ++i) { children.Add(thisChild.GetChild(i)); } } currentProcessedChild = children.Count - 1; while (currentProcessedChild > 0) // skip very first as it is the root object { var go = children[currentProcessedChild--].gameObject; if (go.renderer) { MeshFilter mf = go.GetComponent <MeshFilter>(); if (mf != null) { Mesh mesh = mf.sharedMesh; GameObject.DestroyImmediate(mesh); mf.sharedMesh = null; } } GameObject.DestroyImmediate(go); } tileMap.buildKey++; // force a rebuild }
// Returns index of newly added layer public static int AddNewLayer(tk2dTileMap tileMap) { var existingLayers = tileMap.data.Layers; // find a unique hash bool duplicateHash = false; int hash; do { duplicateHash = false; hash = Random.Range(0, int.MaxValue); foreach (var layer in existingLayers) if (layer.hash == hash) duplicateHash = true; } while (duplicateHash == true); List<Object> objectsToUndo = new List<Object>(); objectsToUndo.Add(tileMap); objectsToUndo.Add(tileMap.data); Undo.RegisterUndo(objectsToUndo.ToArray(), "Add layer"); var newLayer = new tk2dRuntime.TileMap.LayerInfo(); newLayer.name = "New Layer"; newLayer.hash = hash; newLayer.z = 0.1f; tileMap.data.tileMapLayers.Add(newLayer); // remap tilemap tk2dRuntime.TileMap.BuilderUtil.InitDataStore(tileMap); GameObject layerGameObject = new GameObject(newLayer.name); layerGameObject.transform.parent = tileMap.renderData.transform; layerGameObject.transform.localPosition = Vector3.zero; layerGameObject.transform.localScale = Vector3.one; layerGameObject.transform.localRotation = Quaternion.identity; tileMap.Layers[tileMap.Layers.Length - 1].gameObject = layerGameObject; Undo.RegisterCreatedObjectUndo(layerGameObject, "Add layer"); return tileMap.data.NumLayers - 1; }
//////////////////////////////////////////////////////////////////////////////////////////////// /// Static and helper functions //////////////////////////////////////////////////////////////////////////////////////////////// public static bool Import(tk2dTileMap tileMap, Format format) { var importer = new Importer(); string ext = ""; switch (format) { case Format.TMX: if (!importer.CheckZlib()) { return(false); } ext = "tmx"; break; } string path = EditorUtility.OpenFilePanel("Import tilemap", "", ext); if (path.Length == 0) { return(false); } string message = ""; switch (format) { case Format.TMX: message = importer.ImportTMX(path); break; } if (message.Length != 0) { EditorUtility.DisplayDialog("Tilemap failed to import", message, "Ok"); return(false); } importer.PopulateTilemap(tileMap); return(true); }
void PopulateTilemap(tk2dTileMap tileMap) { int extraWidth = staggered ? 1 : 0; tk2dEditor.TileMap.TileMapUtility.ResizeTileMap(tileMap, width + extraWidth, height, tileMap.partitionSizeX, tileMap.partitionSizeY); if (staggered) { tileMap.data.sortMethod = tk2dTileMapData.SortMethod.TopLeft; tileMap.data.tileType = tk2dTileMapData.TileType.Isometric; } foreach (var layer in layers) { int index = tk2dEditor.TileMap.TileMapUtility.FindOrCreateLayer(tileMap, layer.name); var target = tileMap.Layers[index]; int ww = width + extraWidth; for (int y = 0; y < height; ++y) { for (int x = 0; x < ww; ++x) { target.SetTile(x, y, -1); } } for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int tile = (int)(layer.tiles[y * width + x] & ~(0xE0000000)); // ignore flipping int offset = (staggered && ((y % 2) == 0)) ? 0 : 1; target.SetTile(x + offset, height - 1 - y, tile - 1); } } target.Optimize(); } }
public static void Build(tk2dTileMap tileMap, bool forceBuild) { bool incremental = !forceBuild; int numLayers = tileMap.Layers.Length; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; if (layer.IsEmpty || !tileMap.data.Layers[layerId].generateCollider) continue; for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); if (incremental && !chunk.Dirty) continue; if (chunk.IsEmpty) continue; BuildForChunk(tileMap, chunk, baseX, baseY); #if !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) PhysicsMaterial2D material = tileMap.data.Layers[layerId].physicsMaterial2D; foreach (EdgeCollider2D ec in chunk.edgeColliders) { if (ec != null) { ec.sharedMaterial = material; } } #endif } } } }
private void ShrinkRoom(RoomHandler r) { Dungeon dungeon = GameManager.Instance.Dungeon; AkSoundEngine.PostEvent("Play_OBJ_stone_crumble_01", GameManager.Instance.gameObject); tk2dTileMap tk2dTileMap = null; HashSet <IntVector2> hashSet = new HashSet <IntVector2>(); for (int i = -5; i < r.area.dimensions.x + 5; i++) { for (int j = -5; j < r.area.dimensions.y + 5; j++) { IntVector2 intVector = r.area.basePosition + new IntVector2(i, j); CellData cellData = (!dungeon.data.CheckInBoundsAndValid(intVector)) ? null : dungeon.data[intVector]; if (cellData != null && cellData.type != CellType.WALL && cellData.HasTypeNeighbor(dungeon.data, CellType.WALL)) { hashSet.Add(cellData.position); } } } foreach (IntVector2 key in hashSet) { CellData cellData2 = dungeon.data[key]; cellData2.breakable = true; cellData2.occlusionData.overrideOcclusion = true; cellData2.occlusionData.cellOcclusionDirty = true; tk2dTileMap = dungeon.ConstructWallAtPosition(key.x, key.y, true); r.Cells.Remove(cellData2.position); r.CellsWithoutExits.Remove(cellData2.position); r.RawCells.Remove(cellData2.position); } Pixelator.Instance.MarkOcclusionDirty(); Pixelator.Instance.ProcessOcclusionChange(r.Epicenter, 1f, r, false); if (tk2dTileMap) { dungeon.RebuildTilemap(tk2dTileMap); } }
public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; float maxScreenWidth = Screen.width - 16; if (width > maxScreenWidth) { height = height * maxScreenWidth / width; width = maxScreenWidth; } Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.SpriteCollectionInst.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); for (int i = 0; i < dictData.materials.Length; ++i) { dictData.materials[i].SetPass(0); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix, i); } } return(rect); }
//保存当前tilemap的数据为一个字符串,格式与CVS相同 public string SaveTileMap(tk2dTileMap tk2dTM, int layerID) { try { string result = ""; width = tk2dTM.width; height = tk2dTM.height; //根据tilemap的宽度和高度初始化tileID数组 tileID = new int[width, height]; //从第一行开始,依次读取每一行,即row for (int y = 0; y < height; y++) { //从第一列开始,一次读取每一列,即column for (int x = 0; x < width; x++) { //因为tk2dTileMap与Tiled的坐标系不同,y正好是相反的,所以从tk2dTileMap中取tileID时,y的值为height-1-y tileID[x, y] = tk2dTM.GetTile(x, height - 1 - y, layerID); //如果没有达到tilemap的宽度,则添加 "," 区分每一个tile if (x != width - 1) { result += tileID[x, y].ToString() + ","; } //否则,一行完成后,进行换行 else { result += tileID[x, y].ToString() + "\r\n"; } } } return(result); } catch { //throw; return(""); } }
public static Vector3 ApplySpriteVertexTileFlags(tk2dTileMap tileMap, tk2dSpriteDefinition spriteDef, Vector3 pos, bool flipH, bool flipV, bool rot90) { float num = tileMap.data.tileOrigin.x + (0.5f * tileMap.data.tileSize.x); float num2 = tileMap.data.tileOrigin.y + (0.5f * tileMap.data.tileSize.y); float num3 = pos.x - num; float num4 = pos.y - num2; if (rot90) { float num5 = num3; num3 = num4; num4 = -num5; } if (flipH) { num3 *= -1f; } if (flipV) { num4 *= -1f; } pos.x = num + num3; pos.y = num2 + num4; return pos; }
public static void DeleteLayer(tk2dTileMap tileMap, int layerToDelete) { // Just in case if (tileMap.data.NumLayers <= 1) { return; } // Find all objects that will be affected by this operation List <Object> objectsToUndo = new List <Object>(); objectsToUndo.Add(tileMap); objectsToUndo.Add(tileMap.data); objectsToUndo.AddRange(CollectDeepHierarchy(tileMap.Layers[layerToDelete].gameObject)); Undo.RegisterUndo(objectsToUndo.ToArray(), "Delete layer"); tileMap.data.tileMapLayers.RemoveAt(layerToDelete); if (tileMap.Layers[layerToDelete].gameObject != null) { GameObject.DestroyImmediate(tileMap.Layers[layerToDelete].gameObject); } tk2dRuntime.TileMap.BuilderUtil.InitDataStore(tileMap); tileMap.ForceBuild(); }
public static void Build(tk2dTileMap tileMap, bool editMode, bool forceBuild) { bool skipPrefabs = editMode?false:true; bool incremental = !forceBuild; int numLayers = tileMap.data.NumLayers; for (int layerId = 0; layerId < numLayers; ++layerId) { var layer = tileMap.Layers[layerId]; if (layer.IsEmpty) { continue; } var layerData = tileMap.data.Layers[layerId]; bool useColor = !tileMap.ColorChannel.IsEmpty && tileMap.data.Layers[layerId].useColor; #if !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) bool useSortingLayer = tileMap.data.useSortingLayers; #endif for (int cellY = 0; cellY < layer.numRows; ++cellY) { int baseY = cellY * layer.divY; for (int cellX = 0; cellX < layer.numColumns; ++cellX) { int baseX = cellX * layer.divX; var chunk = layer.GetChunk(cellX, cellY); ColorChunk colorChunk = tileMap.ColorChannel.GetChunk(cellX, cellY); bool colorChunkDirty = (colorChunk != null) && colorChunk.Dirty; if (incremental && !colorChunkDirty && !chunk.Dirty) { continue; } if (chunk.mesh != null) { chunk.mesh.Clear(); } if (chunk.IsEmpty) { continue; } if (editMode || (!editMode && !layerData.skipMeshGeneration)) { BuildForChunk(tileMap, chunk, colorChunk, useColor, skipPrefabs, baseX, baseY); #if !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) if (chunk.gameObject != null && useSortingLayer) { Renderer r = chunk.gameObject.GetComponent <Renderer>(); if (r != null) { r.sortingLayerName = layerData.sortingLayerName; r.sortingOrder = layerData.sortingOrder; } } #endif } if (chunk.mesh != null) { tileMap.TouchMesh(chunk.mesh); } } } } }
/// <summary> /// Moves the chunk's gameobject's children to the prefab root /// </summary> public static void HideTileMapPrefabs(tk2dTileMap tileMap) { if (tileMap.renderData == null) { // No Render Data to parent Prefab Root to return; } else { if (tileMap.PrefabsRoot == null) { var go = tileMap.PrefabsRoot = new GameObject("Prefabs"); go.transform.parent = tileMap.renderData.transform; go.transform.localPosition = Vector3.zero; go.transform.localRotation = Quaternion.identity; go.transform.localScale = Vector3.one; } } if (tileMap.Layers == null) { return; } int instListCount = tileMap.GetTilePrefabsListCount(); bool[] instExists = new bool[instListCount]; for (int i = 0; i < tileMap.Layers.Length; ++i) { var layer = tileMap.Layers[i]; for (int j = 0; j < layer.spriteChannel.chunks.Length; ++j) { var chunk = layer.spriteChannel.chunks[j]; if (chunk.gameObject == null) { continue; } var t = chunk.gameObject.transform; int childCount = t.childCount; for (int k = 0; k < childCount; ++k) { GameObject go = t.GetChild(k).gameObject; for (int q = 0; q < instListCount; ++q) { int x, y, layerIdx; GameObject instance; tileMap.GetTilePrefabsListItem(q, out x, out y, out layerIdx, out instance); if (instance == go) { instExists[q] = true; break; } } } } } List <int> tileX = new List <int>(); List <int> tileY = new List <int>(); List <int> tileLayer = new List <int>(); List <GameObject> tileInst = new List <GameObject>(); for (int i = 0; i < instListCount; ++i) { if (instExists[i]) { int x, y, layerIdx; GameObject instance; tileMap.GetTilePrefabsListItem(i, out x, out y, out layerIdx, out instance); tileX.Add(x); tileY.Add(y); tileLayer.Add(layerIdx); tileInst.Add(instance); instance.transform.parent = tileMap.PrefabsRoot.transform; } } tileMap.SetTilePrefabsList(tileX, tileY, tileLayer, tileInst); }
// 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(); }
static Vector3 GetTilePosition(tk2dTileMap tileMap, int x, int y) { return(new Vector3(tileMap.data.tileSize.x * x, tileMap.data.tileSize.y * y, 0.0f)); }
/// Spawns all prefabs for a given chunk /// Expects the chunk to have a valid GameObject public static void SpawnPrefabsForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY, int layer, int[] prefabCounts) { var chunkData = chunk.spriteIds; var tilePrefabs = tileMap.data.tilePrefabs; Vector3 tileSize = tileMap.data.tileSize; var parent = chunk.gameObject.transform; float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); for (int y = 0; y < tileMap.partitionSizeY; ++y) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = 0; x < tileMap.partitionSizeX; ++x) { int tile = GetTileFromRawTile(chunkData[y * tileMap.partitionSizeX + x]); if (tile < 0 || tile >= tilePrefabs.Length) continue; Object prefab = tilePrefabs[tile]; if (prefab != null) { prefabCounts[tile]++; GameObject instance = GetExistingTilePrefabInstance(tileMap, baseX + x, baseY + y, layer); bool foundExisting = (instance != null); #if UNITY_EDITOR if (instance != null) { if (UnityEditor.PrefabUtility.GetPrefabParent(instance) != prefab) { instance = null; } } #endif if (instance == null) { #if UNITY_EDITOR instance = UnityEditor.PrefabUtility.InstantiatePrefab(prefab) as GameObject; #else instance = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity) as GameObject; #endif #if UNITY_EDITOR && !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) if (!Application.isPlaying) { UnityEditor.Undo.RegisterCreatedObjectUndo(instance, "Instantiated Prefab"); } #endif } if (instance != null) { GameObject prefabGameObject = prefab as GameObject; Vector3 pos = new Vector3(tileSize.x * (x + xOffset), tileSize.y * y, 0); bool enablePrefabOffset = false; var tileInfo = tileMap.data.GetTileInfoForSprite(tile); if (tileInfo != null) enablePrefabOffset = tileInfo.enablePrefabOffset; if (enablePrefabOffset && prefabGameObject != null) pos += prefabGameObject.transform.position; if (!foundExisting) instance.name = prefab.name + " " + prefabCounts[tile].ToString(); tk2dUtil.SetTransformParent(instance.transform, parent); instance.transform.localPosition = pos; // Add to tilePrefabs list TilePrefabsX.Add(baseX + x); TilePrefabsY.Add(baseY + y); TilePrefabsLayer.Add(layer); TilePrefabsInstance.Add(instance); } } } } }
// 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(); }
/// Spawns all prefabs for a given chunk /// Expects the chunk to have a valid GameObject public static void SpawnPrefabsForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY, int layer, int[] prefabCounts) { var chunkData = chunk.spriteIds; var tilePrefabs = tileMap.data.tilePrefabs; Vector3 tileSize = tileMap.data.tileSize; var parent = chunk.gameObject.transform; float xOffsetMult = 0.0f, yOffsetMult = 0.0f; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); for (int y = 0; y < tileMap.partitionSizeY; ++y) { float xOffset = ((baseY + y) & 1) * xOffsetMult; for (int x = 0; x < tileMap.partitionSizeX; ++x) { int tile = GetTileFromRawTile(chunkData[y * tileMap.partitionSizeX + x]); if (tile < 0 || tile >= tilePrefabs.Length) { continue; } Object prefab = tilePrefabs[tile]; if (prefab != null) { prefabCounts[tile]++; GameObject instance = GetExistingTilePrefabInstance(tileMap, baseX + x, baseY + y, layer); bool foundExisting = (instance != null); if (instance == null) { #if UNITY_EDITOR && !(UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4) instance = UnityEditor.PrefabUtility.InstantiatePrefab(prefab) as GameObject; #else instance = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity) as GameObject; #endif } if (instance != null) { GameObject prefabGameObject = prefab as GameObject; Vector3 pos = new Vector3(tileSize.x * (x + xOffset), tileSize.y * y, 0); bool enablePrefabOffset = false; var tileInfo = tileMap.data.GetTileInfoForSprite(tile); if (tileInfo != null) { enablePrefabOffset = tileInfo.enablePrefabOffset; } if (enablePrefabOffset && prefabGameObject != null) { pos += prefabGameObject.transform.position; } if (!foundExisting) { instance.name = prefab.name + " " + prefabCounts[tile].ToString(); } instance.transform.parent = parent; instance.transform.localPosition = pos; // Add to tilePrefabs list TilePrefabsX.Add(baseX + x); TilePrefabsY.Add(baseY + y); TilePrefabsLayer.Add(layer); TilePrefabsInstance.Add(instance); } } } } }
//private GameObject player1; // Use this for initialization void Start() { tilemap = GetComponent <tk2dTileMap>(); }
// 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 BuildForChunk(tk2dTileMap tileMap, SpriteChunk chunk, int baseX, int baseY) { #if !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) //////////////////////////////////////////////////////////////////////////////////////// // 1. Build local edge list //////////////////////////////////////////////////////////////////////////////////////// Vector2[] localVerts = new Vector2[0]; int[] localIndices = new int[0]; List <Vector2[]> mergedEdges = new List <Vector2[]>(); BuildLocalMeshForChunk(tileMap, chunk, baseX, baseY, ref localVerts, ref localIndices); //////////////////////////////////////////////////////////////////////////////////////// // 2. Optimize //////////////////////////////////////////////////////////////////////////////////////// if (localIndices.Length > 4) { // Remove duplicate verts, reindex localVerts = WeldVertices(localVerts, ref localIndices); // Remove duplicate and back-to-back edges // Removes inside edges localIndices = RemoveDuplicateEdges(localIndices); } //////////////////////////////////////////////////////////////////////////////////////// // 3. Build and optimize an edge list //////////////////////////////////////////////////////////////////////////////////////// mergedEdges = MergeEdges(localVerts, localIndices); //////////////////////////////////////////////////////////////////////////////////////// // 4. Build the edge colliders //////////////////////////////////////////////////////////////////////////////////////// if (chunk.meshCollider != null) { tk2dUtil.DestroyImmediate(chunk.meshCollider); chunk.meshCollider = null; } if (mergedEdges.Count == 0) { for (int i = 0; i < chunk.edgeColliders.Count; ++i) { if (chunk.edgeColliders[i] != null) { tk2dUtil.DestroyImmediate(chunk.edgeColliders[i]); } } chunk.edgeColliders.Clear(); } else { int numEdges = mergedEdges.Count; // Destroy surplus for (int i = numEdges; i < chunk.edgeColliders.Count; ++i) { if (chunk.edgeColliders[i] != null) { tk2dUtil.DestroyImmediate(chunk.edgeColliders[i]); } } int numToRemove = chunk.edgeColliders.Count - numEdges; if (numToRemove > 0) { chunk.edgeColliders.RemoveRange(chunk.edgeColliders.Count - numToRemove, numToRemove); } // Make sure existing ones are not null for (int i = 0; i < chunk.edgeColliders.Count; ++i) { if (chunk.edgeColliders[i] == null) { chunk.edgeColliders[i] = tk2dUtil.AddComponent <PolygonCollider2D>(chunk.gameObject); } } // Create missing while (chunk.edgeColliders.Count < numEdges) { chunk.edgeColliders.Add(tk2dUtil.AddComponent <PolygonCollider2D>(chunk.gameObject)); } for (int i = 0; i < numEdges; ++i) { chunk.edgeColliders[i].points = mergedEdges[i]; } } #endif }
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; }
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 !(UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2) foreach (PolygonCollider2D c2d in chunk.edgeColliders) { if (c2d != null) { tk2dUtil.DestroyImmediate(c2d); } } chunk.edgeColliders.Clear(); #endif if (localMeshVertices.Length > 0) { if (chunk.colliderMesh != null) { tk2dUtil.DestroyImmediate(chunk.colliderMesh); chunk.colliderMesh = null; } if (chunk.meshCollider == null) { chunk.meshCollider = chunk.gameObject.GetComponent <MeshCollider>(); if (chunk.meshCollider == null) { chunk.meshCollider = tk2dUtil.AddComponent <MeshCollider>(chunk.gameObject); } } chunk.colliderMesh = tk2dUtil.CreateMesh(); chunk.colliderMesh.vertices = localMeshVertices; chunk.colliderMesh.triangles = localMeshIndices; chunk.colliderMesh.RecalculateBounds(); chunk.meshCollider.sharedMesh = chunk.colliderMesh; } else { chunk.DestroyColliderData(tileMap); } }
/// 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 float layerInfoZ = tileMap.data.Layers[layerId].z; if (layerId != 0) { accumulatedLayerZ -= layerInfoZ; } 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, tileMap.data.layersFixedZ ? (-layerInfoZ) : 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 (editMode) { isEmpty = false; } 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 = new Mesh(); 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.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; }
/// Syncs layer data and makes sure data is valid public static bool InitDataStore(tk2dTileMap tileMap) { bool dataChanged = false; int numLayers = tileMap.data.NumLayers; if (tileMap.Layers == null) { tileMap.Layers = new Layer[numLayers]; for (int i = 0; i < numLayers; ++i) { tileMap.Layers[i] = new Layer(tileMap.data.Layers[i].hash, tileMap.width, tileMap.height, tileMap.partitionSizeX, tileMap.partitionSizeY); } dataChanged = true; } else { // link up layer hashes Layer[] newLayers = new Layer[numLayers]; for (int i = 0; i < numLayers; ++i) { var layerInfo = tileMap.data.Layers[i]; bool found = false; // Find an existing layer with this hash for (int j = 0; j < tileMap.Layers.Length; ++j) { if (tileMap.Layers[j].hash == layerInfo.hash) { newLayers[i] = tileMap.Layers[j]; found = true; break; } } if (!found) { newLayers[i] = new Layer(layerInfo.hash, tileMap.width, tileMap.height, tileMap.partitionSizeX, tileMap.partitionSizeY); } } // Identify if it has changed int numActiveLayers = 0; foreach (var layer in newLayers) { if (!layer.IsEmpty) { numActiveLayers++; } } int numPreviousActiveLayers = 0; foreach (var layer in tileMap.Layers) { if (!layer.IsEmpty) { numPreviousActiveLayers++; } } if (numActiveLayers != numPreviousActiveLayers) { dataChanged = true; } tileMap.Layers = newLayers; } if (tileMap.ColorChannel == null) { tileMap.ColorChannel = new ColorChannel(tileMap.width, tileMap.height, tileMap.partitionSizeX, tileMap.partitionSizeY); } return(dataChanged); }