2D rotation map realizes skinning and bone dressing

First you need to know how to rotate 2D graphics.

Achieve costume changes through 2D rotation maps, skinned mesh renderers and merged bones.

The first is the association between the 2D rotation map and the skinning script, the changeAvator.Change() method in the code below.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MyCyclogram2D : MonoBehaviour, IDragHandler, IEndDragHandler
{
    List<GameObject> m_List = new List<GameObject>();
    List<Transform> m_Trans = new List<Transform>();
    public GameObject m_Prefab;//Picture prefab
    int m_Num;//number of pictures
    int indexHead = 11;
    int indexLeg = 5;
    int indexClothes = 4;
    float m_Rad;//radians
    string partName = "";//Part name
    public float m_Spacing;
    float m_Radius;//Radius
    float m_MoveRad;//Move radians
    public ChangeAvator changeAvator;

    private void Start()
    {
        //Intercept part information
        string objName = transform.name;
        partName = objName.Split('-')[1];
        if (partName == "Head")
        {
            m_Num = indexHead;
        }
        else if (partName == "Leg")
        {
            m_Num = indexLeg;
        }
        else if (partName == "Clothes")
        {
            m_Num = indexClothes;
        }
        m_Rad = 2 * Mathf.PI / m_Num;
        m_Radius = (m_Prefab.GetComponent<RectTransform>().rect.width + m_Spacing) * m_Num / (2 * Mathf.PI);
        OnMove();
    }

    private void OnMove()
    {
        for (int i = 0; i < m_Num; i + + )
        {
            float x = Mathf.Sin(i * m_Rad + m_MoveRad) * m_Radius;
            float z = Mathf.Cos(i * m_Rad + m_MoveRad) * m_Radius;
            if (m_List.Count <= i)
            {
                GameObject go = Instantiate(m_Prefab, transform);
                go.GetComponent<Image>().sprite = Resources.Load<Sprite>(partName + "/" + i.ToString());
                go.name = i.ToString();
                m_List.Add(go);
                m_Trans.Add(go.transform);
            }
            m_List[i].transform.localPosition = new Vector3(x, 0, 0);
            float scale = (z + m_Radius) / (2 * m_Radius) * 0.5f + 0.5f;
            m_List[i].transform.localScale = Vector3.one * scale;
        }
        //Sort by z value of localScale
        m_Trans.Sort((a, b) =>
        {
            return (int)(a.localScale.z * 100 - b.localScale.z * 100);
        });
        //Change the hierarchical relationship in unity after sorting
        for (int i = 0; i < m_Trans.Count; i + + )
        {
            m_Trans[i].SetSiblingIndex(i);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        m_MoveRad + = eventData.delta.x / m_Radius;
        OnMove();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        DT.To((a) =>
        {
            //inertia
            m_MoveRad + = a;
            OnMove();
        }, eventData.delta.x, 0, 1.5f).OnComplete(() =>
        {
            //align
            float offsetRad = Mathf.Asin(m_Trans[m_Num - 1].localPosition.x / m_Radius);
            DT.To((a) =>
            {
                m_MoveRad = a;
                OnMove();
            }, m_MoveRad, m_MoveRad - offsetRad, 1).OnComplete(() =>
            {
                //Change after alignment
                if (partName == "Head")
                {
                    changeAvator.m_Objs[0] = Resources.Load<GameObject>("Prefab/Tou_" + m_Trans[m_Num - 1].GetComponent<Image>().sprite.name);
                    changeAvator.Change();
                }
                else if (partName == "Leg")
                {
                    changeAvator.m_Objs[1] = Resources.Load<GameObject>("Prefab/Tui_" + m_Trans[m_Num - 1].GetComponent<Image>().sprite.name);
                    changeAvator.Change();
                }
                else if (partName == "Clothes")
                {
                    changeAvator.m_Objs[2] = Resources.Load<GameObject>("Prefab/YiFu_" + m_Trans[m_Num - 1].GetComponent<Image>().sprite.name);
                    changeAvator.Change();
                }
            });
        });
    }
}

The following is the skinning and bone replacement script code.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeAvator : MonoBehaviour
{
    public List<GameObject> m_Objs;//character parts
    private void Start()
    {
        gameObject.AddComponent<SkinnedMeshRenderer>();
        Change();
    }

    public void Change()
    {
        #region Attribute assignment of skinned mesh renderer
        List<CombineInstance> combines = new List<CombineInstance>();
        List<Material> materials = new List<Material>();//Material collection
        foreach (var item in m_Objs)//Traverse all character parts
        {
            CombineInstance com=new CombineInstance();
            com.mesh = item.GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh;//Assign the mesh information on each component to the combiner
            combines.Add(com);//Add to the collection
            materials.Add(item.GetComponentInChildren<SkinnedMeshRenderer>().sharedMaterial);//The material information on each component is merged into the material collection
        }
        Mesh mesh = new Mesh();//Create a new mesh
        mesh.CombineMeshes(combines.ToArray(), false, false);//Combine mesh arrays and assign values to mesh objects
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh = mesh;//Assign mesh information to the skin mesh renderer
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterials = materials.ToArray();//Assign material information to the skin mesh
        #endregion


        #region merges bones, animation is based on bones
        Transform[] allBones = GetComponentsInChildren<Transform>();//Mount all Transform components of this script game object
        Dictionary<string, Transform> bonesDiC = new Dictionary<string, Transform>();//Bone dictionary
        foreach (var item in allBones)
        {
            bonesDiC.Add(item.name, item);//Add to bone dictionary
        }
        List<Transform> bones = new List<Transform>();//Storage the bones that need to be changed
        foreach (var item in m_Objs)//Traverse the part model, in the rotation diagram, the selected character parts correspond to the bone information
        {
            Transform[] bodyBones = item.GetComponentInChildren<SkinnedMeshRenderer>().bones;//Get all the bones on the part model
            foreach (var item2 in bodyBones)//Traverse all bones on the body model
            {
                if (bonesDiC.ContainsKey(item2.name))//The bone dictionary contains the bones in the part model
                {
                    //Do not write bones.Add(item2); otherwise there will be big problems with subsequent bone movement!
                    bones.Add(bonesDiC[item2.name]);//Add the bones in the part model to the part bone collection that needs to be changed
                }
            }
        }
        gameObject.GetComponent<SkinnedMeshRenderer>().bones = bones.ToArray();//Assign bone data to the skin mesh renderer
        #endregion
    }
}