Unity绳子/绳索效果
程序员文章站
2022-03-16 08:12:36
老规矩先上图:最近在做一个做一个游戏,绳子缠绕在一起然后需要把绳子解开方能赢得游戏。因为需要用到一个绳子的效果,网了查了不少资料一方面是用插件Obi Rope 或 Megafiers 都可以实现,另一方面比较硬核的可以使用自己的算法也可以用关节什么的。但由于IOS14以上版本对代码审核非常严格,很多插件是无法使用的,只能自己写算法了,网上很多方法都是使用关节实现的绳子效果,绳子并非一条连贯的绳子,以下分享一实现的方式:一、使用铰链关节(Hinge Joint)把球体串起,保留Sphere Colli...
老规矩先上图:
最近在做一个做一个游戏,绳子缠绕在一起然后需要把绳子解开方能赢得游戏。因为需要用到一个绳子的效果,网了查了不少资料一方面是用插件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;
}
}
}
//------------------------------------------------------------------------------------
/// <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
}
三、 建模一个圆柱体网格大概是酱子,节不能太少因为绳子会不柔顺,也不能太多因为 性能会伤不起。
四、加了一个可爱的贴图
五、然后把球和网格放在一起。
六、创建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);
}
}
七、提供一个方法,帮所有网格节点找到对应的球节点,网格自动寻找离自己最近的球为目标。
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;
}
十一、跟着动了对吗?显然这还不是我们要的最终效果,优化一下加上这句,
让位置着跟着球球旋转一下:
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<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