using Cysharp.Threading.Tasks; using HxGame.Data; using System.Collections; using System.Collections.Generic; using System.Drawing.Imaging; using System.Drawing; using System.IO; using System.Threading; using UnityEngine; using System.Linq; public partial class MapManager : MonoBehaviour { [SerializeField] private Transform mapRegionParent; public Transform mapGridParent; public Transform mapAreaParent; public Transform mapMonsterArea; public Transform mapNPCArea; public Transform mapTeleportArea; public Transform mapReliveArea; public Transform mapAudioTrigger; public Dictionary allMaps = new Dictionary(); /// /// 当前地图区域 /// public MapRegions _curMapRegions; /// /// 保存地图配置 /// /// public void SaveRegionXML() { int mapId = _curOpenMapId; if (!allMaps.TryGetValue(_curOpenMapId.ToString(), out var curMap)) { UIWindow.Instance.ShowMessage($"没有扫描到当前地图 [{_curOpenMapId}]"); return; } _curMapRegions?.SaveXML(mapId); } public void SaveAtlasToFile() { int atlasWidth = _curMapRegions.regionRowNum * (int)_curMapRegions.regionWidth; int atlasHeight = _curMapRegions.regionColNum * (int)_curMapRegions.regionHeight; if (atlasWidth < 8192) { SaveAtlasToFileSmall(); return; } // 使用内存优化的Bitmap构造 Bitmap atlas = new Bitmap(atlasWidth, atlasHeight, PixelFormat.Format24bppRgb); using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(atlas)) { g.Transform = new System.Drawing.Drawing2D.Matrix(1, 0, 0, -1, 0, atlas.Height); for (int row = 0; row < _curMapRegions.regionRowNum; row++) { for (int col = 0; col < _curMapRegions.regionColNum; col++) { Texture2D tileTex = _curMapRegions.regions[row, col].texture; if (tileTex == null) continue; Bitmap tileBitmap = TextureToBitmap(tileTex); g.DrawImage( tileBitmap, row * (int)_curMapRegions.regionWidth, col * (int)_curMapRegions.regionHeight ); tileBitmap.Dispose(); } } } // 保存为高质量JPG(无Alpha时) string outputPath = $"{PathUtil.GetBigMapPath(_curOpenMapId)}/map_{_curOpenMapId}.jpg"; atlas.Save(outputPath, ImageFormat.Jpeg); atlas.Dispose(); Debug.Log($"导出成功!尺寸: {atlasWidth}x{atlasHeight}"); UIWindow.Instance.ShowMessage("地图导出成功"); } private Bitmap TextureToBitmap(Texture2D texture) { bool hasAlpha = texture.GetPixels().Any(c => c.a < 1f); Bitmap bitmap = new Bitmap( texture.width, texture.height, hasAlpha ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb ); BitmapData data = bitmap.LockBits( new Rectangle(0, 0, texture.width, texture.height), ImageLockMode.WriteOnly, bitmap.PixelFormat ); byte[] bytes = new byte[texture.width * texture.height * (hasAlpha ? 4 : 3)]; UnityEngine.Color[] pixels = texture.GetPixels(); for (int i = 0; i < pixels.Length; i++) { bytes[i * (hasAlpha ? 4 : 3)] = (byte)(pixels[i].b * 255); // B bytes[i * (hasAlpha ? 4 : 3) + 1] = (byte)(pixels[i].g * 255); // G bytes[i * (hasAlpha ? 4 : 3) + 2] = (byte)(pixels[i].r * 255); // R if (hasAlpha) bytes[i * 4 + 3] = (byte)(pixels[i].a * 255); // A } System.Runtime.InteropServices.Marshal.Copy(bytes, 0, data.Scan0, bytes.Length); bitmap.UnlockBits(data); return bitmap; } public void SaveAtlasToFileSmall() { // 计算大图的尺寸 int atlasWidth = _curMapRegions.regionRowNum * (int)_curMapRegions.regionWidth; int atlasHeight = _curMapRegions.regionColNum * (int)_curMapRegions.regionHeight; // 创建空的大图 Texture2D atlas = new Texture2D(atlasWidth, atlasHeight); atlas.filterMode = FilterMode.Bilinear; // 设置抗锯齿 // 遍历所有小图并合并 for (int row = 0; row < _curMapRegions.regionRowNum; row++) { for (int col = 0; col < _curMapRegions.regionColNum; col++) { HxGame.Data.Region region = _curMapRegions.regions[row, col]; Texture2D tileTex = region.texture; // 加载小图纹理 atlas.SetPixels( row * (int)_curMapRegions.regionWidth, col * (int)_curMapRegions.regionHeight, (int)_curMapRegions.regionWidth, (int)_curMapRegions.regionHeight, tileTex.GetPixels() ); } } atlas.Apply(); // 应用像素更改 byte[] pngData = atlas.EncodeToJPG(); File.WriteAllBytes($"{PathUtil.GetBigMapPath(_curOpenMapId)}/map_{_curOpenMapId}.jpg", pngData); UIWindow.Instance.ShowMessage("地图导出成功"); } public void LoadMapRegionSprites(int mapId) { if (!allMaps.TryGetValue(mapId.ToString(),out var mapInfo)) { UIWindow.Instance.ShowMessage("地图不存在。。。"); return; } int mapRownum = mapInfo.maxRow; int mapColumn = mapInfo.maxCol; _curMapRegions = new MapRegions(); _curOpenMapId = mapId; _curMapRegions.regionRowNum = mapRownum; _curMapRegions.regionColNum = mapColumn; _curMapRegions.regionWidth = PicMapPixel; _curMapRegions.regionHeight = PicMapPixel; _curMapRegions.cellWidthPixel = widthPixel; _curMapRegions.cellHeightPixel = heightPixel; _curMapRegions.regions = new HxGame.Data.Region[mapRownum, mapColumn]; int maxRow = mapColumn; int maxCol = mapRownum; float jpgscenew = PicMapPixel / 100.0f; for (int row = 0; row < mapRownum; row++) //14 * 11 { for (int col = 0; col < mapColumn; col++) { string filename = $"v{mapId}_r{mapColumn - col}_c{row + 1}"; // 构造文件名,v1000_r11_c1.jpg string spPath = PathUtil.GetMapTexure(mapId, filename, "jpg"); GameObject obj = new GameObject(filename); obj.transform.SetParent(mapRegionParent); SpriteRenderer sr = obj.AddComponent(); float x = row * jpgscenew; float y = col * jpgscenew; obj.transform.position = new Vector2(x, y); _curMapRegions.regions[row, col] = new HxGame.Data.Region(); _curMapRegions.regions[row, col].indexX = row; _curMapRegions.regions[row, col].indexY = col; multithreadLoadTextrue(spPath, sr, _curMapRegions.regions[row, col]); _curMapRegions.regions[row, col].regionName = filename; } } MapManager.Instance.ReseCamera(jpgscenew * mapColumn, jpgscenew * mapRownum); } public void ClearMapRegions() { ClearMapGrid(); foreach (Transform child in mapRegionParent) { Destroy(child.gameObject); } } public void CreateObs(int mapid) { if(_curMapRegions == null) return; float jpgscenew = PicMapPixel / 100.0f; MapManager.Instance.GenerateMap(mapid, jpgscenew * _curMapRegions.regionRowNum, jpgscenew * _curMapRegions.regionColNum, _curMapRegions.cellWidthPixel / 100.0f, _curMapRegions.cellHeightPixel / 100.0f); } private async void multithreadLoadTextrue(string fullPath,SpriteRenderer sr, HxGame.Data.Region region) { var texture = await loadASyncTexture2D(fullPath, this.GetCancellationTokenOnDestroy()); if (texture != null) { sr.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero, 100f); } region.texture = texture; } private UniTask loadASyncTexture2D(string fullPath,CancellationToken token) { return UniTask.RunOnThreadPool(async () => { if (!File.Exists(fullPath)) { Debug.LogError($"File not found: {fullPath}"); return null; } // 在线程池中异步读取文件 byte[] bytes = await File.ReadAllBytesAsync(fullPath, token); // 切换到主线程处理纹理 await UniTask.Yield(PlayerLoopTiming.Update); Texture2D texture = new Texture2D(2, 2); // 初始大小 if (texture.LoadImage(bytes)) { return texture; } else { Debug.LogError($"Failed to load image from {fullPath}"); return null; } }); } IEnumerator LoadSpriteT(string spName, GameObject go, SpriteRenderer sprite) { if (File.Exists(spName)) { byte[] bytes = File.ReadAllBytes(spName); Texture2D texture = new Texture2D(2, 2); // 初始大小,稍后调整 if (texture.LoadImage(bytes)) // 解码 JPG 到 Texture2D { sprite.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero, 100f); Debug.Log($"Loaded {spName} successfully"); } else { Debug.LogError($"Failed to load image from {spName}"); } } else { Debug.LogError($"File not found: {spName}"); } yield break; //using (UnityWebRequest req = UnityWebRequestTexture.GetTexture(spName)) //{ // yield return req.SendWebRequest(); // if (req.result == UnityWebRequest.Result.Success) // { // Texture2D tt = DownloadHandlerTexture.GetContent(req); // if (tt == null) // yield break; // sprite.sprite = Sprite.Create(tt, new Rect(0, 0, tt.width, tt.height), Vector2.zero, 100f); // } // else // { // UIWindow.Instance.ShowMessage(req.error); // } //} } }