Files
HX_MapEditor/Assets/Scripts/Map/MapManager.Region.cs
2025-11-18 10:11:56 +08:00

294 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Cysharp.Threading.Tasks;
using HxGame.Data;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Threading;
using UnityEngine;
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<string, (int maxRow, int maxCol,int maxNum)> allMaps = new Dictionary<string, (int maxRow, int maxCol, int maxNum)>();
/// <summary>
/// 当前地图区域
/// </summary>
public MapRegions _curMapRegions;
/// <summary>
/// 保存地图配置
/// </summary>
/// <param name="mapId"></param>
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()
{
if (MapManager.Instance.map == null)
{
UIWindow.Instance.ShowMessage("请先打开地图");
return;
}
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)
{
OldRegionSprites(mapId);
}
public void OldRegionSprites(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 = isSmallPic ? $"v{mapId}_r{mapColumn - col}_c{row + 1}" : $"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<SpriteRenderer>();
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;
int horizontalNumber = Mathf.FloorToInt((jpgscenew * _curMapRegions.regionRowNum) / (_curMapRegions.cellWidthPixel / 100.0f));
int verticalNumber = Mathf.FloorToInt((jpgscenew * _curMapRegions.regionColNum) / (_curMapRegions.cellHeightPixel / 100.0f));
MapManager.Instance.GenerateMap(mapid, horizontalNumber, verticalNumber, _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<Texture2D> 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);
// }
//}
}
}