Unity物体骨骼换装系统

Unity的换装系统是为了优化Unity资源,增加游戏乐趣,换装有两种,一种是增添式换装,比如给人物加个武器,装备翅膀等等,另外一种就是下面我要说的更新式换装,比如更换皮肤,更换武器,更换装备等等,换装还是很常见的功能,也是比较重要的知识点,那么,先看下代码吧:

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

public class AvatarSystem : MonoBehaviour
{
    public GameObject targetPlayer;
    public GameObject templatePlayer;

    public Transform targetTrans;
    public Transform templateTrans;

    //保存部位名称,编号和部位位置信息
    public Dictionary> data = new Dictionary>();
    //保存带有蒙皮渲染组件的部位名称和对应的蒙皮网格渲染组件
    public Dictionary partSMR = new Dictionary();

    //目标骨骼位置信息
    public Transform[] targetBones;

    //换装
    public string[,] avatarstr1 = new string[,] { { "coat", "001" }, { "hair", "001" }, { "pant", "001" }, { "hand", "003" }, { "foot", "003" }, { "head", "003" } };


    public void Start()
    {
        InsTemplatePlayer();
        InsTargetPlayer(2f);
        SaveData(templatePlayer);
        targetBones = targetPlayer.GetComponentsInChildren();
        Change();
    }

    /// 
    /// 实例化目标物体
    /// 
    public void InsTargetPlayer(float pos_x)
    {
        targetPlayer = Instantiate(Resources.Load("targetmodel") as GameObject);
        targetTrans = targetPlayer.transform;
      
        targetPlayer.transform.position = new Vector3(pos_x, 0, 0);
    }
    /// 
    /// 实例化模板物体
    /// 
    public void InsTemplatePlayer()
    {
        templatePlayer = Instantiate(Resources.Load("FemaleAvatar") as GameObject);
        templateTrans = templatePlayer.transform;
      
        //因为这里我们不需要模板显示,只是需要模板信息,所以可以选择关闭模板的活跃
        templatePlayer.SetActive(false);
    }

    /// 
    /// 保存模板里有蒙皮渲染组件的物体数据
    /// 
    public void SaveData(GameObject template)
    {
        //首先清空原有数据
        data.Clear();
        partSMR.Clear();

        if (template == null)
            return;

        SkinnedMeshRenderer[] smrs = template.GetComponentsInChildren();
        
        foreach (SkinnedMeshRenderer smr in smrs)
        {
            string[] names = smr.name.Split('-');
           
            if (!data.ContainsKey(names[0]))
            {
                //print(names[0]);
                data.Add(names[0], new Dictionary());
                GameObject obj = new GameObject();
                obj.AddComponent();
                obj.name = names[0];
                obj.transform.parent = targetPlayer.transform;
                obj.transform.position = smr.gameObject.transform.position;
                
                partSMR.Add(obj.name, obj.GetComponent());
                
            }//print(data[names[0]]);
                data[names[0]].Add(names[1], smr.transform);
           
        }
    }

    /// 
    /// 换装(可以更换每个部位的信息)
    /// 
    /// 部位
    /// 编号
    public void ReLoading(string part,string ID)
    {
        SkinnedMeshRenderer smrs = data[part][ID].GetComponent();
        List bones = new List();
        foreach (Transform smr in smrs.bones)
        {
            foreach (Transform targetBone in targetBones)
            {
                if (targetBone.name == smr.name)
                {
                    bones.Add(targetBone);
                    print(targetBone.name +"     "+ targetBone);
                    break; 
                }
            }
        }
        partSMR[part].sharedMesh = smrs.sharedMesh;
        partSMR[part].materials = smrs.materials;
        partSMR[part].bones = bones.ToArray();
    }


    public void Change()
    {
        int count = avatarstr1.GetLength(0);
        for (int i = 0; i < count; i++)
        {
            ReLoading(avatarstr1[i, 0], avatarstr1[i, 1]);
        }
    }
}

上面的脚本就是一个简单的更新式换装脚本,更新式换装脚本的思路是,首先建立一个模板,然后建立一个和模板的骨骼列表一样的物体,但是除了骨骼列表之外别的什么都没有,然后,将模板和目标都实例化出来,之后取的模板的模型Mesh信息,根据信息给目标添加模型Mesh,添加之后需要给模型Mesh上网格,材质以及让模型Mesh和骨骼列表之间关联起来,这里注意一个点,用这种方法的时候,模型Mesh的骨骼列表不可以直接进行赋值,需要有个集合将模板的模型Mesh上面的骨骼列表保存起来然后把这个集合赋值给目标模型Mesh的骨骼列表,模型Mesh的网格,材质球是可以直接进行赋值的。

 

要做模型换装,程序就得和美术提前商量好,每个部位的名称,编号一定要做好,不然后期是个麻烦事,还得一个一个的找。

你可能感兴趣的:(实战核心技术,Avatar,Unity换装,骨骼)