2D轮转图实现蒙皮、骨骼换装

首先你要会2D轮转图。

通过2D轮转图、蒙皮网格渲染器和合并骨骼实现换装。 

首先是2D轮转图与蒙皮脚本的关联,下面代码中的changeAvator.Change()方法。

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;//图片预制体
    int m_Num;//图片数量
    int indexHead = 11;
    int indexLeg = 5;
    int indexClothes = 4;
    float m_Rad;//弧度
    string partName = "";//部位名称
    public float m_Spacing;
    float m_Radius;//半径
    float m_MoveRad;//移动弧度
    public ChangeAvator changeAvator;

    private void Start()
    {
        //截取部位信息
        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;
        }
        //通过localScale的z值排序
        m_Trans.Sort((a, b) =>
        {
            return (int)(a.localScale.z * 100 - b.localScale.z * 100);
        });
        //排序后更改unity中的层级关系
        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) =>
        {
            //惯性
            m_MoveRad += a;
            OnMove();
        }, eventData.delta.x, 0, 1.5f).OnComplete(() =>
        {
            //对齐
            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(() =>
            {
                //对齐结束后换装
                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();
                }
            });
        });
    }
}

下面是蒙皮与换骨骼脚本代码。

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

public class ChangeAvator : MonoBehaviour
{
    public List<GameObject> m_Objs;//人物部位部件
    private void Start()
    {
        gameObject.AddComponent<SkinnedMeshRenderer>();
        Change();
    }

    public void Change()
    {
        #region 蒙皮网格渲染器的属性赋值
        List<CombineInstance> combines = new List<CombineInstance>();
        List<Material> materials = new List<Material>();//材质集合
        foreach (var item in m_Objs)//遍历所有人物部件
        {
            CombineInstance com=new CombineInstance();
            com.mesh = item.GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh;//每个部件上的 网格信息 赋值给合并器
            combines.Add(com);//添加到集合中
            materials.Add(item.GetComponentInChildren<SkinnedMeshRenderer>().sharedMaterial);//每个部件上的 材质信息 合并到材质集合中
        }
        Mesh mesh = new Mesh();//新建一个网格
        mesh.CombineMeshes(combines.ToArray(), false, false);//合并网格数组,赋值给网格对象
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh = mesh;//给皮肤网格渲染器赋值网格信息
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterials = materials.ToArray();//给皮肤网格赋值材质信息
        #endregion


        #region 合并骨骼,动画基于骨骼
        Transform[] allBones = GetComponentsInChildren<Transform>();//挂载此脚本游戏对象的所有Transform组件
        Dictionary<string, Transform> bonesDiC = new Dictionary<string, Transform>();//骨骼字典
        foreach (var item in allBones)
        {
            bonesDiC.Add(item.name, item);//添加到骨骼字典
        }
        List<Transform> bones = new List<Transform>();//存储需要改变的部位骨骼
        foreach (var item in m_Objs)//遍历部位模型,在轮转图中,被选中的人物部件,把骨骼信息对应上
        {
            Transform[] bodyBones = item.GetComponentInChildren<SkinnedMeshRenderer>().bones;//获取部位模型身上的所有骨骼
            foreach (var item2 in bodyBones)//遍历部位模型身上的所有骨骼
            {
                if (bonesDiC.ContainsKey(item2.name))//骨骼字典中包含部位模型中的骨骼
                {
                    //这里千万不要写成  bones.Add(item2);   否则后续骨骼移动会出现大问题!
                    bones.Add(bonesDiC[item2.name]);//将部位模型中的骨骼添加到需要改变的部位骨骼集合
                }
            }
        }
        gameObject.GetComponent<SkinnedMeshRenderer>().bones = bones.ToArray();//骨骼数据赋值给皮肤网格渲染器
        #endregion
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值