欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Unity绳子/绳索效果

程序员文章站 2022-07-02 11:23:57
老规矩先上图:最近在做一个做一个游戏,绳子缠绕在一起然后需要把绳子解开方能赢得游戏。因为需要用到一个绳子的效果,网了查了不少资料一方面是用插件Obi Rope 或 Megafiers 都可以实现,另一方面比较硬核的可以使用自己的算法也可以用关节什么的。但由于IOS14以上版本对代码审核非常严格,很多插件是无法使用的,只能自己写算法了,网上很多方法都是使用关节实现的绳子效果,绳子并非一条连贯的绳子,以下分享一实现的方式:一、使用铰链关节(Hinge Joint)把球体串起,保留Sphere Colli...

老规矩先上图:
Unity绳子/绳索效果

最近在做一个做一个游戏,绳子缠绕在一起然后需要把绳子解开方能赢得游戏。因为需要用到一个绳子的效果,网了查了不少资料一方面是用插件Obi Rope 或 Megafiers 都可以实现,另一方面比较硬核的可以使用自己的算法也可以用关节什么的。

但由于IOS14以上版本对代码审核非常严格,很多插件是无法使用的,只能自己写算法了,网上很多方法都是使用关节实现的绳子效果,绳子并非一条连贯的绳子,以下分享一实现的方式:
一、使用铰链关节(Hinge Joint)把球体串起,保留Sphere Collider和Rigidbody。
Unity绳子/绳索效果
二、随便找下物体挂上下面脚本,使物体可以被拖拽。

using UnityEngine;

public class MousePosHandle : MonoBehaviour
{
    #region 公有变量
    //------------------------------------------------------------------------------------

    //------------------------------------------------------------------------------------
    #endregion

    #region 私有变量
    //------------------------------------------------------------------------------------
    private Transform dragGameObject;
    private Vector3 offset;
    private bool isPicking;
    private Vector3 targetScreenPoint;
    //------------------------------------------------------------------------------------
    #endregion

    #region 公有方法
    #endregion

    #region 私有方法
    //------------------------------------------------------------------------------------
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            if (CheckGameObject())
            {
                offset = dragGameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetScreenPoint.z));
            }
        }

        if (isPicking)
        {
            //当前鼠标所在的屏幕坐标
            Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetScreenPoint.z);
            //把当前鼠标的屏幕坐标转换成世界坐标
            Vector3 curWorldPoint = Camera.main.ScreenToWorldPoint(curScreenPoint);
            Vector3 targetPos = curWorldPoint + offset;

            dragGameObject.position = targetPos;
        }

        if (Input.GetMouseButtonUp(0))
        {
            isPicking = false;
            if (dragGameObject != null)
            {
                dragGameObject = null;
            }
        }

    }
    //------------------------------------------------------------------------------------
    /// <summary>
    /// 检查是否点击到cbue
    /// </summary>
    /// <returns></returns>
    bool CheckGameObject()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hitInfo;
        if (Physics.Raycast(ray, out hitInfo, 1000f))
        {
            isPicking = true;
            //得到射线碰撞到的物体
            dragGameObject = hitInfo.collider.gameObject.transform;

            targetScreenPoint = Camera.main.WorldToScreenPoint(dragGameObject.position);
            return true;
        }
        return false;
    }
    //------------------------------------------------------------------------------------
    #endregion
}

三、 建模一个圆柱体网格大概是酱子,节不能太少因为绳子会不柔顺,也不能太多因为 性能会伤不起。
Unity绳子/绳索效果
四、加了一个可爱的贴图
Unity绳子/绳索效果
五、然后把球和网格放在一起。
Unity绳子/绳索效果
六、创建MonoBehaviour,添加脚本并挂上对应物体,通过先找到所有球

public MeshFilter TargetMesh;               //网格
public Transform BallGroup;                 //球体集合(关节上所有球放这)
private List<Transform> m_listBall;         //存放所有球体
private List<MeshData> m_listMeshData;      //节点数据

void Start()
 {
        m_listBall = new List<Transform>();
        foreach (Transform tran in BallGroup)
        {
            m_listBall.Add(tran);
        }
}

Unity绳子/绳索效果

七、提供一个方法,帮所有网格节点找到对应的球节点,网格自动寻找离自己最近的球为目标。

