HonorLee 7 months ago
parent
commit
2be697ece5

+ 136 - 7
CGTool/Graphic.cs

@@ -8,6 +8,7 @@
  * Graphic.cs 图档解析类
  */
 
+using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
@@ -36,6 +37,10 @@ namespace CGTool
         public int OffsetX;
         //图档偏移Y
         public int OffsetY;
+        //图档合批偏移X
+        public int BatchOffsetX;
+        //图档合批偏移Y
+        public int BatchOffsetY;
         //Palet调色板Index
         public int PaletIndex;
         //图档Sprite
@@ -218,11 +223,7 @@ namespace CGTool
                     texture2D = new Texture2D(2048, height, TextureFormat.RGBA4444, false, true);
                     texture2D.filterMode = FilterMode.Point;
                     //默认填充全透明
-                    Color32[] colors = new Color32[2048 * height];
-                    for (int j = 0; j < colors.Length; j++)
-                    {
-                        colors[j] = new Color32(0,0,0,0);
-                    }
+                    Color32[] colors = Enumerable.Repeat(new Color32(0, 0, 0, 0), 2048 * height).ToArray();
                     texture2D.SetPixels32(colors);
                 }
                 
@@ -249,8 +250,9 @@ namespace CGTool
                 graphicData.OffsetX = graphicInfoData.OffsetX;
                 graphicData.OffsetY = graphicInfoData.OffsetY;
                 graphicData.PaletIndex = PaletIndex;
-                
-                
+                graphicData.BatchOffsetX = x;
+                graphicData.BatchOffsetY = y;
+
                 graphicDatas.Add(graphicData);
             }
             
@@ -280,6 +282,133 @@ namespace CGTool
 
             return graphicDataDic;
         }
