首先在Canvas下创建一个空对象,在空对象身上挂轮转图的脚本。如图:
空对象的命名有要求,对应换装的位置。在场景中放一个调式好的模型:
1 做好裸模,绑好骨骼。
2 做出模型需要更换的装备,刷好权重。每个部位需要拆分成单独的模型。比如衣服,头,脚等。
3 导出裸模与装备模型到unity,每种模型都需要包含骨骼,因为换装依赖的组件是SkinnedMeshRenderer,只有包含骨骼的模型,导入到unity中才会生成该组件。不包含骨骼的模型,导入到unity中只会生成Mesh Renderer。
如图:
2D轮转图代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using DG.Tweening;
using System;
public class ClcoyGram2D : MonoBehaviour,IDragHandler,IEndDragHandler
{
public Image prefab;
public int n;
public float spacing = 100;
public float max = 1f;
public float min = 0.5f;
float c;
float r;
float ang;
public string path;
List<Image> list = new List<Image>();
List<Transform> sortlist = new List<Transform>();
float moveAng = 0;
public float cut = 100;
// Start is called before the first frame update
void Start()
{
c = (prefab.rectTransform.rect.width + spacing) * n;
r = c / (Mathf.PI * 2);
ang = (Mathf.PI * 2) / n;
Move();
}
private void Move()
{
for (int i = 0; i < n; i++)
{
if (list.Count<=i)
{
Image icon = Instantiate(prefab, transform);
icon.sprite = Resources.Load<Sprite>("Ti/" + path + i);
list.Add(icon);
list[i].transform.name = i.ToString();
sortlist.Add(list[i].transform);
}
float x = Mathf.Sin(i * ang+moveAng) * r;
float z = Mathf.Cos(i * ang+moveAng) * r;
float p = (z + r) / (r * 2);
float scale = (max - min) * p + min;
list[i].rectTransform.anchoredPosition = new Vector2(x, 0);
list[i].transform.localScale = Vector3.one * scale;
}
sortlist.Sort((a, b) => {
if (a.lossyScale.x<b.lossyScale.x)
{
return -1;
}
else if(a.lossyScale.x == b.lossyScale.x)
{
return 0;
}
else
{
return 1;
}
});
for (int i = 0; i < sortlist.Count; i++)
{
sortlist[i].SetSiblingIndex(i);
}
}
// Update is called once per frame
void Update()
{
}
public void OnDrag(PointerEventData eventData)
{
float dis = eventData.delta.x;
float dragAng = dis / r;
moveAng += dragAng;
Move();
}
public void OnEndDrag(PointerEventData eventData)
{
float speed = eventData.delta.x;
float time = Mathf.Abs(speed) / cut;
DT.To((a) => {
float dragAng = a / r;
moveAng += dragAng;
Move();
},speed,0,time).OnComplete(()=> {
Align();
});
}
private void Align()
{
float AlignAng = Mathf.Asin(sortlist[n - 1].GetComponent<RectTransform>().anchoredPosition.x / r);
float Aligndis = AlignAng * r;
float time = Mathf.Abs(Aligndis) / cut;
DT.To((a) => {
moveAng = a;
Move();
},moveAng,moveAng-AlignAng,time).OnComplete(()=> {
int num = int.Parse(transform.name);
Reloading.ins.GetBodys(num, path + int.Parse(sortlist[n - 1].transform.name));
});
}
}
通过轮转图里对齐后的回调方法去调用换装里封装好的方法。
换装代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Reloading : MonoBehaviour
{
public GameObject[] bodys;
public static Reloading ins = null;
private void Awake()
{
ins = this;
}
// Start is called before the first frame update
void Start()
{
OnPlane(bodys);
}
public void GetBodys(int type,string path)
{
bodys[type] = Resources.Load<GameObject>("Prefab/" + path);
OnPlane(bodys);
}
private void OnPlane(GameObject[] bodys)
{
List<CombineInstance> combines = new List<CombineInstance>();
List<Material> materials = new List<Material>();
List<Transform> mybodys = new List<Transform>();
Transform[] allbodys = GetComponentsInChildren<Transform>();
Dictionary<string, Transform> BodysDic = new Dictionary<string, Transform>();
foreach (var item in allbodys)
{
BodysDic.Add(item.name, item);
}
for (int i = 0; i < bodys.Length; i++)
{
CombineInstance combine = new CombineInstance();
combine.mesh = bodys[i].GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh;
combines.Add(combine);
materials.Add(bodys[i].GetComponentInChildren<SkinnedMeshRenderer>().sharedMaterial);
Transform[] bones = bodys[i].GetComponentInChildren<SkinnedMeshRenderer>().bones;
for (int j = 0; j < bones.Length; j++)
{
if (BodysDic.ContainsKey(bones[j].name))
{
mybodys.Add(BodysDic[bones[j].name]);
}
}
}
Mesh mesh = new Mesh();
mesh.CombineMeshes(combines.ToArray(), false, false);
GetComponent<SkinnedMeshRenderer>().sharedMesh = mesh;
GetComponent<SkinnedMeshRenderer>().sharedMaterials = materials.ToArray();
GetComponent<SkinnedMeshRenderer>().bones = mybodys.ToArray();
}
}
从Resources中加载预制体,从预制体身上的SkinnedMeshRenderer中读取骨骼,材质,Mesh(网格)。存贮这些数据,并加载进裸模的SkinnedMeshRenderer中去。