Unity绳子/绳索效果

您所在的位置:网站首页 3d麻绳模型怎么做 Unity绳子/绳索效果

Unity绳子/绳索效果

2024-07-14 05:04| 来源: 网络整理| 查看: 265

老规矩先上图: 在这里插入图片描述

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

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

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; } } } //------------------------------------------------------------------------------------ /// /// 检查是否点击到cbue /// /// 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 }

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

public MeshFilter TargetMesh; //网格 public Transform BallGroup; //球体集合(关节上所有球放这) private List m_listBall; //存放所有球体 private List m_listMeshData; //节点数据 void Start() { m_listBall = new List(); foreach (Transform tran in BallGroup) { m_listBall.Add(tran); } }

在这里插入图片描述

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

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

在这里插入图片描述 十一、跟着动了对吗?显然这还不是我们要的最终效果,优化一下加上这句, 让位置着跟着球球旋转一下:

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

在这里插入图片描述 十二、完整代码:

using System.Collections.Generic; using UnityEngine; public class TestMono : MonoBehaviour { public MeshFilter TargetMesh; //网格 public Transform BallGroup; //球体集合(关节上所有球放这) private List m_listBall; //存放所有球体 private List m_listMeshData; //节点数据 void Start() { m_listBall = new List(); foreach (Transform tran in BallGroup) { m_listBall.Add(tran); } m_listMeshData = new List(); 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; //与目标球球位置差距 }

有问题请与我取得联系。 Demo地址: https://download.csdn.net/download/ww1351646544/15345650



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3