+        
+        //预备地图物件缓存
+        partial class TextureData
+        {
+            public int MaxHeight;
+            public int MaxWidth;
+            public List<GraphicData> GraphicDatas = new List<GraphicData>();
+            public List<GraphicInfoData> GraphicInfoDatas = new List<GraphicInfoData>();
+        }
+        public static Dictionary<int, GraphicData> PrepareMapObjectTexture(int MapID, int PaletIndex,
+            List<GraphicInfoData> objectInfos)
+        {
+            //如果已经缓存过,则直接返回
+            // if(_mapSpriteMap.ContainsKey(MapID) && _mapSpriteMap[MapID].ContainsKey(PaletIndex)) return _mapSpriteMap[MapID][PaletIndex];
+            //如果没有缓存过,则创建缓存
+            // if(!_mapSpriteMap.ContainsKey(MapID)) _mapSpriteMap.Add(MapID,new Dictionary<int, Dictionary<int, GraphicData>>());
+            
+            // 单个Texture最大尺寸
+            int maxWidth = 4096;
+            int maxHeight = 4096;
+            
+            List<TextureData> textureDatas = new List<TextureData>();
+            Dictionary<int, GraphicData> graphicDataDic = new Dictionary<int, GraphicData>();
+            // _mapSpriteMap[MapID].Add(PaletIndex, graphicDataDic);
+
+            // 根据objectInfos的内,GraphicInfoData的Width,Height进行排序,优先排序Width,使图档从小到大排列
+            objectInfos = objectInfos.OrderBy(obj => obj.Width).ThenBy(obj => obj.Height).ToList();
+
+            int offsetX = 0;    // X轴偏移量
+            int offsetY = 0;    // Y轴偏移量
+            int maxRowHeight = 0;   // 当前行最大高度
+            
+            TextureData textureData = new TextureData();
+            
+            for (var i = 0; i < objectInfos.Count; i++)
+            {
+                GraphicInfoData graphicInfoData = objectInfos[i];
+                // 如果宽度超过4096,则换行
+                if((graphicInfoData.Width + offsetX) > maxWidth)
+                {
+                    offsetX = 0;
+                    offsetY = offsetY + maxRowHeight + 5;
+                    maxRowHeight = 0;
+                }
+                // 如果高度超过2048,则生成新的Texture2D
+                if ((graphicInfoData.Height + offsetY) > maxHeight)
+                {
+                    offsetX = 0;
+                    offsetY = 0;
+                    maxRowHeight = 0;
+                    textureDatas.Add(textureData);
+                    textureData = new TextureData();
+                }
+
+                GraphicData graphicData = new GraphicData();
+                //写入数据
+                graphicData.Version = graphicInfoData.Version;
+                graphicData.Index = graphicInfoData.Index;
+                graphicData.MapSerial = graphicInfoData.Serial;
+                graphicData.Width = graphicInfoData.Width;
+                graphicData.Height = graphicInfoData.Height;
+                graphicData.OffsetX = graphicInfoData.OffsetX;
+                graphicData.OffsetY = graphicInfoData.OffsetY;
+                graphicData.PaletIndex = PaletIndex;
+                graphicData.BatchOffsetX = offsetX;
+                graphicData.BatchOffsetY = offsetY;
+
+                // graphicDatas.Add(graphicData);
+                
+                textureData.GraphicDatas.Add(graphicData);
+                textureData.GraphicInfoDatas.Add(graphicInfoData);
+                
+                
+                maxRowHeight = Mathf.Max(maxRowHeight, (int) graphicData.Height);
+                textureData.MaxHeight = Mathf.Max(textureData.MaxHeight, offsetY + maxRowHeight);
+                textureData.MaxWidth = Mathf.Max(textureData.MaxWidth, offsetX + (int) graphicData.Width);
+                offsetX += (int) graphicData.Width + 5;
+            }
+            
+            //最后一次合并
+            if (textureData.GraphicDatas.Count > 0) textureDatas.Add(textureData);
+            
+            //合并Texture2D
+            for (var i = 0; i < textureDatas.Count; i++)
+            {
+                TextureData textureDataPiece = textureDatas[i];
+                // Debug.Log($"合并第{i}个Texture2D,最大高度:{textureDataPiece.MaxHeight},图像数量:{textureDataPiece.GraphicDatas.Count}");
+                Color32[] colors = Enumerable.Repeat(new Color32(0,0,0,0), textureDataPiece.MaxWidth * textureDataPiece.MaxHeight).ToArray();
+                Texture2D texture2DPiece = new Texture2D(textureDataPiece.MaxWidth, textureDataPiece.MaxHeight, TextureFormat.RGBA4444, false, false);
+                texture2DPiece.filterMode = FilterMode.Point;
+                texture2DPiece.SetPixels32(colors);
+                for (var n = 0; n < textureDataPiece.GraphicDatas.Count; n++)
+                {
+                    GraphicData graphicData = textureDataPiece.GraphicDatas[n];
+                    GraphicInfoData graphicInfoData = textureDataPiece.GraphicInfoDatas[n];
+                    
+                    //设置图像数据
+                    List<Color32> pixels = UnpackGraphic(graphicInfoData, PaletIndex);
+                    graphicData.PrimaryColor = pixels.Last();
+                    pixels.RemoveAt(pixels.Count - 1);
+                
+                    texture2DPiece.SetPixels32(graphicData.BatchOffsetX, graphicData.BatchOffsetY, (int) graphicInfoData.Width, (int) graphicInfoData.Height,
+                        pixels.ToArray());
+                }
+                texture2DPiece.Apply();
+                Combine(texture2DPiece, textureDataPiece.GraphicDatas);
+            }
+
+            void Combine(Texture2D texture2D,List<GraphicData> graphicDatas)
+            {
+                for (var i = 0; i < graphicDatas.Count; i++)
+                {
+                    GraphicData graphicDataPiece = graphicDatas[i];
+                    //直接通过Texture2D做偏移,并转为Sprite的偏移量
+                    Vector2 offset = new Vector2(0f, 1f);
+                    offset.x += -(graphicDataPiece.OffsetX * 1f) / graphicDataPiece.Width;
+                    offset.y -= (-graphicDataPiece.OffsetY * 1f) / graphicDataPiece.Height;
+
+                    Sprite sprite = Sprite.Create(texture2D, new Rect(graphicDataPiece.BatchOffsetX, graphicDataPiece.BatchOffsetY, (int)graphicDataPiece.Width, (int)graphicDataPiece.Height),offset, 1, 1, SpriteMeshType.FullRect);
+                    graphicDataPiece.Sprite = sprite;
+                    graphicDataDic.Add((int) graphicDataPiece.MapSerial, graphicDataPiece);
+                }
+            }
+
+            return graphicDataDic;
+        }
+        
         private static List<Color32> UnpackGraphic(GraphicInfoData graphicInfoData,int PaletIndex){
             List<Color32> pixels = new List<Color32>();
             //获取调色板

+ 4 - 6
CGTool/Map.cs

@@ -301,7 +301,7 @@ namespace CGTool
                     //在物件South+1位置,到x+East位置,补正为-48*x
                     if (!ObjectTile.GraphicInfo.AsGround)
                     {
-                        for(int i = x;i<(x+ObjectTile.GraphicInfo.East-1);i++)
+                        for(int i = x;i<(x+ObjectTile.GraphicInfo.East);i++)
                         {
                             int fix = 1;
                             int oy = y - 1;
@@ -327,17 +327,14 @@ namespace CGTool
                     }
 
 
-                    //如果物件占地范围大于1x1,则需要处理遮挡
-                    if (ObjectTile.GraphicInfo.East > 1 || ObjectTile.GraphicInfo.South > 1)
+                    //如果物件占地范围大于1x1,则需要处理行走限制
+                    if ((ObjectTile.GraphicInfo.East > 1 || ObjectTile.GraphicInfo.South > 1) && ObjectTile.GraphicInfo.Blocked)
                     {
                         //取物件占地中间点位置
                         // objectTileZIndex = (x + ObjectTile.GraphicInfo.East / 2 + (y + ObjectTile.GraphicInfo.South / 2) * mapInfo.Width) * FixZIndex;
                         // ObjectTile.ObjectZIndex = objectTileZIndex;
                         //取物件左上角位置Z轴复写默认Z轴
                         // ObjectTile.ObjectZIndex = (x + (y + ObjectTile.GraphicInfo.South) * mapInfo.Width) * FixZIndex;
-                        
-                        
-
                         for (int i = x; i < (x + ObjectTile.GraphicInfo.East); i++)
                         {
                             for (int j = y; j < (y+ ObjectTile.GraphicInfo.South); j++)
@@ -358,6 +355,7 @@ namespace CGTool
             mapInfo.MapNodes = nodes;
             mapInfo.FixPlayerZs = fixPlayerZs;
             _cache[serial] = mapInfo;
+            
             // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now);
             return mapInfo;
         }

BIN
Preview/AnimePlayer.png


BIN
Preview/AnimeSupport.gif


BIN
Preview/MapGroundMix.png


BIN
Preview/MapObjectMix.png


BIN
Preview/Preview.png


BIN
Preview/batches.png


+ 76 - 29
README.md

@@ -18,7 +18,29 @@
 
 如有任何问题请至Github提交Issues或联系作者
 
-## 2、使用说明
+![预览](Preview/Preview.png)
+
+## 2、功能支持
+> 当前版本目前仅支持 魔力宝贝3.7-龙之沙漏 及以下版本的图档解析
+> 
+> 目前版本支持以下功能:
+> 
+> * `GraphicInfo` [图档索引解析](#获取图档索引数据)
+> * `Graphic` [图档数据解析](#获取指定索引图档数据)
+> * `Palet` 调色板数据解析
+> * `Map` [服务端/客户端 图数据解析](#获取地图数据)
+> * `AudioTool` [音频索引及加载](#获取音频)
+> * `AnimeInfo` 动画索引解析
+> * `Anime` 动画数据解析
+> * `AnimePlayer` [动画播放器挂载组件](#动画播放) 
+>   * `AnimePlayer` 动画关键帧(攻击/攻击完成)事件回调
+>   * `AnimePlayer` 音频帧事件回调
+
+![动画效果](Preview/AnimePlayer.png)
+![动画效果](Preview/AnimeSupport.gif)
+
+
+## 3、使用说明
 
 克隆当前仓库或下载zip包解压,将CGTool文件夹放置于Unity项目文件夹内引用
 
@@ -45,7 +67,8 @@ CGTool.CGTool.Init();
 CGTool初始化时,会自动对相关索引Info文件进行解析,请根据实际所采用版本情况,对脚本代码中解析相关的文件名称进行修改调整
 
 
-### 获取图档索引数据(图档基本索引数据属性信息)
+### 获取图档索引数据
+(图档基本索引数据属性信息)
 ```csharp
 // 通过编号获取图档,无需版本号(推荐方法)
 GraphicInfo.GetGraphicInfoDataBySerial(uint Serial);
@@ -60,7 +83,8 @@ GraphicInfo.GetGraphicInfoDataByMapSerial(int Version, uint MapSerial);
 GraphicInfo.GetGraphicInfoDataByIndex(int Version, uint Index);
 ```
 
-### 获取指定索引图档数据(图档实际数据,包含图像Sprite资源)
+### 获取指定索引图档数据
+(图档实际数据,包含图像Sprite资源)
 ```csharp
 // 通过图档索引编号获取GraphicData数据
 Graphic.GetGraphicData(GraphicInfoData graphicInfoData,int PaletIndex=0);
@@ -86,25 +110,48 @@ SpriteRenderer(Image).sprite = graphicData.Sprite;
 Map.MapInfo mapInfo = Map.GetMap(uint Serial);
 ```
 
-### 获取地图地面图档合批图档数据
+### 获取地图地面/地图物件图档合批数据
 ```csharp
 /**
- * 针对地面数据将地面图档自动进行拼合成一个或多个2048*2048尺寸Texture2D
- * 并将拼合后的Texture2D数据拆分为对应的Sprite资源
- * 这样可以大幅降低地面图档的内存占用和Drawcall数量,提高渲染的动态合批性能
+ * * 针对地面数据将地面图档自动进行拼合成一个或多个2048*2048尺寸Texture2D
+ * * 针对地图物件(建筑等)拼合成一个或多个不大于4096*4096尺寸Texture2D
+ * 拼合后的Texture2D数据拆分为对应的Sprite资源
+ * 这样可以大幅降低地图的内存占用和Drawcall数量,提高渲染的动态合批性能
  * 另:
  * 代码中暂时禁用了已合并地面Texture2D的缓存功能,如需使用请取消相关代码注释或自行修改
- * 由于4.0后地图模式变动,所以这个方法可能不适用于4.0后的地图
+ * 由于4.0后地图模式变动,部分地图图档过大,所以这个方法可能不适用于4.0后的地图
  */
+
+// 地面合批
 Dictionary<int, GraphicData> MapGroundSerialDic =
-    Graphic.PrepareMapGroundTexture(
+    Graphic.PrepareMapGroundTexture(    // <= 合并地面图形
+        int MapID,
+        int PaletIndex,
+        List<GraphicInfoData> graphicInfoDataList
+    );
+
+// 物件合批
+Dictionary<int, GraphicData> MapObjectSerialDic =
+    Graphic.PrepareMapObjectTexture(    // <= 合并物件图形
         int MapID,
         int PaletIndex,
         List<GraphicInfoData> graphicInfoDataList
-    ); 
+    );
+```
+![地面合并效果](Preview/MapGroundMix.png)
+![物件合并效果](Preview/MapObjectMix.png)
+![资源合并后效果](Preview/batches.png)
+
+### 获取音频
+```csharp
+//获取背景音乐
+AudioClip clip = AudioTool.GetAudio(AudioTool.Type.BGM,int serial);
+
+//获取音效音频
+AudioClip clip = AudioTool.GetAudio(AudioTool.Type.EFFECT,int serial);
 ```
 
-### 获取并播放动画数据
+### 动画播放
 ```csharp
 /**
 * 动画播放器,用于播放CG动画,支持多动画队列播放
@@ -121,6 +168,7 @@ Dictionary<int, GraphicData> MapGroundSerialDic =
 *
 * 当动画播放完成后会自动调用onFinishCallback回调函数
 * 另外可指定onActionListener和onAudioListener监听动画动作帧和音频帧相关判定
+*
 * 目前已知的动作帧有:
 * 击中 Hit (未结束攻击动作,如小石像、黄蜂、绿螳螂等单次攻击动作中有多次击中效果)
 * 伤害结算 HitOver
@@ -133,7 +181,7 @@ AnimePlayer player = GetComponent<AnimePlayer>();
 * @param Serial     动画序列号
 * @param Direction  动画方向
 * @param ActionType 动画动作
-* @param PlayType   播放类型
+* @param PlayType   播放类型 Loop / Once / OnceAndDestory
 * @param Speed      播放速度倍率,以 1s 为单位基准,根据动画帧率计算实际播放周期时长
 * @param onFinishCallback 动画结束回调
 * @return AnimePlayer
@@ -148,7 +196,7 @@ player.play(
     AnimeCallback onFinishCallback = null
 );
 
-// 简化方式: 此方法大多数情况下用以播放特效动画,没有方向和动作类型
+// 简化播放: 此方法大多数情况下用以播放特效动画,没有方向和动作类型
 player.play(
     uint Serial,
     Anime.PlayType playType,
@@ -157,10 +205,20 @@ player.play(
 );
 
 // 播放一次
-player.playOnce(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null);
+player.playOnce(
+    Anime.DirectionType directionType,
+    Anime.ActionType actionType,
+    float Speed=1f,
+    AnimeCallback onFinishCallback=null
+    );
 
 // 循环播放
-player.playLoop(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null);
+player.playLoop(
+    Anime.DirectionType directionType,
+    Anime.ActionType actionType,
+    float Speed=1f,
+    AnimeCallback onFinishCallback=null
+    );
 
 /**
  * 可通过setter方法设置动画
@@ -204,23 +262,12 @@ player.Stop();
 ### 其他
 请根据情况自行探索修改代码适应应用场景
 
-## 3、版本及功能概述
-> 当前版本目前仅支持 魔力宝贝3.7-龙之沙漏 及以下版本的图档解析
-> 
-> 目前版本支持以下功能:
-> 
-> * `GraphicInfo` 图档索引解析
-> * `Graphic` 图档数据解析
-> * `Palet` 调色板数据解析
-> * `AnimeInfo` 动画索引解析
-> * `Anime` 动画数据解析
-> * `AudioTool` 音频索引及加载
-> * `AnimePlayer` 动画播放器挂载组件
-> * `Map` 服务端/客户端 图数据解析
-
 
 
 ## 4、更新日志
+### v 1.7
+> `ADD` 加入地图物件合批处理
+
 ### v 1.6
 > `ADD` 加入<font color="red">客户端</font>地图读取支持,同时附加了客户端地图文件缺失的名字和调色版映射表
 >