Untitled

mail@pastecode.io avatar
unknown
plain_text
2 years ago
9.8 kB
6
Indexable
Never
#define TEMPLATE_DRESS_CODE
using System;
using System.Collections.Generic;
using UnityEngine;

using Newtonsoft.Json.Linq;
using Sirenix.OdinInspector;

using Spine;
using Spine.Unity;
using Spine.Unity.AttachmentTools;

namespace GogogaieV2.CoreSystem.MainRole
{
	// 服裝 Sate
	public enum ROLE_SLOT_INDEX
	{
		HEAD = 0,
		BODY,
		LEFT_HAND,
		RIGHT_HAND,
		HEAD_DECORATION,
		BACK_DECORATION,
		NONE,
	};

	// 總共有十三個動作
	// 這邊的名稱是根據 Spine 上面的名稱做對應
	// 雖然我覺得有時候名詞 有時候動詞 很奇怪= =
	// 8 種互動 + 5 種其他動作 
	// 0 就當作 None
	public enum MainRoleAnimState
	{
		// 其他動作
		IDLING = 9,
		WALK,
		CAT,
		DOG,
		JUMP,

		// 互動的
		SIT = 1,
		HAPPY,
		SHOCK,
		WORRY,
		SLEEP,
		LOVE,
		SAD,
		SPEECHLESS,

		// 例外狀況使用
		NONE = 0
	}

	[RequireComponent(typeof(SkeletonAnimation))]
	public class MainRoleController : MonoBehaviour
	{
		public float u1 = 1;
		public float v1 = 1;
		private static GameObject MainRoleOutterSpace;
		private static int OutSideIndex = 0;

		#region 主角雞相關變數
		private SkeletonAnimation anim;
		private Skeleton skeleton;

		// 各個部位的資料
		private Slot[] Parts;
		private Material[] PartsNewMaterial;

		// 由於要換裝
		// 美術圖又沒給好
		// 這裡你們自己想辦法優化
		[System.NonSerialized]
		public RenderTexture renderT;

		// 這個也太好笑了吧XD
		// 原來是要程式自己解壓縮並蓋圖檔XD
		private string[] DefaultName = {
			"hand_L",
			"hair",
			"mouth",
			"eye_L",
			"eye_R",
			"head",
			"body",
			"hand_R",
			"tail",
			"foot_L",
			"foot_R",
			"shadow",
		};
		#endregion
		#region 暫時給他們編輯使用的功能
		#if UNITY_EDITOR
		#if TEMPLATE_DRESS_CODE
		[Space(10)]
		[System.NonSerialized, ShowInInspector]
		public long DressID;
		[System.NonSerialized, ShowInInspector]
		public float Rotate = -90;
		[System.NonSerialized, ShowInInspector]
		public Vector2 Offset;
		[System.NonSerialized, ShowInInspector]
		public Vector2 Scale = Vector2.one;
		private bool IsDebugMode = false;
		
		private void Update()
		{
			if (IsDebugMode)
			{
				TakeOffAllCloth();
				var dict = FindClothingByID(DressID);
				ROLE_SLOT_INDEX SlotIndex = MainRoleController.PartsMapping((int)(long)dict["Part"]);
				WearClothing(SlotIndex, Helper.SpriteDB.GetSprite(dict["ReferenceAtlas"].ToString(), dict["ReferenceKey"].ToString()), Offset, Rotate, Scale);
			}
		}

		[Button("開啟 or 關閉編輯模式", ButtonSizes.Gigantic)]
		public void DressButton()
		{
			IsDebugMode = !IsDebugMode;
		}
		#endif
		#endif
		#endregion

		private void OnDestroy()
		{
			if (PartsNewMaterial != null)
				for (int i = 0; i < PartsNewMaterial.Length; i++)
					Destroy(PartsNewMaterial[i]);
		}


