//皮肤上关键的一个组件是SkinnedMeshRenderer,它关联了3样东西:1.网格Mesh(蒙皮);2.骨骼Hips;3.材质。所以我们只要在代码中改变以上三样东西
//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AvatarSys : MonoBehaviour {
public static AvatarSys _instance;
//女孩变量
private Transform girlSourceTrans;//模型的位置信息
private GameObject girlTarget;//保存骨架物体,换装的人
//小女孩所有的资源信息,字典意义:1部位,2编号,3定位对应的skm
private Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> girlData = new Dictionary<string, Dictionary<string, SkinnedMeshRenderer>>();
Transform[] girlHips;//小女孩所有骨骼信息
//换装骨骼身上的SkinnedMeshRenderer信息,部位的名字,对应的skm
private Dictionary<string, SkinnedMeshRenderer> girlSmr = new Dictionary<string, SkinnedMeshRenderer>();
//男孩变量
private Transform boySourceTrans;//模型的位置信息
private GameObject boyTarget;//保存骨架物体,换装的人
//小男孩所有的资源信息,字典意义:1部位,2编号,3定位对应的skm
private Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> boyData = new Dictionary<string, Dictionary<string, SkinnedMeshRenderer>>();
Transform[] boyHips;//所有骨骼信息
//换装骨骼身上的SkinnedMeshRenderer信息,部位的名字,对应的skm
private Dictionary<string, SkinnedMeshRenderer> boySmr = new Dictionary<string, SkinnedMeshRenderer>();
private void Awake()
{
_instance = this;
DontDestroyOnLoad(this.gameObject);//不删除游戏物体
}
//初始化信息,可以用来存储换装数据
private string[,] str = new string[,] {
{ "eyes", "1" },
{ "hair", "1" },
{ "top", "1" },
{ "shoes", "1" },
{"pants" ,"1"},
{ "face", "1" }
};
public int nowCount = 0;//0为小女孩,1为小男孩
public GameObject girlPanel;
public GameObject boyPanel;
//Use this for initialization(初始化信息)
void Start()
{
GirlAvatar();
BoyAvatar();
boyTarget.SetActive(false);
}
public void GirlAvatar()//初始化女孩信息
{
//初始化人物信息
InstantiateGirl();
//存储需要用到的信息(将初始化的数据存入字典中)
SaveData(girlSourceTrans,girlData,girlSmr,girlTarget);
//初始化骨架,让她有蒙皮、材质、骨骼信息
InitAvatar(girlData,girlHips,girlSmr);
}
public void BoyAvatar()//初始化男孩信息
{
//初始化人物信息
InstantiateBoy();
//存储需要用到的信息(将初始化的数据存入字典中)
SaveData(boySourceTrans,boyData,boySmr,boyTarget);
//初始化骨架,让她有蒙皮、材质、骨骼信息
InitAvatar(boyData,boyHips,boySmr);
}
//gril参数
void InstantiateGirl()
{
//初始化人物资源
//加载资源物体,从resource文件夹获取其中的物体,go为femalemodel,保存资源model,各种衣服头发等信息
GameObject go = Instantiate(Resources.Load("FemaleModel")) as GameObject;//as为强制转换
girlSourceTrans = go.transform;//获取游戏对象的位置信息
go.SetActive(false);//停用此游戏对象。
//初始化人物骨架
girlTarget = Instantiate(Resources.Load("FemaleTarget")) as GameObject;
//遍历FemaleTarget的组件(骨骼),赋给girlHips
girlHips = girlTarget.GetComponentsInChildren<Transform>();
//girlTarget.SetActive(false);//停用此游戏对象。
}
//boy参数
void InstantiateBoy()
{
//初始化人物资源
//加载资源物体,从resource文件夹获取其中的物体,go为femalemodel,保存资源model,各种衣服头发等信息
GameObject go = Instantiate(Resources.Load("MaleModel")) as GameObject;//as为强制转换
boySourceTrans = go.transform;//获取游戏对象的位置信息
go.SetActive(false);//停用此游戏对象。
//初始化人物骨架
boyTarget = Instantiate(Resources.Load("MaleTarget")) as GameObject;
//遍历FemaleTarget的组件(骨骼),赋给girlHips
boyHips = boyTarget.GetComponentsInChildren<Transform>();
//girlTarget.SetActive(falbse);//停用此游戏对象。
}
void SaveData(Transform souceTrans, Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> data,
Dictionary<string, SkinnedMeshRenderer> smr,
GameObject target)//存储需要用到的信息(将初始化的数据存入字典中)
{
data.Clear();//存储之前清空字典
smr.Clear();
if (souceTrans == null)
return;
//遍历所有子物体,将有SkinnedMeshRenderer的逐渐进行存储
SkinnedMeshRenderer[] parts = souceTrans.GetComponentsInChildren<SkinnedMeshRenderer>();
//通过split函数将名字以'-'拆分,把信息存到字典中
foreach (var part in parts)
{
string[] names = part.name.Split('-');//eyes-1拆分成eyes和1存储到names数组中
if (!data.ContainsKey(names[0]))//判断当前是否包含键(名字)
{//不包含名字,说明第一次遍历到,就是新的部位,需要生成对应部位,包括名字和SkinnedMeshRenderer只生成一个
GameObject partGo = new GameObject();
partGo.name = names[0];//无关信息,位置信息
//设置骨骼位置信息,让物体生成到骨骼下面
partGo.transform.parent = target.transform;
//把骨骼target身上的skm信息存储到小女孩中
smr.Add(names[0], partGo.AddComponent<SkinnedMeshRenderer>());
//资源库也存入该信息
data.Add(names[0], new Dictionary<string, SkinnedMeshRenderer>());
}
//将信息加载到girlData下面,part就是一个SkinnedMeshRenderer
data[names[0]].Add(names[1], part);//存储所有的skm信息到数据里面
}
}
//传入部位的名字、编号,从girlData取出对应的Smr,将Smr的材质、mesh、骨骼传递给小女孩骨骼上的Smr组件
void ChangeMesh(string part,string num, Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> data,
Transform[] hips,
Dictionary<string, SkinnedMeshRenderer> smr,
string[,] str
)
{
SkinnedMeshRenderer skm = data[part][num];//要更换的部位
List<Transform> bones = new List<Transform>();//临时动态链表,临时骨骼
foreach(var trans in skm.bones)//通过SkinnedMeshRenderer.bones,可以缠绕到现在mesh的骨头
{
foreach(var bone in hips)
{
if (bone.name == trans.name)
{
bones.Add(bone);
break;
}
}
}
//换装实现!!!
smr[part].bones = bones.ToArray();//换骨骼,将链表变成数组
smr[part].materials = skm.materials;//换材质,将所有材料拿过来
smr[part].sharedMesh = skm.sharedMesh;//换蒙皮
SaveData(part,num,str);
}
void InitAvatar(Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> data,
Transform[] hips,
Dictionary<string, SkinnedMeshRenderer> smr)//初始化骨架,让她有蒙皮、材质、骨骼信息
{
int length = str.GetLength(0);//获得行数
for (int i = 0; i < length; i++)
{
ChangeMesh(str[i, 0], str[i, 1], data, hips, smr,str);//穿上衣服
}
}
public void OnChangePeople(string part,string num)
{
if (nowCount == 0)//girl
{
ChangeMesh(part, num, girlData, girlHips, girlSmr, str);
}
else//boy
{
ChangeMesh(part, num, boyData, boyHips, boySmr, str);
}
}
public void sexChange()//性别转换,任务隐藏,模版隐藏
{
if (nowCount == 1)//显示男孩及其装扮面板
{
boyTarget.SetActive(true);
girlTarget.SetActive(false);
boyPanel.SetActive(true);
girlPanel.SetActive(false);
}
else//显示男孩及其装扮面板
{
boyTarget.SetActive(false);
girlTarget.Set