2D轮转图实现蒙皮、骨骼换装

首先你要会2D轮转图。

通过2D轮转图、蒙皮网格渲染器和合并骨骼实现换装。 

首先是2D轮转图与蒙皮脚本的关联,下面代码中的changeAvator.Change()方法。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MyCyclogram2D : MonoBehaviour, IDragHandler, IEndDragHandler
{
    List<GameObject> m_List = new List<GameObject>();
    List<Transform> m_Trans = new List<Transform>();
    public GameObject m_Prefab;//图片预制体
    int m_Num;//图片数量
    int indexHead = 11;
    int indexLeg = 5;
    int indexClothes = 4;
    float m_Rad;//弧度
    string partName = "";//部位名称
    public float m_Spacing;
    float m_Radius;//半径
    float m_MoveRad;//移动弧度
    public ChangeAvator changeAvator;

    private void Start()
    {
        //截取部位信息
        string objName = transform.name;
        partName = objName.Split('-')[1];
        if (partName == "Head")
        {
            m_Num = indexHead;
        }
        else if (partName == "Leg")
        {
            m_Num = indexLeg;
        }
        else if (partName == "Clothes")
        {
            m_Num = indexClothes;
        }
        m_Rad = 2 * Mathf.PI / m_Num;
        m_Radius = (m_Prefab.GetComponent<RectTransform>().rect.width + m_Spacing) * m_Num / (2 * Mathf.PI);
        OnMove();
    }

    private void OnMove()
    {
        for (int i = 0; i < m_Num; i++)
        {
            float x = Mathf.Sin(i * m_Rad + m_MoveRad) * m_Radius;
            float z = Mathf.Cos(i * m_Rad + m_MoveRad) * m_Radius;
            if (m_List.Count <= i)
            {
                GameObject go = Instantiate(m_Prefab, transform);
                go.GetComponent<Image>().sprite = Resources.Load<Sprite>(partName + "/" + i.ToString());
                go.name = i.ToString();
                m_List.Add(go);
                m_Trans.Add(go.transform);
            }
            m_List[i].transform.localPosition = new Vector3(x, 0, 0);
            float scale = (z + m_Radius) / (2 * m_Radius) * 0.5f + 0.5f;
            m_List[i].transform.localScale = Vector3.one * scale;
        }
        //通过localScale的z值排序
        m_Trans.Sort((a, b) =>
        {
            return (int)(a.localScale.z * 100 - b.localScale.z * 100);
        });
        //排序后更改unity中的层级关系
        for (int i = 0; i < m_Trans.Count; i++)
        {
            m_Trans[i].SetSiblingIndex(i);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        m_MoveRad += eventData.delta.x / m_Radius;
        OnMove();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        DT.To((a) =>
        {
            //惯性
            m_MoveRad += a;
            OnMove();
        }, eventData.delta.x, 0, 1.5f).OnComplete(() =>
        {
            //对齐
            float offsetRad = Mathf.Asin(m_Trans[m_Num - 1].localPosition.x / m_Radius);
            DT.To((a) =>
            {
                m_MoveRad = a;
                OnMove();
            }, m_MoveRad, m_MoveRad - offsetRad, 1).OnComplete(() =>
            {
                //对齐结束后换装
                if (partName == "Head")
                {
                    changeAvator.m_Objs[0] = Resources.Load<GameObject>("Prefab/Tou_" + m_Trans[m_Num - 1].GetComponent<Image>().sprite.name);
                    changeAvator.Change();
                }
                else if (partName == "Leg")
                {
                    changeAvator.m_Objs[1] = Resources.Load<GameObject>("Prefab/Tui_" + m_Trans[m_Num - 1].GetComponent<Image>().sprite.name);
                    changeAvator.Change();
                }
                else if (partName == "Clothes")
                {
                    changeAvator.m_Objs[2] = Resources.Load<GameObject>("Prefab/YiFu_" + m_Trans[m_Num - 1].GetComponent<Image>().sprite.name);
                    changeAvator.Change();
                }
            });
        });
    }
}

下面是蒙皮与换骨骼脚本代码。

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

public class ChangeAvator : MonoBehaviour
{
    public List<GameObject> m_Objs;//人物部位部件
    private void Start()
    {
        gameObject.AddComponent<SkinnedMeshRenderer>();
        Change();
    }

    public void Change()
    {
        #region 蒙皮网格渲染器的属性赋值
        List<CombineInstance> combines = new List<CombineInstance>();
        List<Material> materials = new List<Material>();//材质集合
        foreach (var item in m_Objs)//遍历所有人物部件
        {
            CombineInstance com=new CombineInstance();
            com.mesh = item.GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh;//每个部件上的 网格信息 赋值给合并器
            combines.Add(com);//添加到集合中
            materials.Add(item.GetComponentInChildren<SkinnedMeshRenderer>().sharedMaterial);//每个部件上的 材质信息 合并到材质集合中
        }
        Mesh mesh = new Mesh();//新建一个网格
        mesh.CombineMeshes(combines.ToArray(), false, false);//合并网格数组,赋值给网格对象
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh = mesh;//给皮肤网格渲染器赋值网格信息
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterials = materials.ToArray();//给皮肤网格赋值材质信息
        #endregion


        #region 合并骨骼,动画基于骨骼
        Transform[] allBones = GetComponentsInChildren<Transform>();//挂载此脚本游戏对象的所有Transform组件
        Dictionary<string, Transform> bonesDiC = new Dictionary<string, Transform>();//骨骼字典
        foreach (var item in allBones)
        {
            bonesDiC.Add(item.name, item);//添加到骨骼字典
        }
        List<Transform> bones = new List<Transform>();//存储需要改变的部位骨骼
        foreach (var item in m_Objs)//遍历部位模型,在轮转图中,被选中的人物部件,把骨骼信息对应上
        {
            Transform[] bodyBones = item.GetComponentInChildren<SkinnedMeshRenderer>().bones;//获取部位模型身上的所有骨骼
            foreach (var item2 in bodyBones)//遍历部位模型身上的所有骨骼
            {
                if (bonesDiC.ContainsKey(item2.name))//骨骼字典中包含部位模型中的骨骼
                {
                    //这里千万不要写成  bones.Add(item2);   否则后续骨骼移动会出现大问题!
                    bones.Add(bonesDiC[item2.name]);//将部位模型中的骨骼添加到需要改变的部位骨骼集合
                }
            }
        }
        gameObject.GetComponent<SkinnedMeshRenderer>().bones = bones.ToArray();//骨骼数据赋值给皮肤网格渲染器
        #endregion
    }
}

在二维轮播图中,通常会有一个背景图像固定不变,而按钮作为导航控制元素,会随着用户的交互(比如点击事件)动态地切换显示的文字内容。这种设计允许用户通过点击不同的按钮来切换图片展示的内容,同时保持背景画面的一致性。 实现这一功能,你需要准备一组预设的按钮文字,对应每一张图片。在HTML中,可以设置每个按钮的初始状态和`onclick`事件,当按钮被点击时触发JavaScript或jQuery函数。这个函数会更新当前显示的按钮文本,同时管理轮播图的索引,让下一张图片显示出来。如果使用的是CSS动画或JavaScript库如Swiper.js等,还需要对轮播图进行相应的操作,以便实现图片的切换。 示例代码: ```html <div class="carousel"> <img src="image1.jpg" alt="Image 1"> <button id="btn1">按钮1</button> <button id="btn2" style="display: none;">按钮2</button> <!-- 添加更多按钮... --> </div> <script> let currentSlide = 0; function switchButtons(text) { // 隐藏当前按钮并显示新的按钮文字 document.getElementById("btn" + currentSlide).style.display = "none"; document.getElementById("btn" + (currentSlide + 1)).innerText = text; // 更新按钮和轮播图索引 currentSlide = (currentSlide + 1) % buttons.length; // 确保索引不会超过总按钮数 showSlide(currentSlide); } // 轮播图片的显示方法 function showSlide(index) { document.querySelector('.carousel img').src = 'image' + (index + 1) + '.jpg'; switchButtons('新按钮文字'); // 根据需要更改按钮文字 } // 当按钮被点击时,触发切换 document.getElementById('btn1').addEventListener('click', function() { switchButtons('新按钮1'); }); </script> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值