		/// <summary>
		/// 初始化
		/// </summary>
		public void Init()
		{
			#region 初始化
			anim = this.GetComponent<SkeletonAnimation>();
			skeleton = anim.Skeleton;
			Parts = new Slot[]
			{
				skeleton.FindSlot("suit1_hat"),
				skeleton.FindSlot("cloth"),
				skeleton.FindSlot("suit1_hand_L"),
				skeleton.FindSlot("suit1_hand_R"),
				skeleton.FindSlot("glasses"),
				skeleton.FindSlot("decroation_back")
			};

			// Camera & Render Texture
			renderT = new RenderTexture(1280 / 2, 720 / 2, 0);
			this.transform.parent.GetComponent<Camera>().targetTexture = renderT;
			this.transform.parent.GetComponent<Camera>().depth = -10;
			if (MainRoleOutterSpace == null)
			{
				MainRoleOutterSpace = new GameObject();
				MainRoleOutterSpace.name = "MainRoleOutterSpace";
				MainRoleOutterSpace.transform.position = new Vector3(-10000, 0, 0);
				DontDestroyOnLoad(MainRoleOutterSpace);
			}
			this.transform.parent.SetParent(MainRoleOutterSpace.transform);
			this.transform.parent.position = new Vector3(MainRoleController.OutSideIndex * -2000, 0, 0);
			MainRoleController.OutSideIndex++;

			// 脫衣服
			TakeOffAllCloth();
			SwitchAnimation(MainRoleAnimState.IDLING);
			anim.AnimationState.SetAnimation(0, "idling1", true);


			// 初始化其他部件的裝備
			PartsNewMaterial = new Material[Parts.Length];
			for (int i = 0; i < Parts.Length; i++)
				PartsNewMaterial[i] = new Material(Shader.Find("Spine/Skeleton"));
			#endregion
		}

		/// <summary>
		/// 把所有的衣服脫光
		/// </summary>
		public void TakeOffAllCloth()
		{
			// 要先卻把這邊的所有的狀態都清空
			anim.ClearState();
			for (int i = 0; i < skeleton.Slots.Items.Length; i++)
			{
				bool IsFind = false;
				for (int j = 0; j < DefaultName.Length; j++)
					if (skeleton.Slots.Items[i].Data.Name == DefaultName[j])
					{
						IsFind = true;
						break;
					}

				if (!IsFind)
					skeleton.Slots.Items[i].Attachment = null;
			}
		}

		/// <summary>
		/// 主角雞跟據穿裝備
		/// </summary>
		public void MainRoleWear()
		{
			foreach(var key in Helper.UserDB.CacheDressedIndex.Keys)
			{
				int DressedIndex = Helper.UserDB.CacheDressedIndex[key];
				long ClothingID = Helper.UserDB.Clothing[key][DressedIndex].Value<long>("ClothingId");

				var dict = FindClothingByID(ClothingID);
				ROLE_SLOT_INDEX SlotIndex = MainRoleController.PartsMapping((int)(long)dict["Part"]);
				if (MainRoleController.IsOffsetInfo(dict))
					WearClothing(SlotIndex, Helper.SpriteDB.GetSprite(dict["ReferenceAtlas"].ToString(), dict["ReferenceKey"].ToString()),
						new Vector2(Convert.ToSingle(dict["OffsetX"]), Convert.ToSingle(dict["OffsetY"])),
						Convert.ToSingle(dict["Rotate"]),
						new Vector2(Convert.ToSingle(dict["ScaleX"]), Convert.ToSingle(dict["ScaleY"])));
				else
					WearClothing(SlotIndex, Helper.SpriteDB.GetSprite(dict["ReferenceAtlas"].ToString(), dict["ReferenceKey"].ToString()));
			}
		}

