当前位置: 首页 > news >正文

【Unity】实现UI Spine动态换皮肤(SkeletonGraphic)

针对UI的Spine进行动态局部换皮肤行为,换的是Spine插槽的附件贴图。

using System.Collections.Generic;
using Spine;
using Spine.Unity;
using UnityEngine;
using Spine.Unity.AttachmentTools;public class UISpineChangeSkin : MonoBehaviour
{private SkeletonGraphic skeletonAnimation;private SkeletonDataAsset skeletonDataAsset;private Material sourceMaterial;private string skinName = "default";[SpineSkin] private string templateSkinName;//模板皮肤名称(初始)private Spine.Skin equipsSkin;private Dictionary<int, Dictionary<string, bool>> slotIndexAttachDict;public void Init(){skeletonAnimation = GetComponent<SkeletonGraphic>();skeletonDataAsset = skeletonAnimation.SkeletonDataAsset;sourceMaterial = skeletonDataAsset.atlasAssets[0].PrimaryMaterial;ReSetSkin();}public void Destroy(bool ignore = false){if (slotIndexAttachDict != null && slotIndexAttachDict.Count > 0){foreach (var v in slotIndexAttachDict){int slotIndex = v.Key;foreach (var p in v.Value){string attachmentName = p.Key;var lastAttachment = equipsSkin.GetAttachment(slotIndex, attachmentName);var mat = lastAttachment.GetMaterial();if (mat != null){if (mat.mainTexture != null){GameObject.Destroy(mat.mainTexture);}GameObject.Destroy(mat);}equipsSkin.RemoveAttachment(slotIndex, attachmentName);}}}if (!ignore){equipsSkin.Clear();equipsSkin = null;}}private void ReSetSkin(){var skeleton = skeletonAnimation.Skeleton;var skin = skeleton.Skin;if (skin == null)templateSkinName = "default";elsetemplateSkinName = skin.Name;equipsSkin = new Skin("Equips");var skeletonData = skeletonAnimation.Skeleton.Data;var tSkin = skeletonData.FindSkin(templateSkinName);if (tSkin != null)equipsSkin.AddAttachments(tSkin);skeletonAnimation.Skeleton.Skin = equipsSkin;RefreshSkeletonAttachments();}/// <summary>/// 刷新皮肤/// </summary>void RefreshSkeletonAttachments(){skeletonAnimation.Skeleton.SetSlotsToSetupPose();skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);}public void ChangeImage(Sprite sprite, string slotName, string attachmentName){SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);int slotIndex = skeletonData.FindSlot(slotName).Index;Attachment attachment = GenerateAttachmentFromEquipAsset(sprite, slotIndex, skinName, attachmentName);var lastAttachment = equipsSkin.GetAttachment(slotIndex, attachmentName);if (lastAttachment != null){if (slotIndexAttachDict != null && slotIndexAttachDict.ContainsKey(slotIndex) &&slotIndexAttachDict[slotIndex].ContainsKey(attachmentName)&& slotIndexAttachDict[slotIndex][attachmentName]){var mat = lastAttachment.GetMaterial();if (mat != null){if (mat.mainTexture != null){GameObject.Destroy(mat.mainTexture);}GameObject.Destroy(mat);}equipsSkin.RemoveAttachment(slotIndex, attachmentName);}else{if (slotIndexAttachDict == null)slotIndexAttachDict = new Dictionary<int, Dictionary<string, bool>>();if (!slotIndexAttachDict.ContainsKey(slotIndex))slotIndexAttachDict.Add(slotIndex, new Dictionary<string, bool>());if (!slotIndexAttachDict[slotIndex].ContainsKey(attachmentName))slotIndexAttachDict[slotIndex].Add(attachmentName, true);equipsSkin.RemoveAttachment(slotIndex, attachmentName);}}equipsSkin.SetAttachment(slotIndex, slotName, attachment);skeletonAnimation.Skeleton.SetSkin(equipsSkin);RefreshSkeletonAttachments();}private Attachment GenerateAttachmentFromEquipAsset(Sprite sprite, int slotIndex, string templateSkinName, string templateAttachmentName){Attachment attachment = null;if (attachment == null){SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);Skin templateSkin = skeletonData.FindSkin(templateSkinName);Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName);attachment = templateAttachment.GetRemappedClone(sprite, sourceMaterial, premultiplyAlpha: true);}return attachment;}}

用法:

//初始化Spine
skeletonGraphic.Initialize(true);
//监听Spine事件
skeletonGraphic.AnimationState.Complete += ...;uiSpineChangeSkin.Init();//初始化换皮组件uiSpineChangeSkin.ChangeImage(sprite, "插槽名称", "附件名称"); //更换Spine图像uiSpineChangeSkin.Destroy();//销毁换皮组件//注销Spine事件
skeletonGraphic.AnimationState.Complete -= ...;//*重要* 卸载Spine缓存资源(大量使用GetRemappedClone导致内存泄露问题)
AtlasUtilities.ClearCache();

注意这里的调用顺序,skeletonGraphic.Initialize(true) 调用后会恢复成原本的皮肤,所以一定要在最前面进行。而AtlasUtilities.ClearCache();是释放缓存的,基本都在游戏结束调用 或者 内存不足时强制调用 (切记频繁调用 有性能开销)

http://www.dtcms.com/a/525358.html

相关文章:

  • 从数据仓库到数据中台再到数据飞轮:我的数据技术成长之路
  • MIT:塑造未来的技术引擎
  • 查错控制方法-上(奇偶校验与循环冗余校验)
  • NVIDIA cuLitho 重新定义计算光刻的GPU加速
  • 水位雨量监测站:数据实时辅助防汛指挥
  • 网站总体设计方案网站首页不见怎么做
  • 德语网站建设注意事项天津做网站推广的公司
  • 本溪做网站的怎么看出网站有没有做404页面
  • 数据库技术指南(一):从基础概念到 MySQL 核心实践
  • 安徽义信建设网站莱芜新闻视频回放今天
  • 江西建设厅网站官网安卓开发软件手机版
  • 光伏系统中,高压电弧是怎么产生的?什么是AFCI
  • 简单了解一下环境变量(Linux)
  • 计算机端口
  • 外贸网站建设有哪些要求网站seo培训
  • 怎么增加网站的收录量成都网站优化多少钱
  • 继续网站建设南宁网页制作招聘
  • 01)PB(PowerBuilder9)学习 设置语法提示、 新建工作空间、应用、window窗体、设置应用启动open event
  • UVa 1336 Fixing the Great Wall
  • 网站开发浏览器关键词优化提升排名
  • 湖北省荆门市城乡建设网站seo代码优化有哪些方法
  • [Python快速入门]基础语法以及使用
  • el-table选中行颜色
  • Flask入门教程——李辉 第5章: 数据库 关键知识梳理
  • 嘉峪关市建设局建管科资质网站网站制作教程
  • 如何免费建设网站列表页面设计模板
  • 通过diskpart强制格式化报错:虚拟磁盘服务错误:卷大小太大
  • 02)PB(PowerBuilder9)学习 连接数据库 开发一个增删改查功能
  • Java 开发 - 扁平化数据转换成树形结构数据(递归查找 + 移除节点、Map + 一次遍历)
  • 探寻企业数字化转型“底座”:技术基石与核心支撑