using Spine; using Spine.Unity; using Spine.Unity.AttachmentTools; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; public enum EquipType { None, Armor, Weapon, Accessory } [System.Serializable] public class EquipData { public EquipType type; public string type2; public Sprite sprite; [Space(10)] public ItemData item; public Attachment attachment; public Texture texture; public Material matOrigin; public Material matHit; public Material matResist; } [System.Serializable] public class EquipHook { public EquipType type; public string type2; [Space(10)] [SpineSlot] public string slot; [SpineAttachment(skinField: "templateSkin")] public string templateAttachment; } public class Equipment : ResourcePool { void Start() { Skin(skinName); InstallApply(); Install(ItemData.Copy(DataManager.Instance.dataItem.Search($"spear1"))); //Install(ItemData.Copy(DataManager.Instance.dataItem.Search($"gold_01"))); } public Character character; [Space(10)] public SkeletonAnimation skeletonAnimation; [Space(10)] public SkeletonDataAsset skeletonDataAsset; public Material sourceMaterial; public bool applyPMA = true; /// /// 캐릭터의 아틀라스(스킨 및 장비아이템)를 갱신합니다. /// void RefreshSkeletonAttachments() { skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); //skeletonAnimation.Update(0); } Dictionary attachments = new Dictionary(); /// /// 장비의 이미지를 적용합니다. /// /// 풀링 키 /// 장비의 이미지 /// 슬롯 번호 /// 현재 스킨 이름 /// 바꿔야할 어태치먼트의 이름 /// Attachment AtlasAttachment(string key, Sprite sprite, int slotIndex, string templateSkinName, string templateAttachmentName) { Attachment attachment = null; if (attachments.ContainsKey(key)) { attachment = attachments[key]; } else { var templateSkin = skeletonDataAsset.GetSkeletonData(true).FindSkin(templateSkinName); attachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName).GetRemappedClone(sprite, sourceMaterial, premultiplyAlpha: this.applyPMA); attachments.Add(key, attachment); } return attachment; } [Space(10)] [SpineSkin] public string skinName;//현재 선택된 스킨(아머) Skin equipsSkin;//현재 장착하고 있는 스킨(아머) Dictionary skins = new Dictionary(); /// /// 캐릭터의 스킨을 변경 합니다. /// /// public void Skin(string name) { skinName = name; if (skins.ContainsKey($"{skinName}")) { equipsSkin = skins[$"{skinName}"]; } else { equipsSkin = new Skin($"{skinName}"); var templateSkin = skeletonAnimation.Skeleton.Data.FindSkin(skinName); if (templateSkin != null) equipsSkin.AddAttachments(templateSkin); skins.Add($"{skinName}", equipsSkin); } skeletonAnimation.Skeleton.Skin = equipsSkin; RefreshSkeletonAttachments(); } [Space(10)] public List equips;//스파인 내의 장비 목록 /// /// 장착 아이템을 장착합니다. /// /// /// public bool Install(ItemData item, bool EQUIP = true) { EquipData data = new EquipData(); if (item.type.CompareTo($"{EquipType.Armor}") == 0) { character.ec.Remove(OnChanged_ArmorHeart); data.type = Util.EnumUtil.Parse($"{item.type}"); data.item = item; Skin(item.idx); //character.ec.Add(OnChanged_ArmorHeart); } else if (item.type.CompareTo($"{EquipType.Weapon}") == 0 || item.type.CompareTo($"{EquipType.Accessory}") == 0) { data.sprite = SpriteManager.Instance.SpriteGet($"{item.idx}"); data.type = Util.EnumUtil.Parse($"{item.type}"); data.item = item; } else return false; bool INSTALL = InstallEquip(data); if (INSTALL && EQUIP) { INSTALL = InstallApply(); EquipHook hook = equips.Find(a => a.type == data.type && data.item.idx.Contains(a.type2)); if (hook != null) data.type2 = hook.type2; if (data.type == EquipType.Weapon) onWeaponChanged.Invoke(data);//바뀐 무기의 연동이 필요 else if (data.type == EquipType.Armor) character.ec.Add(OnChanged_ArmorHeart); } return INSTALL; } Dictionary installs = new Dictionary(); public System.Action OnUnInstall; /// /// 해당 아이템 의 부위를 확인 /// 이미 장착되어 있는 부위 라면 장착하고 잇던 아이템을 드랍 처리합니다. /// /// /// public bool InstallEquip(EquipData data) { if (installs.ContainsKey(data.type)) { EquipData before = installs[data.type]; if (data.type == EquipType.Armor || before.item.idx != data.item.idx) { installs[data.type] = data; //이전 장착 아이템 드랍 처리 //character.map.blkCurrent.OnDropItem_Create(transform, before.item); //장비가 보유중인 스킬 해제 character.skill.UnInstall(before.item); } else return false; } else installs.Add(data.type, data);//빈 슬롯에 장착 //장비가 보유중인 스킬 적용 character.skill.Install(data.item); return true; } /// /// 착용한 장비 중 같은 아이템이 있는지 확인합니다. /// /// 확인할 아이템 /// public bool InstallCheck_Item(ItemData data) { EquipType type = Util.EnumUtil.Parse($"{data.type}"); if (installs.ContainsKey(type)) { EquipData before = installs[type]; if (type == EquipType.Armor || before.item.idx != data.idx) return true; else return false; } return true; } /// /// 해당 부위에 착용중인 아이템이 있는지 확인 /// /// 확인할 부위 /// public bool InstallCheck_Part(EquipType type) { return installs.ContainsKey(type); } [Space(10)] public Sprite spriteAlpha; /// /// 장착 부위를 적용합니다. /// bool InstallApply() { for (int i = 0; i < equips.Count; i++) { var skeletonData = skeletonDataAsset.GetSkeletonData(true); var slotIndex = skeletonData.FindSlotIndex(equips[i].slot); //var attachment = AtlasAttachment($"{slotIndex}{spriteAlpha}", spriteAlpha, slotIndex, skinName, equips[i].templateAttachment); //Equip(slotIndex, equips[i].templateAttachment, attachment); equipsSkin.RemoveAttachment(slotIndex, equips[i].templateAttachment); } EquipData data = null; var list = new List(installs.Values); for (int h = 0; h < list.Count; h++) { data = list[h]; if (data.type == EquipType.Armor) continue; List hooks = equips.FindAll(a => a.type == data.type && data.item.idx.Contains(a.type2)); //if (hooks.Count == 0) // return false; EquipHook equip = null; for (int i = 0; i < hooks.Count; i++) { equip = hooks[i]; var skeletonData = skeletonDataAsset.GetSkeletonData(true); var slotIndex = skeletonData.FindSlotIndex(equip.slot); var attachment = AtlasAttachment($"{slotIndex}{equip.slot}{data.sprite}", data.sprite, slotIndex, skinName, equip.templateAttachment); if (attachment != null) { data.attachment = attachment; data.matOrigin = (Material)data.attachment.GetRegion().page.rendererObject; data.texture = data.matOrigin.mainTexture; data.matHit = new Material(matHit); data.matHit.mainTexture = data.texture; data.matResist = new Material(matResist); data.matResist.mainTexture = data.texture; } Equip(slotIndex, equip.templateAttachment, attachment); } } return true; } /// /// 장비의 이미지를 적용합니다. /// /// /// /// void Equip(int slotIndex, string attachmentName, Attachment attachment) { equipsSkin.SetAttachment(slotIndex, attachmentName, attachment); skeletonAnimation.Skeleton.SetSkin(equipsSkin); RefreshSkeletonAttachments(); } [System.Serializable] public class WeaponChangEvent : UnityEvent { } [FormerlySerializedAs("onWeaponChanged")] [SerializeField] [Space(10)] private WeaponChangEvent onWeaponChanged = new WeaponChangEvent(); [Space(10)] public TileCameraEvent tiltEvent; public GameObject particleArmorDestroy; public Transform targetArmorDestroy; /// /// 캐릭터의 AH 가 변경되어 이를 적용합니다. /// /// /// public void OnChanged_ArmorHeart(int type, object value) { if (installs.ContainsKey(EquipType.Armor)) { ItemData item = installs[EquipType.Armor].item; SkillData skill = item.skills.Find(a => a.work.Equals("AH")); skill.value = character.AH; //AH 가 0 이 되면 착용중인 갑옷을 파괴 if (skill.value < 1) { //장비가 보유중인 스킬 해제 for (int i = 0; i < item.skills.Count; i++) character.skill.skills.Remove(item.skills[i]); character.skill.items.Remove(item); Skin("base_01"); installs.Remove(EquipType.Armor); InstallApply(); tiltEvent.Shake(); ObjectCreateLocalPos(particleArmorDestroy, targetArmorDestroy, Vector3.one, Vector3.zero); } } } /// /// 캐릭터의 히트 등의 효과로 스파인에 Material 이 변경 될 경우, 장비의 이미지는 따로 적용해야함(어태치먼트 적용시 장비템 마다 아틀라스가 새로생성됨) /// [Space(5)] public Material matHit; public void Hit_Start(float duration) { if (0 == installs.Count || duration == 0) return; CancelInvoke("Hit_End"); foreach (KeyValuePair value in installs) { if (value.Value.matHit != null) value.Value.attachment.GetRegion().page.rendererObject = value.Value.matHit; } Invoke("Hit_End", duration); } void Hit_End() { foreach (KeyValuePair value in installs) { if (value.Value.matHit != null) value.Value.attachment.GetRegion().page.rendererObject = value.Value.matOrigin; } } public Material matResist; public void Resist_Start(float duration) { if (0 == installs.Count || duration == 0) return; CancelInvoke("Hit_End"); foreach (KeyValuePair value in installs) { if (value.Value.matResist != null) value.Value.attachment.GetRegion().page.rendererObject = value.Value.matResist; } Invoke("Hit_End", duration); } void Resist_End() { foreach (KeyValuePair value in installs) { if (value.Value.matResist != null) value.Value.attachment.GetRegion().page.rendererObject = value.Value.matOrigin; } } }