Files
HX_MapEditor/Assets/Scripts/Character/AnimParserComponent.cs
2025-07-18 22:28:40 +08:00

257 lines
9.2 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace Game.HotFix
{
public enum AnimEnum
{
Anim_cloth,
Anim_weapon,
}
// 帧数据结构
public struct FrameData
{
public int frameID;
public int startX;
public int startY;
public int width;
public int height;
public int offsetX;
public int offsetY;
public int sourceWidth;
public int sourceHeight;
public override string ToString()
{
return $"Frame {frameID}: ({startX},{startY}) {width}x{height} offset:({offsetX},{offsetY})";
}
}
public class AnimParserComponent : MonoBehaviour
{
public static AnimParserComponent instance;
// 存储所有动画数据: [部件ID][方向][帧]
private Dictionary<string, Dictionary<int, List<FrameData>>> clothAnimData =
new Dictionary<string, Dictionary<int, List<FrameData>>>();
private Dictionary<string, Dictionary<int, List<FrameData>>> weaponAnimData =
new Dictionary<string, Dictionary<int, List<FrameData>>>();
private void Awake()
{
instance = this;
System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
LoadAndParseCSV("cloth.biz.csv", clothAnimData);
stopwatch.Stop();
Debug.Log($"加载装备CSV {clothAnimData.Count} 耗时 {stopwatch.Elapsed.Milliseconds} ms");
stopwatch.Start();
LoadAndParseCSV("weapon.biz.csv", weaponAnimData);
stopwatch.Stop();
Debug.Log($"加载武器CSV {weaponAnimData.Count} 耗时 {stopwatch.Elapsed.Milliseconds} ms");
}
// 加载并解析CSV文件
public void LoadAndParseCSV(string file, Dictionary<string, Dictionary<int, List<FrameData>>> AnimData)
{
string filePath = Path.Combine(Application.dataPath, "GameAssets/CSV", file);
if (!File.Exists(filePath))
{
Debug.LogError($"CSV file not found: {filePath}");
return;
}
string csvContent = File.ReadAllText(filePath);
ParseCSVContent(csvContent, AnimData);
}
// 解析CSV文本内容
public void ParseCSVContent(string csvContent, Dictionary<string, Dictionary<int, List<FrameData>>> AnimData)
{
// 按行分割
var lines = csvContent.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int lineCount = 0;
foreach (var line in lines)
{
lineCount++;
if (string.IsNullOrWhiteSpace(line) || line.StartsWith(","))
continue;
try
{
// 分割行
var parts = line.Trim().Split(',');
if (parts.Length < 7)
{
Debug.LogWarning($"Skipping line {lineCount}: insufficient parts ({parts.Length})");
continue;
}
string partID = parts[0];
int texWidth = ParseInt(parts[1]);
int texHeight = ParseInt(parts[2]);
int frameCount = ParseInt(parts[3]); //总共帧数
int totalDirections = ParseInt(parts[4]); //总共方向
int framesPerDirection = ParseInt(parts[5]); //每个方向帧数
// 创建方向帧列表
// 解析帧数据
for (int i = 6; i < 6 + frameCount; i++)
{
// 计算当前方向索引(基于已存在的方向数量)
int directionIndex = (i - 6) / framesPerDirection;
if (i >= parts.Length)
{
Debug.LogWarning($"Part {partID} direction {directionIndex}: expected {frameCount} frames, got {i - 6}");
break;
}
if (string.IsNullOrWhiteSpace(parts[i]))
continue;
var frameData = parts[i].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (frameData.Length < 10)
{
Debug.LogWarning($"Skipping frame data: insufficient values ({frameData.Length})");
continue;
}
FrameData frame = new FrameData
{
frameID = ParseInt(frameData[0]),
startX = ParseInt(frameData[1]),
startY = ParseInt(frameData[2]),
width = ParseInt(frameData[3]),
height = ParseInt(frameData[4]),
offsetX = ParseInt(frameData[5]),
offsetY = ParseInt(frameData[6]),
sourceWidth = ParseInt(frameData[7]),
sourceHeight = ParseInt(frameData[8])
};
if (!AnimData.ContainsKey(partID))
{
AnimData[partID] = new Dictionary<int, List<FrameData>>();
}
if (!AnimData[partID].ContainsKey(directionIndex))
{
AnimData[partID][frame.frameID / 10000] = new List<FrameData>();
}
AnimData[partID][frame.frameID / 10000].Add(frame);
}
}
catch (Exception e)
{
//Debug.LogError($"Error parsing line {lineCount}: {line}\n{e}");
}
}
}
// 获取指定部件和方向的帧数据
public List<FrameData> GetFramesForPartAndDirection(Dictionary<string, Dictionary<int, List<FrameData>>> AnimData, string partID, int direction)
{
if (AnimData.TryGetValue(partID, out var directions) &&
directions.TryGetValue(direction, out var frames))
{
return frames;
}
Debug.LogWarning($"No frames found for part {partID}, direction {direction}");
return null;
}
public List<FrameData> GetFramesForPartAndDirection(AnimEnum animEnum,string partId,int direction)
{
switch (animEnum)
{
case AnimEnum.Anim_cloth:
return GetFramesForPartAndDirection(clothAnimData,partId,direction);
case AnimEnum.Anim_weapon:
return GetFramesForPartAndDirection(weaponAnimData, partId, direction);
}
return null;
}
// 获取部件可用的方向数量
public int GetDirectionCountForPart(string partID)
{
if (clothAnimData.TryGetValue(partID, out var directions))
{
return directions.Count;
}
return 0;
}
// 获取所有部件ID
public List<string> GetAllPartIDs()
{
return clothAnimData.Keys.ToList();
}
// 获取特定部件的所有方向数据
public Dictionary<int, List<FrameData>> GetPartData(string partID)
{
if (clothAnimData.TryGetValue(partID, out var directions))
{
return directions;
}
return null;
}
// 清除所有数据
public void ClearAllData()
{
clothAnimData.Clear();
Debug.Log("Cleared all animation data");
}
// 辅助方法:安全解析整数
private int ParseInt(string value)
{
if (int.TryParse(value, out int result))
{
return result;
}
Debug.LogWarning($"Failed to parse integer: {value}");
return 0;
}
// 辅助方法:获取下一个方向索引
private int GetDirectionIndex(string partID)
{
if (clothAnimData.TryGetValue(partID, out var directions))
{
return directions.Count;
}
return 0;
}
// 调试方法:打印所有动画数据
[ContextMenu("Print Animation Data")]
public void PrintAnimationData()
{
Debug.Log("==== Animation Data Summary ====");
Debug.Log($"Total parts: {clothAnimData.Count}");
foreach (var part in clothAnimData)
{
Debug.Log($"Part: {part.Key}");
foreach (var direction in part.Value)
{
Debug.Log($" Direction {direction.Key}: {direction.Value.Count} frames");
// 打印前3帧数据
for (int i = 0; i < Mathf.Min(3, direction.Value.Count); i++)
{
Debug.Log($" {direction.Value[i]}");
}
if (direction.Value.Count > 3)
{
Debug.Log($" ... and {direction.Value.Count - 3} more");
}
}
}
Debug.Log("================================");
}
}
}