		/// <summary>
		/// 穿衣服
		/// </summary>
		/// <param name="SlotIndex">放到哪一個位置</param>
		/// <param name="sprite">哪一張圖片</param>
		public void WearClothing(ROLE_SLOT_INDEX SlotIndex, Sprite sprite)
		{
			WearClothing(SlotIndex, sprite, Vector2.zero, -90, new Vector2(4.0f, 4.0f));
		}
		public void WearClothing(ROLE_SLOT_INDEX SlotIndex, Sprite sprite, Vector2 offset, float rotate, Vector2 scale)
		{
			// 更新資料
			if (SlotIndex == ROLE_SLOT_INDEX.NONE)
				return;

			int index = (int)SlotIndex;
			PartsNewMaterial[index].mainTexture = sprite.texture;
			var NewAttachment = sprite.ToRegionAttachment(PartsNewMaterial[index], rotate);
			NewAttachment.RegionWidth = (int)sprite.textureRect.width;
			NewAttachment.RegionHeight = (int)sprite.textureRect.height;
			NewAttachment.RegionOffsetX = sprite.textureRectOffset.x;;
			NewAttachment.RegionOffsetY = sprite.textureRectOffset.y;;
			var boneRotate = Parts[index].Bone.WorldRotationX;
			var bonePos = Quaternion.AngleAxis(boneRotate, Vector3.forward) * new Vector2(Parts[index].Bone.WorldX, Parts[index].Bone.WorldY);
			NewAttachment.X = offset.x + bonePos.x * 0.05f * u1;
			NewAttachment.Y = offset.y + bonePos.y * 0.05f * v1;
			NewAttachment.Rotation = -boneRotate;
			NewAttachment.ScaleX = scale.x;
			NewAttachment.ScaleY = scale.y;
			NewAttachment.UpdateOffset();
			Parts[(int)index].Attachment = NewAttachment;
		}

		/// <summary>
		/// 接換動作
		/// </summary>
		/// <param name=""></param>
		public void SwitchAnimation(MainRoleAnimState state, bool IsLoop = true)
		{
			anim.AnimationState.SetAnimation(0, System.Enum.GetName(typeof(MainRoleAnimState), state).ToLower() + "1", IsLoop);
		}

		/// <summary>
		/// 根據位置轉向
		/// </summary>
		/// <param name="Sign">方向</param>
		public void FilpSpine(float Sign)
		{
			this.gameObject.transform.localScale =
				new Vector3(Sign * Mathf.Abs(this.gameObject.transform.localScale.x), this.gameObject.transform.localScale.y, 1);
		}

		/// <summary>
		/// 根據服飾表的 ID
		/// 找出對應的圖
		/// </summary>
		/// <param name="ID">服飾表</param>
		/// <returns>檔案</returns>
		public static Dictionary<string, object> FindClothingByID(long ID)
		{
			Dictionary<string, object>[] clothingArray = (Dictionary<string, object>[])Helper.GameDB.Data["MainRoleClothingID"];
			for (int i = 0; i < clothingArray.Length; i++)
			{
				Dictionary<string, object> clothingObj = clothingArray[i] as Dictionary<string, object>;
				if ((long)clothingObj["ID"] == ID)
					return clothingObj;
			}
			return null;
		}

		/// <summary>
		/// 部位對應關係
		/// </summary>
		/// <param name="index">從 JSON 傳來的 Parts</param>
		/// <returns>實際對應的程式的 Index</returns>
		public static ROLE_SLOT_INDEX PartsMapping(int index)
		{
			switch (index)
			{
				case 1:
					return ROLE_SLOT_INDEX.HEAD;
				case 2:
					return ROLE_SLOT_INDEX.BODY;
				case 3:
					return ROLE_SLOT_INDEX.LEFT_HAND;
				case 4:
					return ROLE_SLOT_INDEX.RIGHT_HAND;
				case 5:
					return ROLE_SLOT_INDEX.HEAD_DECORATION;
				case 7:
					return ROLE_SLOT_INDEX.BACK_DECORATION;
			}
			Debug.LogError("Parts Mapping Error: " + index.ToString());
			return ROLE_SLOT_INDEX.NONE;
		}

		/// <summary>
		/// 是否有從編輯器中
		/// 編輯位移資訊
		/// </summary>
		/// <returns> Boolean </returns>
		public static bool IsOffsetInfo(Dictionary<string, object> dict)
		{
			if (dict.ContainsKey("OffsetX") && dict.ContainsKey("OffsetY") && dict.ContainsKey("Rotate") && dict.ContainsKey("ScaleX") && dict.ContainsKey("ScaleY"))
				return true;
			return false;
		}
	}
}