using UnityEngine; using Live2D.Cubism.Rendering; using System.IO; using UnityEngine.Rendering; using YooAsset; using System.Collections.Generic; using System; using cfg.GfgCfg; using ET; namespace GFGGame { //提供各种换装相关的方法 public class DressUpUtil { public const string HEAD_DEFAULT_RES_NAME = "head"; public const string BODY_DEFAULT_RES_NAME = "body"; public const string ROLE_OBJ_NAME = "Role"; public const string HEAD_SPRITE_NAME = "Head"; public const string BODY_SPRITE_NAME = "Body"; public const string BODY_ANIMATION_NAME = "Body_a"; public const string BODY_EFFECT_OBJ_NAME = "Body_eff"; public const string FORMAT_SPRITE_NAME = "I_{0}_s{1}"; public const string FORMAT_ANIMATION_NAME = "I_{0}_a{1}"; public const string FORMAT_EFFECT_OBJ_NAME = "I_{0}_e{1}"; public static List AddItemAsync(int itemID, GameObject sceneObj, bool needSetMask = false, bool showAni = true, GameObject parentObj = null, int resLayer = 0) { ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID); if (itemCfg == null) return null; if (parentObj == null) { if (itemCfg.SubType == ConstDressUpItemType.BEI_JING || DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType)) { parentObj = sceneObj; } else { //角色 Transform role = sceneObj.transform.Find(ROLE_OBJ_NAME); parentObj = role.gameObject; } } showAni = showAni || itemCfg.SubType == ConstDressUpItemType.ZHUANG_RONG; List handlers = new List(); DressUpLayerOperation handler; if (resLayer > 0) { string layerName = ""; switch (resLayer) { case 1: layerName = itemCfg.ResLayer1; break; case 2: layerName = itemCfg.ResLayer2; break; case 3: layerName = itemCfg.ResLayer3; break; } if (!string.IsNullOrEmpty(layerName)) { handler = UpdateLayerResAsync(itemCfg, parentObj, resLayer, needSetMask, showAni); if (handler != null) handlers.Add(handler); } } else { //普通层 if (!string.IsNullOrEmpty(itemCfg.ResLayer1)) { handler = UpdateLayerResAsync(itemCfg, parentObj, 1, needSetMask, showAni); if (handler != null) handlers.Add(handler); } //第二层 if (!string.IsNullOrEmpty(itemCfg.ResLayer2)) { handler = UpdateLayerResAsync(itemCfg, parentObj, 2, needSetMask, showAni); if (handler != null) handlers.Add(handler); } //第三层 if (!string.IsNullOrEmpty(itemCfg.ResLayer3)) { handler = UpdateLayerResAsync(itemCfg, parentObj, 3, needSetMask, showAni); if (handler != null) handlers.Add(handler); } } if (handlers.Count > 0) { return handlers; } return null; } public static string GetSpriteName(ItemCfg itemCfg, int layer) { if (itemCfg.SubType == ConstDressUpItemType.BEI_JING) { return "Bg"; } return string.Format(FORMAT_SPRITE_NAME, itemCfg.Id, layer); } public static void RemoveItem(int itemID, GameObject parentObj) { ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID); if (itemCfg == null || parentObj == null) return; string spritObjName; string aniObjName; //默认层 if (!string.IsNullOrEmpty(itemCfg.ResLayer1)) { spritObjName = GetSpriteName(itemCfg, 1); TryRemoveSprite(parentObj, spritObjName); aniObjName = string.Format(FORMAT_ANIMATION_NAME, itemCfg.Id, 1); TryRemoveObj(parentObj, aniObjName); aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 1); TryRemoveObj(parentObj, aniObjName); } //特殊层 if (!string.IsNullOrEmpty(itemCfg.ResLayer2)) { spritObjName = GetSpriteName(itemCfg, 2); TryRemoveSprite(parentObj, spritObjName); aniObjName = string.Format(FORMAT_ANIMATION_NAME, itemCfg.Id, 2); TryRemoveObj(parentObj, aniObjName); aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 2); TryRemoveObj(parentObj, aniObjName); } //第三层 if (!string.IsNullOrEmpty(itemCfg.ResLayer3)) { spritObjName = GetSpriteName(itemCfg, 3); TryRemoveSprite(parentObj, spritObjName); aniObjName = string.Format(FORMAT_ANIMATION_NAME, itemCfg.Id, 3); TryRemoveObj(parentObj, aniObjName); aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 3); TryRemoveObj(parentObj, aniObjName); } } public static DressUpRemoveOperation RemoveItemAsync(int itemID, GameObject sceneObj, GameObject parentObj = null) { ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID); if (itemCfg == null) return null; if (parentObj == null) { if (itemCfg.SubType == ConstDressUpItemType.BEI_JING || DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType)) { parentObj = sceneObj; } else { //角色 Transform role = sceneObj.transform.Find(ROLE_OBJ_NAME); parentObj = role.gameObject; } } var operation = new DressUpRemoveOperation(itemID, parentObj); operation.Begin(); return operation; } public static DressUpLayerOperation UpdateHeadAsync(bool show, GameObject sceneObj, bool needSetMask = false, GameObject parentObj = null) { var roleTf = sceneObj.transform.Find(ROLE_OBJ_NAME); parentObj = parentObj == null ? roleTf.gameObject : parentObj; string res = null; string resPath = null; if (show) { res = HEAD_DEFAULT_RES_NAME; resPath = ResPathUtil.GetDressUpPath(res); } DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, false, resPath, null); handler.InitHead(); handler.Begin(); return handler; } public static DressUpLayerOperation UpdateBodyAsync(string actionRes, GameObject sceneObj, bool needSetMask = false, GameObject parentObj = null, int itemIdLianYiQun = 0) { //角色 var roleTf = sceneObj.transform.Find(ROLE_OBJ_NAME); parentObj = parentObj == null ? roleTf.gameObject : parentObj; var extPng = "png"; string resPath = null; string effectResPath = null; bool showAni = !string.IsNullOrEmpty(actionRes); string aniResPath = null; if (showAni) { aniResPath = ResPathUtil.GetDressUpAnimationPath(actionRes); if (!YooAssetsEx.CheckResExist(aniResPath)) { showAni = false; } } if (showAni) { resPath = aniResPath; //特效 effectResPath = ResPathUtil.GetDressUpEffectPath(actionRes, true); if (!YooAssetsEx.CheckResExist(effectResPath)) { effectResPath = null; } } else { bool hideBody = false; if (itemIdLianYiQun > 0) { ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemIdLianYiQun); hideBody = itemCfg.HideBody > 0; } if (hideBody) { resPath = null; } else { resPath = ResPathUtil.GetDressUpPath(BODY_DEFAULT_RES_NAME, extPng); } } DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath); handler.InitBody(); handler.Begin(); return handler; } private static DressUpLayerOperation UpdateLayerResAsync(ItemCfg itemCfg, GameObject parentObj, int layerId, bool needSetMask, bool showAni = true) { string resPath; string aniResPath = null; //根据资源存在与否再次检查是否播放动画 if (showAni) { aniResPath = ResPathUtil.GetDressUpLayerAnimationResPath(itemCfg, layerId); if (!YooAssetsEx.CheckResExist(aniResPath)) { showAni = false; } } if (showAni) { resPath = aniResPath; } else { resPath = ResPathUtil.GetDressUpLayerSpriteResPath(itemCfg, layerId); } if (!YooAssetsEx.CheckResExist(resPath)) { return null; } //特效 string effectResPath = ResPathUtil.GetDressUpLayerEffectResPath(itemCfg, layerId, showAni); if (!YooAssetsEx.CheckResExist(effectResPath)) { effectResPath = null; } DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath); handler.InitLayer(itemCfg, layerId); handler.Begin(); return handler; } public static void AddSpriteObjAsync( string resPath, string objName, GameObject parentObj, int sortingOrder, bool needSetMask, Action onComplete) { // 检查资源是否存在 if (!YooAssetsEx.CheckResExist(resPath)) { onComplete?.Invoke(null); return; } // 检查是否已存在相同对象 var existedObj = GetGameObjExisted(parentObj, objName, resPath); if (existedObj != null) { onComplete?.Invoke(existedObj); return; } // 查找或创建游戏对象 GameObject gameObj = parentObj.transform.Find(objName)?.gameObject; if (gameObj == null) { gameObj = new GameObject(objName); gameObj.transform.SetParent(parentObj.transform, false); } // 获取或添加SpriteRenderer SpriteRenderer spr = gameObj.GetComponent(); if (spr == null) { spr = gameObj.AddComponent(); } // 异步加载精灵位置 LoadSpritePosAsync(resPath, (tx, ty) => { // 设置位置 gameObj.transform.localPosition = new Vector3(tx, ty, gameObj.transform.localPosition.z); // 添加精灵 SpriteHelper.AddSpriteTo(spr, resPath); gameObj.SetActive(true); spr.sortingOrder = sortingOrder; // 设置遮罩交互 if (needSetMask) { spr.maskInteraction = parentObj.transform.parent != null && parentObj.transform.parent.name == "targetRole" ? SpriteMaskInteraction.VisibleOutsideMask : SpriteMaskInteraction.VisibleInsideMask; } else { spr.maskInteraction = SpriteMaskInteraction.None; } onComplete?.Invoke(gameObj); }); } public static void AddAnimationObjAsync( string resPath, string objName, GameObject parentObj, int sortingOrder, Action callback) { // 检查已有对象 var gameObj = GetGameObjExisted(parentObj, objName, resPath); if (gameObj != null) { callback?.Invoke(gameObj); return; } // 异步加载预制体 PrefabManager.Instance.SpawnAsync(resPath, (loadedObj) => { if (loadedObj == null) { callback?.Invoke(null); return; } if (objName == BODY_ANIMATION_NAME) { DressUpOffsetInfo dressUpOffsetInfo = loadedObj.GetComponent(); if (dressUpOffsetInfo == null) { dressUpOffsetInfo = loadedObj.AddComponent(); dressUpOffsetInfo.OffsetPosition = loadedObj.transform.localPosition; dressUpOffsetInfo.Rotation = loadedObj.transform.localRotation; } parentObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition; parentObj.transform.rotation = dressUpOffsetInfo.Rotation; } // 设置位置和父对象 loadedObj.transform.localPosition = Vector3.zero; loadedObj.transform.rotation = Quaternion.identity; loadedObj.name = objName; loadedObj.transform.SetParent(parentObj.transform, false); // 设置渲染顺序 var render = loadedObj.GetComponent(); if (render == null && loadedObj.transform.childCount > 0) { var childObj = loadedObj.transform.GetChild(0); if (childObj != null) { render = childObj.GetComponent(); } } if (render != null && render.gameObject.activeSelf) { render.SortingOrder = sortingOrder; } SetRenderersOrder(loadedObj, sortingOrder); Debug.Log($"UpdateBody UpdateLayer 结束"); callback?.Invoke(loadedObj); }); } // public static GameObject AddAnimationObj(string resPath, string objName, GameObject parentObj, int sortingOrder) // { // var gameObj = GetGameObjExisted(parentObj, objName, resPath); // if (gameObj != null) // { // return gameObj; // } // // gameObj = PrefabManager.Instance.SpawnSync(resPath); // if (gameObj == null) // { // return null; // } // // if (objName == BODY_ANIMATION_NAME) // { // //这里有个需求是一些特殊动作需要自定义位置和角度, // //实现方法就是美术在动作预制体上设置这个位置, // //然后程序记录下这个位置,把他设置到role节点上,并把动作节点的位置重置成默认值。 // DressUpOffsetInfo dressUpOffsetInfo = gameObj.GetComponent(); // if (dressUpOffsetInfo == null) // { // dressUpOffsetInfo = gameObj.AddComponent(); // dressUpOffsetInfo.OffsetPosition = gameObj.transform.localPosition; // dressUpOffsetInfo.Rotation = gameObj.transform.localRotation; // } // // //如果是动作动画,就根据动画位置及角度信息设置给Role对象 // parentObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition; // parentObj.transform.rotation = dressUpOffsetInfo.Rotation; // //.SetPositionAndRotation(Vector3.zero, Quaternion.identity); // } // // gameObj.transform.localPosition = Vector3.zero; // gameObj.transform.rotation = Quaternion.identity; // gameObj.name = objName; // gameObj.transform.SetParent(parentObj.transform, false); // var render = gameObj.GetComponent(); // if (render == null && gameObj.transform.childCount > 0) // { // var childObj = gameObj.transform.GetChild(0); // if (childObj != null) // { // render = childObj.GetComponent(); // } // } // // if (render != null && render.gameObject.activeSelf == true) // { // render.SortingOrder = sortingOrder; // } // // SetRenderersOrder(gameObj, sortingOrder); // return gameObj; // } public static void TryAddEffectObjAsync(string resPath, string objName, GameObject parentObj, int sortingOrder, Action callback) { // 检查是否已存在相同对象 var gameObj = GetGameObjExisted(parentObj, objName, resPath); if (gameObj != null) { callback?.Invoke(gameObj); return; } // 异步加载预制体 PrefabManager.Instance.SpawnAsync(resPath, (loadedObj) => { if (loadedObj == null) { callback?.Invoke(null); return; } // 处理DressUpOffsetInfo组件 DressUpOffsetInfo dressUpOffsetInfo = loadedObj.GetComponent(); if (dressUpOffsetInfo == null) { dressUpOffsetInfo = loadedObj.AddComponent(); dressUpOffsetInfo.OffsetPosition = loadedObj.transform.localPosition; dressUpOffsetInfo.Rotation = loadedObj.transform.localRotation; } // 设置位置和旋转 loadedObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition; loadedObj.transform.rotation = dressUpOffsetInfo.Rotation; // 设置父对象和名称 loadedObj.transform.SetParent(parentObj.transform, false); loadedObj.name = objName; // 处理SortingGroup组件 var sortingGroup = loadedObj.GetComponent(); if (sortingGroup != null) { GameObject.Destroy(sortingGroup); } // 设置渲染层级 SetRenderersOrder(loadedObj, sortingOrder + 1); //特效层默认高一个层级 callback?.Invoke(loadedObj); }); } public static bool TryRemoveObj(GameObject parentObj, string objName) { if (parentObj == null) { return false; } Transform transform = parentObj.transform.Find(objName); if (transform != null) { GameObject gameObj = transform.gameObject; if (gameObj != null) { PrefabManager.Instance.Restore(gameObj); return true; } } return false; } public static bool TryRemoveSprite(GameObject parentObj, string objName) { if (parentObj == null) { return false; } Transform transform = parentObj.transform.Find(objName); if (transform != null) { GameObject gameObj = transform.gameObject; if (gameObj != null) { var spr = gameObj.GetComponent(); if (spr != null) { //LogUtil.LogEditor($"TryRemoveSprite {objName}"); SpriteHelper.RemoveSpriteFrom(spr); gameObj.SetActive(false); } return true; } } return false; } public static GameObject GetGameObjExisted(GameObject parentObj, string objName, string resPath) { if (parentObj == null) { return null; } Transform transform = parentObj.transform.Find(objName); if (transform != null) { GameObject gameObj = transform.gameObject; if (gameObj != null) { var assetReleaser = gameObj.GetComponent(); if (assetReleaser != null) { if (assetReleaser.ResPath == resPath) { return gameObj; } } } } return null; } // public static void LoadSpritePos(string resPath, out float tx, out float ty) // { // int index = resPath.LastIndexOf('.'); // resPath = resPath.Substring(0, index) + ".bytes"; // if (YooAssets.CheckResExist(resPath)) // { // var handle = YooAssets.LoadAssetSync(resPath); // TextAsset asset = handle.AssetObject as TextAsset; // var st = new MemoryStream(asset.bytes); // var br = new BinaryReader(st); // tx = br.ReadInt32() / 100f; // ty = -br.ReadInt32() / 100f; // handle.Release(); // } // else // { // tx = 0; // ty = 0; // } // } public static void LoadSpritePosAsync(string resPath, Action onComplete) { int index = resPath.LastIndexOf('.'); resPath = resPath.Substring(0, index) + ".bytes"; if (YooAssetsEx.CheckResExist(resPath)) { var handle = YooAssets.LoadAssetAsync(resPath); handle.Completed += (operation) => { if (operation.Status == EOperationStatus.Succeed) { TextAsset asset = operation.AssetObject as TextAsset; using (var st = new MemoryStream(asset.bytes)) using (var br = new BinaryReader(st)) { float tx = br.ReadInt32() / 100f; float ty = -br.ReadInt32() / 100f; onComplete?.Invoke(tx, ty); } } else { Debug.LogError($"Failed to load position data: {resPath}"); onComplete?.Invoke(0, 0); } operation.Release(); }; } else { onComplete?.Invoke(0, 0); } } public static void SetRenderersOrder(GameObject gameObj, int sortingOrder) { var meshRenderers = gameObj.transform.GetComponentsInChildren(); for (int i = 0; i < meshRenderers.Length; i++) { var renderer = meshRenderers[i].GetComponent(); if (renderer != null) { renderer.sortingOrder = sortingOrder; //renderer.gameObject.layer = LayerMask.NameToLayer("UI"); } } ParticleSystem[] particles = gameObj.transform.GetComponentsInChildren(); for (int i = 0; i < particles.Length; i++) { var renderer = particles[i].GetComponent(); if (renderer != null) { renderer.sortingOrder = sortingOrder; // renderer.gameObject.layer = LayerMask.NameToLayer("UI"); } } var spritesRenderers = gameObj.transform.GetComponentsInChildren(); for (int i = 0; i < spritesRenderers.Length; i++) { var spriteRender = spritesRenderers[i]; spriteRender.sortingOrder = sortingOrder; //spriteRender.gameObject.layer = LayerMask.NameToLayer("UI"); } } public static List GetSuitItems(int suitId, bool isAction, int[] excludeType = null, bool showOptional = true, bool CheckOwn = true, bool isDress = false) { SuitCfg suitCfg = CommonDataManager.Tables.TblSuitCfg.GetOrDefault(suitId); if (suitCfg == null) { return null; } List items = new List(suitCfg.Parts); if (showOptional) { if (suitCfg.PartsOptional != null && suitCfg.PartsOptional.Count > 0) { items.AddRange(suitCfg.PartsOptional); } } int subType = 0; //找到要穿的散件 List targetItemList = new List(); foreach (int itemId in items) { if (!CheckOwn || DressUpMenuItemDataManager.CheckHasItem(itemId) || isDress) { subType = ItemDataManager.GetItemSubType(itemId); bool notInAction = SuitCfgArray.Instance.CheckItemNotInAction(itemId); if (!isAction || notInAction) { if (excludeType == null || Array.IndexOf(excludeType, subType) < 0) { targetItemList.Add(itemId); } } } } return targetItemList; } public static void LoadSpritePos(string resPath, out float tx, out float ty) { int index = resPath.LastIndexOf('.'); resPath = resPath.Substring(0, index) + ".bytes"; if (YooAssetsEx.CheckResExist(resPath)) { var handle = YooAssets.LoadAssetSync(resPath); TextAsset asset = handle.AssetObject as TextAsset; var st = new MemoryStream(asset.bytes); var br = new BinaryReader(st); tx = br.ReadInt32() / 100f; ty = -br.ReadInt32() / 100f; handle.Release(); } else { tx = 0; ty = 0; } } } }