private Transform __FindNearest(Vector3 v3)
    {
        if (m_listBall != null)
        {
            float MaxDis = 999999;
            Transform MaxTran = null;
            for (int i = 0; i < m_listBall.Count; i++)
            {
                float curDis = Vector3.Distance(m_listBall[i].localPosition, v3);
                if (curDis < MaxDis)
                {
                    MaxDis = curDis;
                    MaxTran = m_listBall[i];
                }
            }
            return MaxTran;
        }
        return null;
    }

八、提供记录节点数据的数据结构

public class MeshData
{
    public int Index;               //索引
    public Transform target;        //目标球球
    public Vector3 offset;          //与目标球球位置差距
}

九、在Start中调用以下代码找到各节点的目标与位差信息

m_listMeshData = new List<MeshData>();
        int totleMeshPoint = TargetMesh.mesh.vertices.Length;
        for (int i = 0; i < totleMeshPoint; i++)
        {
            MeshData data = new MeshData();

            data.Index = i;
            data.target = __FindNearest(TargetMesh.mesh.vertices[i]);
            if (data.target == null) Debug.Log("有空的");
            data.offset = TargetMesh.mesh.vertices[i] - data.target.localPosition;
            m_listMeshData.Add(data);
        }

十、然后在Update调用以下方法,并拖动。你会得到下面的效果:

	private void MoveMeshPoint()
    {
        Vector3[] v3 = TargetMesh.mesh.vertices;
        for (int i = 0; i < m_listMeshData.Count; i++)
        {
            MeshData curData = m_listMeshData[i];
            v3[i] = curData.target.localPosition+ curData.offset;
        }
        TargetMesh.mesh.vertices = v3;
    }

Unity绳子/绳索效果
十一、跟着动了对吗?显然这还不是我们要的最终效果,优化一下加上这句,
让位置着跟着球球旋转一下:

Vector3 dir = curData.target.transform.TransformDirection(curData.offset);

变成这样:

private void MoveMeshPoint()
    {
        Vector3[] v3 = TargetMesh.mesh.vertices;
        for (int i = 0; i < m_listMeshData.Count; i++)
        {
            MeshData curData = m_listMeshData[i];
            Vector3 dir = curData.target.transform.TransformDirection(curData.offset);
            v3[i] = curData.target.localPosition + dir;
        }
        TargetMesh.mesh.vertices = v3;
    }

Unity绳子/绳索效果
十二、完整代码:

using System.Collections.Generic;
using UnityEngine;

public class TestMono : MonoBehaviour
{

    public MeshFilter TargetMesh;               //网格
    public Transform BallGroup;                 //球体集合(关节上所有球放这)
    private List<Transform> m_listBall;         //存放所有球体
    private List<MeshData> m_listMeshData;      //节点数据

    void Start()
    {
        m_listBall = new List<Transform>();
        foreach (Transform tran in BallGroup)
        {
            m_listBall.Add(tran);
        }


        m_listMeshData = new List<MeshData>();
        int totleMeshPoint = TargetMesh.mesh.vertices.Length;
        for (int i = 0; i < totleMeshPoint; i++)
        {
            MeshData data = new MeshData();

            data.Index = i;
            data.target = __FindNearest(TargetMesh.mesh.vertices[i]);
            if (data.target == null) Debug.Log("有空的");
            data.offset = TargetMesh.mesh.vertices[i] - data.target.localPosition;
            m_listMeshData.Add(data);
        }
    }

    // Update is called once per frame
    void Update()
    {
        MoveMeshPoint();
    }

    private void MoveMeshPoint()
    {
        Vector3[] v3 = TargetMesh.mesh.vertices;
        for (int i = 0; i < m_listMeshData.Count; i++)
        {
            MeshData curData = m_listMeshData[i];
            Vector3 dir = curData.target.transform.TransformDirection(curData.offset);
            v3[i] = curData.target.localPosition + dir;
        }
        TargetMesh.mesh.vertices = v3;
    }



    private Transform __FindNearest(Vector3 v3)
    {
        if (m_listBall != null)
        {
            float MaxDis = 999999;
            Transform MaxTran = null;
            for (int i = 0; i < m_listBall.Count; i++)
            {
                float curDis = Vector3.Distance(m_listBall[i].localPosition, v3);
                if (curDis < MaxDis)
                {
                    MaxDis = curDis;
                    MaxTran = m_listBall[i];
                }
            }
            return MaxTran;
        }
        return null;
    }

}

public class MeshData
{
    public int Index;               //索引
    public Transform target;        //目标球球
    public Vector3 offset;          //与目标球球位置差距
}

点赞关注,谢谢。
有问题请与我取得联系。

本文地址:https://blog.csdn.net/ww1351646544/article/details/109235955