using System.Collections.Generic; using UnityEngine; public class TilesetFadeExample2:MonoBehaviour { public static float duration = 0.3f; private Dictionary items; private OnlineMaps map; private int zoom; private List disposedTiles; private List tileDatas; private void OnDrawTile(OnlineMapsTile tile, Material material) { if (!items.ContainsKey(material)) items.Add(material, new Item(material)); items[material].SetTile(tile); } private void Start() { items = new Dictionary(); disposedTiles = new List(); tileDatas = new List(); map = OnlineMaps.instance; zoom = map.zoom; map.OnStartDownloadTile += OnStartDownloadTile; map.OnChangeZoom += OnChangeZoom; OnlineMapsTileSetControl.instance.OnDrawTile += OnDrawTile; map.OnLateUpdateAfter += OnMapUpdated; } private void OnChangeZoom() { int z = map.zoom; if (z < zoom) OnZoomOut(z); else foreach (KeyValuePair pair in items) pair.Value.SetMode(0); zoom = z; } private void OnMapUpdated() { lock (disposedTiles) { foreach (TileData data in tileDatas) { if (data.tile.status == OnlineMapsTileStatus.disposed && !disposedTiles.Contains(data)) { disposedTiles.Add(data); } } if (disposedTiles.Count > 0) { foreach (TileData data in disposedTiles) { if (data.zoomOutTexture != null) OnlineMapsUtils.DestroyImmediate(data.zoomOutTexture); data.zoomOutTexture = null; foreach (KeyValuePair pair in items) if (pair.Value.RemoveReference(data.tile)) break; data.tile = null; tileDatas.Remove(data); } disposedTiles.Clear(); } } float alphaDelta = Time.deltaTime / duration; lock (OnlineMapsTile.tiles) { foreach (OnlineMapsTile tile in OnlineMapsTile.tiles) { TileData tileData = tile.customData as TileData; if (tileData != null) tileData.ClearFlags(); } } foreach (KeyValuePair item in items) { item.Value.UpdateMaterial(alphaDelta); } } private void OnStartDownloadTile(OnlineMapsTile tile) { TileData data = new TileData(tile); tile.customData = data; tileDatas.Add(data); tile.OnDisposed += OnTileDisposed; OnlineMaps.instance.StartDownloadTile(tile); } private void OnTileDisposed(OnlineMapsTile tile) { lock (disposedTiles) { if (tile.customData != null) disposedTiles.Add(tile.customData as TileData); //foreach (KeyValuePair pair in items) if (pair.Value.RemoveReference(tile)) break; } } private void OnZoomOut(int newZoom) { map.buffer.allowUnloadTiles = false; List currentZoomTiles = new List(); List childZoomTiles = new List(); lock (OnlineMapsTile.tiles) { foreach (OnlineMapsTile tile in OnlineMapsTile.tiles) { if (tile.status != OnlineMapsTileStatus.loaded) continue; if (tile.zoom == newZoom) currentZoomTiles.Add(tile); else if (tile.zoom == newZoom + 1) childZoomTiles.Add(tile); } } int tileSize = OnlineMapsUtils.tileSize; int halfSize = tileSize / 2; OnlineMapsTile[] childs = new OnlineMapsTile[4]; foreach (OnlineMapsTile tile in currentZoomTiles) { TileData data = tile.customData as TileData; if (data == null || data.zoomOutTexture != null) continue; int tx = tile.x; int ty = tile.y; for (int i = 0; i < 4; i++) childs[i] = null; int childCount = 0; foreach (OnlineMapsTile childTile in childZoomTiles) { int ctx = childTile.x; int cty = childTile.y; if (ctx / 2 != tx || cty / 2 != ty) continue; int index = cty % 2 * 2 + ctx % 2; if (index < 0 || index > 3) continue; childs[index] = childTile; childCount++; } if (childCount == 0) continue; int targetOffsetX; int targetOffsetY; Color32[] colors = tile.texture.GetPixels32(); for (int i = 0; i < 4; i++) { OnlineMapsTile child = childs[i]; if (child == null || child.texture == null) continue; targetOffsetX = i % 2 * halfSize; targetOffsetY = (1 - i / 2) * halfSize; Color32[] originalColors = child.texture.GetPixels32(); if (originalColors.Length != 65536) continue; for (int y = 0; y < halfSize; y++) { int targetY = (y + targetOffsetY) * tileSize + targetOffsetX; int originalY = y * tileSize * 2; for (int x = 0; x < halfSize; x++) { int index = originalY + x * 2; colors[targetY + x] = originalColors[index]; } } } Texture2D texture = new Texture2D(tileSize, tileSize, TextureFormat.RGB24, false); texture.SetPixels32(colors); texture.Apply(); texture.wrapMode = TextureWrapMode.Clamp; if (tile.status == OnlineMapsTileStatus.loaded) { data.alpha = 0; data.zoomOutTexture = texture; } } map.buffer.allowUnloadTiles = true; } internal class Item { internal OnlineMapsTile tile; private TileData tileData; private bool isModified; private Material material; private Vector2 originalScale; private Vector2 originalOffset; private int mode = 0; // 0 - zoom in, 1 - zoom out private Texture2D originalTexture; public Item(Material material) { this.material = material; } private void FadeIn(float alphaDelta) { OnlineMapsTile currentTile = tile; OnlineMapsTile parent = null; Vector2 scale = originalScale; Vector2 offset = originalOffset; Vector2 parentScale = Vector2.one; Vector2 parentOffset = Vector2.zero; while (currentTile.parent != null) { OnlineMapsTile cParent = currentTile.parent; if (cParent.status == OnlineMapsTileStatus.disposed || cParent.status == OnlineMapsTileStatus.error) { parent = cParent; break; } parentScale = scale / 2; parentOffset.x = offset.x / 2 + (currentTile.x % 2 == 0 ? 0 : 0.5f); parentOffset.y = offset.y / 2 + (currentTile.y % 2 == 0 ? 0.5f : 0); if (parentOffset.y < 0) parentOffset.y += 1; TileData parentData = cParent.customData as TileData; if (parentData == null) { parent = cParent; break; } if (parentData.alpha >= 1) { parent = cParent; break; } currentTile = cParent; offset = parentOffset; scale = parentScale; } if (parent == null) { parentScale = Vector2.one; parentOffset = Vector2.zero; } TileData data = currentTile.customData as TileData; data.IncreaseAlpha(alphaDelta); Texture mainTexture = parent != null ? parent.texture : OnlineMapsTile.emptyColorTexture; Texture overlayTexture = currentTile.texture; material.mainTexture = mainTexture; material.mainTextureScale = parentScale; material.mainTextureOffset = parentOffset; material.SetTexture("_OverlayBackTex", overlayTexture); material.SetTextureScale("_OverlayBackTex", scale); material.SetTextureOffset("_OverlayBackTex", offset); material.SetFloat("_OverlayBackAlpha", data.alpha); isModified = true; } public bool RemoveReference(OnlineMapsTile disposedTile) { if (tile == disposedTile) { tile = null; tileData = null; originalTexture = null; return true; } return false; } public void SetMode(int mode) { this.mode = mode; } public void SetTile(OnlineMapsTile tile) { this.tile = tile; tileData = tile.customData as TileData; if (tileData != null && tileData.zoomOutTexture != null) mode = 1; else mode = 0; isModified = false; originalScale = material.mainTextureScale; originalOffset = material.mainTextureOffset; originalTexture = material.mainTexture as Texture2D; } public void UpdateMaterial(float alphaDelta) { if (tile == null || tileData == null) return; lock (tileData) { if (tileData.alpha >= 1) { if (tileData.zoomOutTexture != null) { OnlineMapsUtils.DestroyImmediate(tileData.zoomOutTexture); tileData.zoomOutTexture = null; } if (!isModified) return; material.mainTexture = tile.texture; material.mainTextureScale = originalScale; material.mainTextureOffset = originalOffset; material.SetTexture("_OverlayBackTex", null); isModified = false; return; } if (mode == 0) FadeIn(alphaDelta); else { tileData.IncreaseAlpha(alphaDelta); Texture mainTexture = tileData.zoomOutTexture; Texture overlayTexture = originalTexture; material.mainTexture = mainTexture; material.mainTextureScale = Vector2.one; material.mainTextureOffset = Vector2.zero; material.SetTexture("_OverlayBackTex", overlayTexture); material.SetTextureScale("_OverlayBackTex", Vector2.one); material.SetTextureOffset("_OverlayBackTex", Vector2.zero); material.SetFloat("_OverlayBackAlpha", tileData.alpha); isModified = true; } } } } internal class TileData { public float alpha; public Texture2D zoomOutTexture; private bool isIncreased; public OnlineMapsTile tile; public TileData(OnlineMapsTile tile) { this.tile = tile; } public void IncreaseAlpha(float delta) { if (isIncreased) return; alpha += delta; if (alpha >= 1) alpha = 1; isIncreased = true; } public void ClearFlags() { isIncreased = false; } } }