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<string, Dictionary<string, Transform>> data = new Dictionary<string, Dictionary<string, Transform>>();
//保存带有蒙皮渲染组件的部位名称和对应的蒙皮网格渲染组件
public Dictionary<string, SkinnedMeshRenderer> partSMR = new Dictionary<string, SkinnedMeshRenderer>();
//目标骨骼位置信息
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<Transform>();
Change();
}
/// <summary>
/// 实例化目标物体
/// </summary>
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);
}
/// <summary>
/// 实例化模板物体
/// </summary>
public void InsTemplatePlayer()
{
templatePlayer = Instantiate(Resources.Load("FemaleAvatar") as GameObject);
templateTrans = templatePlayer.transform;
//因为这里我们不需要模板显示,只是需要模板信息,所以可以选择关闭模板的活跃
templatePlayer.SetActive(false);
}
/// <summary>
/// 保存模板里有蒙皮渲染组件的物体数据
/// </summary>
public void SaveData(GameObject template)
{
//首先清空原有数据
data.Clear();
partSMR.Clear();
if (template == null)
return;
SkinnedMeshRenderer[] smrs = template.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (SkinnedMeshRenderer smr in smrs)
{
string[] names = smr.name.Split('-');
if (!data.ContainsKey(names[0]))
{
//print(names[0]);
data.Add(names[0], new Dictionary<string, Transform>());
GameObject obj = new GameObject();
obj.AddComponent<SkinnedMeshRenderer>();
obj.name = names[0];
obj.transform.parent = targetPlayer.transform;
obj.transform.position = smr.gameObject.transform.position;
partSMR.Add(obj.name, obj.GetComponent<SkinnedMeshRenderer>());
}//print(data[names[0]]);
data[names[0]].Add(names[1], smr.transform);
}
}
/// <summary>
/// 换装(可以更换每个部位的信息)
/// </summary>
/// <param name="part">部位</param>
/// <param name="ID">编号</param>
public void ReLoading(string part,string ID)
{
SkinnedMeshRenderer smrs = data[part][ID].GetComponent<SkinnedMeshRenderer>();
List<Transform> bones = new List<Transform>();
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的网格,材质球是可以直接进行赋值的。