DressUpUtil.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. using UnityEngine;
  2. using Live2D.Cubism.Rendering;
  3. using System.IO;
  4. using UnityEngine.Rendering;
  5. using YooAsset;
  6. using System.Collections.Generic;
  7. using System;
  8. using cfg.GfgCfg;
  9. namespace GFGGame
  10. {
  11. //提供各种换装相关的方法
  12. public class DressUpUtil
  13. {
  14. public const string HEAD_DEFAULT_RES_NAME = "head";
  15. public const string BODY_DEFAULT_RES_NAME = "body";
  16. public const string ROLE_OBJ_NAME = "Role";
  17. public const string HEAD_SPRITE_NAME = "Head";
  18. public const string BODY_SPRITE_NAME = "Body";
  19. public const string BODY_ANIMATION_NAME = "Body_a";
  20. public const string BODY_EFFECT_OBJ_NAME = "Body_eff";
  21. public const string FORMAT_SPRITE_NAME = "I_{0}_s{1}";
  22. public const string FORMAT_ANIMATION_NAME = "I_{0}_a{1}";
  23. public const string FORMAT_EFFECT_OBJ_NAME = "I_{0}_e{1}";
  24. public static List<DressUpLayerOperation> AddItemAsync(int itemID, GameObject sceneObj, bool needSetMask = false, bool showAni = true, GameObject parentObj = null, int resLayer = 0)
  25. {
  26. ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID);
  27. if (itemCfg == null) return null;
  28. if (parentObj == null)
  29. {
  30. if (itemCfg.SubType == ConstDressUpItemType.BEI_JING || DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType))
  31. {
  32. parentObj = sceneObj;
  33. }
  34. else
  35. {
  36. //角色
  37. Transform role = sceneObj.transform.Find(ROLE_OBJ_NAME);
  38. parentObj = role.gameObject;
  39. }
  40. }
  41. showAni = showAni || itemCfg.SubType == ConstDressUpItemType.ZHUANG_RONG;
  42. List<DressUpLayerOperation> handlers = new List<DressUpLayerOperation>();
  43. DressUpLayerOperation handler;
  44. if (resLayer > 0)
  45. {
  46. string layerName = "";
  47. switch (resLayer)
  48. {
  49. case 1:
  50. layerName = itemCfg.ResLayer1;
  51. break;
  52. case 2:
  53. layerName = itemCfg.ResLayer2;
  54. break;
  55. case 3:
  56. layerName = itemCfg.ResLayer3;
  57. break;
  58. }
  59. if (!string.IsNullOrEmpty(layerName))
  60. {
  61. handler = UpdateLayerResAsync(itemCfg, parentObj, resLayer, needSetMask, showAni);
  62. if (handler != null) handlers.Add(handler);
  63. }
  64. }
  65. else
  66. {
  67. //普通层
  68. if (!string.IsNullOrEmpty(itemCfg.ResLayer1))
  69. {
  70. handler = UpdateLayerResAsync(itemCfg, parentObj, 1, needSetMask, showAni);
  71. if (handler != null) handlers.Add(handler);
  72. }
  73. //第二层
  74. if (!string.IsNullOrEmpty(itemCfg.ResLayer2))
  75. {
  76. handler = UpdateLayerResAsync(itemCfg, parentObj, 2, needSetMask, showAni);
  77. if (handler != null) handlers.Add(handler);
  78. }
  79. //第三层
  80. if (!string.IsNullOrEmpty(itemCfg.ResLayer3))
  81. {
  82. handler = UpdateLayerResAsync(itemCfg, parentObj, 3, needSetMask, showAni);
  83. if (handler != null) handlers.Add(handler);
  84. }
  85. }
  86. if(handlers.Count > 0)
  87. {
  88. return handlers;
  89. }
  90. return null;
  91. }
  92. public static string GetSpriteName(ItemCfg itemCfg, int layer)
  93. {
  94. if(itemCfg.SubType == ConstDressUpItemType.BEI_JING)
  95. {
  96. return "Bg";
  97. }
  98. return string.Format(FORMAT_SPRITE_NAME, itemCfg.Id, layer);
  99. }
  100. public static void RemoveItem(int itemID, GameObject parentObj)
  101. {
  102. ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID);
  103. if (itemCfg == null || parentObj== null) return;
  104. string spritObjName;
  105. string aniObjName;
  106. //默认层
  107. if (!string.IsNullOrEmpty(itemCfg.ResLayer1))
  108. {
  109. spritObjName = GetSpriteName(itemCfg, 1);
  110. TryRemoveSprite(parentObj, spritObjName);
  111. aniObjName = string.Format(FORMAT_ANIMATION_NAME, itemCfg.Id, 1);
  112. TryRemoveObj(parentObj, aniObjName);
  113. aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 1);
  114. TryRemoveObj(parentObj, aniObjName);
  115. }
  116. //特殊层
  117. if (!string.IsNullOrEmpty(itemCfg.ResLayer2))
  118. {
  119. spritObjName = GetSpriteName(itemCfg, 2);
  120. TryRemoveSprite(parentObj, spritObjName);
  121. aniObjName = string.Format(FORMAT_ANIMATION_NAME, itemCfg.Id, 2);
  122. TryRemoveObj(parentObj, aniObjName);
  123. aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 2);
  124. TryRemoveObj(parentObj, aniObjName);
  125. }
  126. //第三层
  127. if (!string.IsNullOrEmpty(itemCfg.ResLayer3))
  128. {
  129. spritObjName = GetSpriteName(itemCfg, 3);
  130. TryRemoveSprite(parentObj, spritObjName);
  131. aniObjName = string.Format(FORMAT_ANIMATION_NAME, itemCfg.Id, 3);
  132. TryRemoveObj(parentObj, aniObjName);
  133. aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 3);
  134. TryRemoveObj(parentObj, aniObjName);
  135. }
  136. }
  137. public static DressUpRemoveOperation RemoveItemAsync(int itemID, GameObject sceneObj, GameObject parentObj = null)
  138. {
  139. ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID);
  140. if (itemCfg == null) return null;
  141. if (parentObj == null)
  142. {
  143. if (itemCfg.SubType == ConstDressUpItemType.BEI_JING || DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType))
  144. {
  145. parentObj = sceneObj;
  146. }
  147. else
  148. {
  149. //角色
  150. Transform role = sceneObj.transform.Find(ROLE_OBJ_NAME);
  151. parentObj = role.gameObject;
  152. }
  153. }
  154. var operation = new DressUpRemoveOperation(itemID, parentObj);
  155. operation.Begin();
  156. return operation;
  157. }
  158. public static DressUpLayerOperation UpdateHeadAsync(bool show, GameObject sceneObj, bool needSetMask = false, GameObject parentObj = null)
  159. {
  160. var roleTf = sceneObj.transform.Find(ROLE_OBJ_NAME);
  161. parentObj = parentObj == null ? roleTf.gameObject : parentObj;
  162. string res = null;
  163. string resPath = null;
  164. if(show)
  165. {
  166. res = HEAD_DEFAULT_RES_NAME;
  167. resPath = ResPathUtil.GetDressUpPath(res);
  168. }
  169. DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, false, resPath, null);
  170. handler.InitHead();
  171. handler.Begin();
  172. return handler;
  173. }
  174. public static DressUpLayerOperation UpdateBodyAsync(string actionRes, GameObject sceneObj, bool needSetMask = false, GameObject parentObj = null, int itemIdLianYiQun = 0)
  175. {
  176. //角色
  177. var roleTf = sceneObj.transform.Find(ROLE_OBJ_NAME);
  178. parentObj = parentObj == null ? roleTf.gameObject : parentObj;
  179. var extPng = "png";
  180. string resPath = null;
  181. string effectResPath = null;
  182. bool showAni = !string.IsNullOrEmpty(actionRes);
  183. string aniResPath = null;
  184. if (showAni)
  185. {
  186. aniResPath = ResPathUtil.GetDressUpAnimationPath(actionRes);
  187. if(!YooAssets.CheckResExist(aniResPath))
  188. {
  189. showAni = false;
  190. }
  191. }
  192. if(showAni)
  193. {
  194. resPath = aniResPath;
  195. //特效
  196. effectResPath = ResPathUtil.GetDressUpEffectPath(actionRes, true);
  197. if (!YooAssets.CheckResExist(effectResPath))
  198. {
  199. effectResPath = null;
  200. }
  201. }
  202. else
  203. {
  204. bool hideBody = false;
  205. if(itemIdLianYiQun > 0)
  206. {
  207. ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemIdLianYiQun);
  208. hideBody = itemCfg.HideBody > 0;
  209. }
  210. if(hideBody)
  211. {
  212. resPath = null;
  213. }
  214. else
  215. {
  216. resPath = ResPathUtil.GetDressUpPath(BODY_DEFAULT_RES_NAME, extPng);
  217. }
  218. }
  219. DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath);
  220. handler.InitBody();
  221. handler.Begin();
  222. return handler;
  223. }
  224. private static DressUpLayerOperation UpdateLayerResAsync(ItemCfg itemCfg, GameObject parentObj, int layerId, bool needSetMask, bool showAni = true)
  225. {
  226. string resPath;
  227. string aniResPath = null;
  228. //根据资源存在与否再次检查是否播放动画
  229. if (showAni)
  230. {
  231. aniResPath = ResPathUtil.GetDressUpLayerAnimationResPath(itemCfg, layerId);
  232. if(!YooAssets.CheckResExist(aniResPath))
  233. {
  234. showAni = false;
  235. }
  236. }
  237. if (showAni)
  238. {
  239. resPath = aniResPath;
  240. }
  241. else
  242. {
  243. resPath = ResPathUtil.GetDressUpLayerSpriteResPath(itemCfg, layerId);
  244. }
  245. if (!YooAssets.CheckResExist(resPath))
  246. {
  247. return null;
  248. }
  249. //特效
  250. string effectResPath = ResPathUtil.GetDressUpLayerEffectResPath(itemCfg, layerId, showAni);
  251. if (!YooAssets.CheckResExist(effectResPath))
  252. {
  253. effectResPath = null;
  254. }
  255. DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath);
  256. handler.InitLayer(itemCfg, layerId);
  257. handler.Begin();
  258. return handler;
  259. }
  260. public static GameObject AddSpriteObj(string resPath, string objName, GameObject parentObj, int sortingOrder, bool needSetMask)
  261. {
  262. if (!YooAssets.CheckResExist(resPath))
  263. {
  264. return null;
  265. }
  266. var gameObj = GetGameObjExisted(parentObj, objName, resPath);
  267. if (gameObj != null)
  268. {
  269. return gameObj;
  270. }
  271. SpriteRenderer spr = null;
  272. gameObj = parentObj.transform.Find(objName)?.gameObject;
  273. if (gameObj == null)
  274. {
  275. gameObj = new GameObject(objName);
  276. gameObj.transform.SetParent(parentObj.transform, false);
  277. }
  278. spr = gameObj.GetComponent<SpriteRenderer>();
  279. if (spr == null)
  280. {
  281. spr = gameObj.AddComponent<SpriteRenderer>();
  282. }
  283. float tx, ty;
  284. LoadSpritePos(resPath, out tx, out ty);
  285. gameObj.transform.localPosition = new Vector3(tx, ty, gameObj.transform.localPosition.z);
  286. SpriteHelper.AddSpriteTo(spr, resPath);
  287. gameObj.SetActive(true);
  288. spr.sortingOrder = sortingOrder;
  289. if (needSetMask)
  290. {
  291. spr.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
  292. if (parentObj.transform.parent != null && parentObj.transform.parent.name == "targetRole")
  293. {
  294. spr.maskInteraction = SpriteMaskInteraction.VisibleOutsideMask;
  295. }
  296. else
  297. {
  298. spr.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
  299. }
  300. }
  301. else
  302. {
  303. spr.maskInteraction = SpriteMaskInteraction.None;
  304. }
  305. return gameObj;
  306. }
  307. public static GameObject AddAnimationObj(string resPath, string objName, GameObject parentObj, int sortingOrder)
  308. {
  309. var gameObj = GetGameObjExisted(parentObj, objName, resPath);
  310. if (gameObj != null)
  311. {
  312. return gameObj;
  313. }
  314. gameObj = PrefabManager.Instance.SpawnSync(resPath);
  315. if (gameObj == null)
  316. {
  317. return null;
  318. }
  319. if (objName == BODY_ANIMATION_NAME)
  320. {
  321. //这里有个需求是一些特殊动作需要自定义位置和角度,
  322. //实现方法就是美术在动作预制体上设置这个位置,
  323. //然后程序记录下这个位置,把他设置到role节点上,并把动作节点的位置重置成默认值。
  324. DressUpOffsetInfo dressUpOffsetInfo = gameObj.GetComponent<DressUpOffsetInfo>();
  325. if(dressUpOffsetInfo == null)
  326. {
  327. dressUpOffsetInfo = gameObj.AddComponent<DressUpOffsetInfo>();
  328. dressUpOffsetInfo.OffsetPosition = gameObj.transform.localPosition;
  329. dressUpOffsetInfo.Rotation = gameObj.transform.localRotation;
  330. }
  331. //如果是动作动画,就根据动画位置及角度信息设置给Role对象
  332. parentObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition;
  333. parentObj.transform.rotation = dressUpOffsetInfo.Rotation;
  334. //.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
  335. }
  336. gameObj.transform.localPosition = Vector3.zero;
  337. gameObj.transform.rotation = Quaternion.identity;
  338. gameObj.name = objName;
  339. gameObj.transform.SetParent(parentObj.transform, false);
  340. var render = gameObj.GetComponent<CubismRenderController>();
  341. if (render == null && gameObj.transform.childCount > 0)
  342. {
  343. var childObj = gameObj.transform.GetChild(0);
  344. if (childObj != null)
  345. {
  346. render = childObj.GetComponent<CubismRenderController>();
  347. }
  348. }
  349. if (render != null && render.gameObject.activeSelf == true)
  350. {
  351. render.SortingOrder = sortingOrder;
  352. }
  353. SetRenderersOrder(gameObj, sortingOrder);
  354. return gameObj;
  355. }
  356. public static GameObject TryAddEffectObj(string resPath, string objName, GameObject parentObj, int sortingOrder)
  357. {
  358. var gameObj = GetGameObjExisted(parentObj, objName, resPath);
  359. if (gameObj != null)
  360. {
  361. return gameObj;
  362. }
  363. gameObj = PrefabManager.Instance.SpawnSync(resPath);
  364. if (gameObj == null)
  365. {
  366. return null;
  367. }
  368. DressUpOffsetInfo dressUpOffsetInfo = gameObj.GetComponent<DressUpOffsetInfo>();
  369. if (dressUpOffsetInfo == null)
  370. {
  371. //这里因为特效资源初始是有位移偏移的,记录下来每次设置为初始位置和角度,以防unity自身的坐标转换导致位置偏移
  372. dressUpOffsetInfo = gameObj.AddComponent<DressUpOffsetInfo>();
  373. dressUpOffsetInfo.OffsetPosition = gameObj.transform.localPosition;
  374. dressUpOffsetInfo.Rotation = gameObj.transform.localRotation;
  375. }
  376. gameObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition;
  377. gameObj.transform.rotation = dressUpOffsetInfo.Rotation;
  378. gameObj.transform.SetParent(parentObj.transform, false);
  379. gameObj.name = objName;
  380. var sortingGroup = gameObj.transform.GetComponent<SortingGroup>();
  381. if (sortingGroup != null)
  382. {
  383. GameObject.Destroy(sortingGroup);
  384. }
  385. SetRenderersOrder(gameObj, sortingOrder + 1);//特效层默认高一个层级
  386. return gameObj;
  387. }
  388. public static bool TryRemoveObj(GameObject parentObj, string objName)
  389. {
  390. if (parentObj == null)
  391. {
  392. return false;
  393. }
  394. Transform transform = parentObj.transform.Find(objName);
  395. if (transform != null)
  396. {
  397. GameObject gameObj = transform.gameObject;
  398. if (gameObj != null)
  399. {
  400. PrefabManager.Instance.Restore(gameObj);
  401. return true;
  402. }
  403. }
  404. return false;
  405. }
  406. public static bool TryRemoveSprite(GameObject parentObj, string objName)
  407. {
  408. if (parentObj == null)
  409. {
  410. return false;
  411. }
  412. Transform transform = parentObj.transform.Find(objName);
  413. if (transform != null)
  414. {
  415. GameObject gameObj = transform.gameObject;
  416. if (gameObj != null)
  417. {
  418. var spr = gameObj.GetComponent<SpriteRenderer>();
  419. if(spr != null)
  420. {
  421. //LogUtil.LogEditor($"TryRemoveSprite {objName}");
  422. SpriteHelper.RemoveSpriteFrom(spr);
  423. gameObj.SetActive(false);
  424. }
  425. return true;
  426. }
  427. }
  428. return false;
  429. }
  430. public static GameObject GetGameObjExisted(GameObject parentObj, string objName, string resPath)
  431. {
  432. if (parentObj == null)
  433. {
  434. return null;
  435. }
  436. Transform transform = parentObj.transform.Find(objName);
  437. if (transform != null)
  438. {
  439. GameObject gameObj = transform.gameObject;
  440. if (gameObj != null)
  441. {
  442. var assetReleaser = gameObj.GetComponent<AssetReleaser>();
  443. if (assetReleaser != null)
  444. {
  445. if (assetReleaser.ResPath == resPath)
  446. {
  447. return gameObj;
  448. }
  449. }
  450. }
  451. }
  452. return null;
  453. }
  454. public static void LoadSpritePos(string resPath, out float tx, out float ty)
  455. {
  456. int index = resPath.LastIndexOf('.');
  457. resPath = resPath.Substring(0, index) + ".bytes";
  458. if (YooAssets.CheckResExist(resPath))
  459. {
  460. var handle = YooAssets.LoadAssetSync<TextAsset>(resPath);
  461. TextAsset asset = handle.AssetObject as TextAsset;
  462. var st = new MemoryStream(asset.bytes);
  463. var br = new BinaryReader(st);
  464. tx = br.ReadInt32() / 100f;
  465. ty = -br.ReadInt32() / 100f;
  466. handle.Release();
  467. }
  468. else
  469. {
  470. tx = 0;
  471. ty = 0;
  472. }
  473. }
  474. public static void SetRenderersOrder(GameObject gameObj, int sortingOrder)
  475. {
  476. var meshRenderers = gameObj.transform.GetComponentsInChildren<MeshRenderer>();
  477. for (int i = 0; i < meshRenderers.Length; i++)
  478. {
  479. var renderer = meshRenderers[i].GetComponent<Renderer>();
  480. if (renderer != null)
  481. {
  482. renderer.sortingOrder = sortingOrder;
  483. }
  484. }
  485. ParticleSystem[] particles = gameObj.transform.GetComponentsInChildren<ParticleSystem>();
  486. for (int i = 0; i < particles.Length; i++)
  487. {
  488. var renderer = particles[i].GetComponent<Renderer>();
  489. if (renderer != null)
  490. {
  491. renderer.sortingOrder = sortingOrder;
  492. }
  493. }
  494. var spritesRenderers = gameObj.transform.GetComponentsInChildren<SpriteRenderer>();
  495. for(int i = 0; i < spritesRenderers.Length; i++)
  496. {
  497. var spriteRender = spritesRenderers[i];
  498. spriteRender.sortingOrder = sortingOrder;
  499. }
  500. }
  501. public static List<int> GetSuitItems(int suitId, bool isAction, int[] excludeType = null, bool showOptional = true, bool CheckOwn = true,bool isDress = false)
  502. {
  503. SuitCfg suitCfg = CommonDataManager.Tables.TblSuitCfg.GetOrDefault(suitId);
  504. if (suitCfg == null)
  505. {
  506. return null;
  507. }
  508. List<int> items = new List<int>(suitCfg.Parts);
  509. if (showOptional)
  510. {
  511. if (suitCfg.PartsOptional != null && suitCfg.PartsOptional.Count > 0)
  512. {
  513. items.AddRange(suitCfg.PartsOptional);
  514. }
  515. }
  516. int subType = 0;
  517. //找到要穿的散件
  518. List<int> targetItemList = new List<int>();
  519. foreach (int itemId in items)
  520. {
  521. if (!CheckOwn || DressUpMenuItemDataManager.CheckHasItem(itemId) || isDress)
  522. {
  523. subType = ItemDataManager.GetItemSubType(itemId);
  524. bool notInAction = SuitCfgArray.Instance.CheckItemNotInAction(itemId);
  525. if (!isAction || notInAction)
  526. {
  527. if (excludeType == null || Array.IndexOf(excludeType, subType) < 0)
  528. {
  529. targetItemList.Add(itemId);
  530. }
  531. }
  532. }
  533. }
  534. return targetItemList;
  535. }
  536. }
  537. }