ユニティロープ/ロープ効果

古いルールが最初に描かれています:
ここに写真の説明を挿入

私は最近ゲームをしています。ロープを撚り合わせてから、ゲームに勝つためにロープをほどく必要があります。ロープ効果を使う必要があるので、インターネットでたくさんの情報をチェックしました。プラグインのオビロープやメガファイアーで実現できる一方で、ハードコアのものは独自のアルゴリズムやジョイントを使うことができます。

ただし、IOS14以降のバージョンではコードレビューが非常に厳しいため、多くのプラグインを使用できず、独自のアルゴリズムしか記述できません。インターネット上の多くの方法では、ジョイントを使用してロープ効果を実現しています。ロープはコヒーレントロープではありません。以下は実装方法です。 :
1。ヒンジジョイントを使用して球をつなぎ合わせ、球コライダーとリジッドボディを維持します。
ここに写真の説明を挿入
2.オブジェクトを見つけて下のスクリプトをハングさせ、オブジェクトをドラッグできるようにします。

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
}

3.円筒形メッシュのモデリングはおそらくソースです。ロープがコンプライアントにならないためにノットが少なすぎたり、パフォーマンスが低下するために多すぎたりしないでください。
ここに写真の説明を挿入
第四に、かわいいテクスチャを追加します。
ここに写真の説明を挿入
第五に、ボールとグリッドを組み合わせます。
ここに写真の説明を挿入
6. 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);
        }
}

ここに写真の説明を挿入

7.すべてのグリッドノードが対応するボールノードを見つけるのに役立つ方法を提供します。グリッドは、ターゲットとして自分に最も近いボールを自動的に見つけます。

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;
    }

8.ノードデータを記録するためのデータ構造を提供します

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

9.スタートで次のコードを呼び出して、各ノードのターゲットと位置の差の情報を見つけます

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);
        }

10.次に、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;
    }

ここに写真の説明を挿入
11、それは続いたのですか?明らかに、これは私たちが望む最終結果ではありません。この文を最適化して追加
し、位置をボールに沿って回転させます。

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;
    }

ここに写真の説明を挿入
12.完全なコード:

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;          //与目标球球位置差距
}

いいねしてフォローしてくれてありがとう。
ご不明な点がございましたら、お問い合わせください。

おすすめ

転載: blog.csdn.net/ww1351646544/article/details/109235955
おすすめ