As regras antigas são descritas pela primeira vez:
Estou fazendo um jogo recentemente. As cordas estão torcidas e precisam ser desamarradas para vencer o jogo. Devido à necessidade de usar um efeito de corda, verifiquei muitas informações na Internet. Por um lado, isso pode ser obtido com os plug-ins Obi Rope ou Megafiers. Por outro lado, os hard-core podem usar seus próprios algoritmos ou articulações.
No entanto, como o IOS14 e as versões superiores são muito rígidas na revisão de código, muitos plug-ins não podem ser usados e você só pode escrever seus próprios algoritmos. Muitos métodos na Internet usam juntas para obter o efeito de corda. A corda não é uma corda coerente. O seguinte é um método de implementação. :
1. Use a junta de dobradiça para amarrar as esferas juntas e manter o colisor de esfera e o corpo rígido.
2. Encontre qualquer objeto e pendure o script abaixo, para que o objeto possa ser arrastado.
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. Modelar uma malha cilíndrica provavelmente é um molho. Não deve haver poucos nós porque a corda não será compatível, nem muitos porque o desempenho prejudicará.
Quarto, adicione uma textura fofa.
Quinto, coloque a bola e a grade juntas.
6. Crie MonoBehaviour, adicione scripts e pendure os objetos correspondentes, encontre todas as bolas primeiro
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. Forneça um método para ajudar todos os nós da grade a encontrar os nós da bola correspondentes, e a grade encontrará automaticamente a bola mais próxima de si mesma como o alvo.
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. Fornece uma estrutura de dados para registrar os dados do nó
public class MeshData
{
public int Index; //索引
public Transform target; //目标球球
public Vector3 offset; //与目标球球位置差距
}
Nove, chame o seguinte código em Iniciar para encontrar o alvo e as informações de diferença de posição de cada nó
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. Em seguida, chame o seguinte método em Atualizar e arraste. Você obterá o seguinte efeito:
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;
}
Onze, isso acompanhou, certo? Obviamente este não é o resultado final que queremos, otimize e adicione esta frase,
deixe a posição seguir a bola para girar:
Vector3 dir = curData.target.transform.TransformDirection(curData.offset);
Torna-se assim:
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. Código completo:
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; //与目标球球位置差距
}
Curta e siga, obrigado.
Se você tiver alguma dúvida, entre em contato comigo.