换装原理初探

换装系列文章:
换装原理初探
换装原理中篇
换装原理实践
换装英文中称为Character Customization,在游戏中很常见。换装的基本步骤如下。

  • MaleModel预设制作,此模型包括所有样式的SkinnedMeshRenderer和骨骼,并以一定规则命名,比如eye有三种,则命名为eye-1,eye-2,eye-3。
  • MaleTarget预设制作,此模型只包含骨骼。
  • 加载MaleModel和MaleTarget。
  • 保存数据,将MaleModel中的所有样式SkinnedMeshRenderer组件保存在字典中maleData,将MaleTarget中的骨骼保存在数组maleHips中,为MaleTarget添加所有身体部件,例如eye、body,并将此保存到另一个字典中targetData。
  • 换装,在给定身体部件名称和序号的情况下,从maleData数组中找到相应的SkinnedMeshRenderer组件part,从中提取骨骼信息,遍历骨骼,在MaleTarget中的骨骼中找到对应骨骼,并保存为数组bones。将MaleTarget相应的SkinnedMeshRenderer组件中的骨骼绑定为bones,网格替换为part的网格,材质替换为part的材质。
    最后,给出相应的代码如下。
using System.Collections.Generic;
using UnityEngine;

public class AvataCustomization : MonoBehaviour
{
    private Transform maleModelTrans;
    private Transform maleTargetTrans;

    private Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> maleData = new Dictionary<string, Dictionary<string, SkinnedMeshRenderer>>();
    private Dictionary<string, SkinnedMeshRenderer> targetData = new Dictionary<string, SkinnedMeshRenderer>();
    private Transform[] maleHips;

    private void Start()
    {
        InitiateModel();
        InitiateTarget();
        SaveData();
    }

    void InitiateModel()
    {
        GameObject maleModel = GameObject.Instantiate(Resources.Load("MaleModel")) as GameObject;
        maleModelTrans = maleModel.transform;
        maleModel.SetActive(false);
    }

    void InitiateTarget()
    {
        GameObject maleTarget = GameObject.Instantiate(Resources.Load("MaleTarget")) as GameObject;
        maleTargetTrans = maleTarget.transform;       
    }

    void SaveData()
    {
        SkinnedMeshRenderer[] parts = maleModelTrans.GetComponentsInChildren<SkinnedMeshRenderer>();
        maleHips = maleTargetTrans.GetComponentsInChildren<Transform>();
        foreach (SkinnedMeshRenderer part in parts)
        {
            string[] names = part.name.Split('-');

            if(!maleData.ContainsKey(names[0]))
            {
                GameObject partGo = new GameObject();
                partGo.name = names[0];
                partGo.transform.SetParent(maleTargetTrans);
                maleData.Add(names[0], new Dictionary<string, SkinnedMeshRenderer>());
                targetData.Add(names[0], partGo.AddComponent<SkinnedMeshRenderer>());
            }
            maleData[names[0]].Add(names[1], part);
        }
    }

    void ChangeStyle(string partName, string num)
    {
        SkinnedMeshRenderer part = maleData[partName][num];
        List<Transform> bones = new List<Transform>();
        foreach(var trans in part.bones)
        {
            foreach(var bone in maleHips)
            {
                if(bone.name == trans.name)
                {
                    bones.Add(bone);
                    break;
                }
            }
        }
        targetData[partName].bones = bones.ToArray();
        targetData[partName].sharedMesh = part.sharedMesh;
        targetData[partName].material = part.material;
    }
}

你可能感兴趣的:(游戏)