RoadLun原创(包括图片),转载请声明
演示:
效果如上图,具有绳子一般的柔软
对绳子发射一颗Cube,绳子会做出被外力击中的反应,模拟绳子的柔软的物理特性。
思路
思路如下:将绳子看作数个节点组成的链,控制这些节点从而控制整个绳子的运动情况。
如下图
单个节点的受力情况:
所以,模拟单个节点的受力情况,需要模拟此节点受到的重力和绳子的拉力,此处我用添加刚体的方法来模拟重力,接下来就是模拟拉力了。
通常认为的绳子并不是一个有弹性的绳子(橡皮筋),所以绳子上两个点的最大距离不超过绳子绷直时两点的距离,所以我通过时刻修正节点的位置(确保两个节点之间的距离不超过最大值),来模拟绳子的拉力。
所以,如何修正节点的位置呢?
因为节点添加了刚体,所以节点会收到重力下落,一旦超过两节点最大值,就要被修正,如下图:
代码如下:
realDistance = Vector3.Magnitude(lastNodeTran.position-transform.position); //求两点实际距离
if (realDistance>nodeDistance*nodeDistance||realDistance<nodeDistance*nodeDistance-allowValue) //如果两节点距离超过规定距离,则进行修正。
{
//修正
transform.position = Vector3.Lerp(lastNodeTran.position, transform.position, nodeDistance / realDistance);
}
注:这个脚本赋给要修正的子节点上
按照上面的思路写,就ok了,
但是在实际运用中,发现虽然子节点的位置被修正,但是子节点一直处于下落状态(重力势能转化为动能,所以子节点会抖动并且抖得越来越快),所以我加上了一个修正速度的方法,没帧判断当前节点的速度,如果超过一个定值,则进行修正。这个方法可以缓解抖动问题,但是没法彻底解决。方法如下:
void Deceleration() //减速
{
if (rig.velocity.sqrMagnitude>25) //检测速度是否超过 5 m/s
{
rig.velocity /= 3; //修正为3 m/s
}
}
如何显示:
思路时用线性渲染(LineRender)组件,实时修改LineRender的节点位置为绳子节点位置。
代码:
修正节点的脚本。(需要附在节点上,并且头节点不要放Rigbody组件,也不要放此脚本)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NodePosition : MonoBehaviour {
//绳子核心算法:
//判断两个节点的距离,如果超过节点定长,则当前距离变为定常距离(改变子节点位置,用插值来计算)
private float nodeDistance = 1.6f; //节点定长
public Transform lastNodeTran; //上一个节点的位置
float realDistance; //真实距离
Rigidbody rig;
float allowValue = 0.02f; //允许误差的值
private void Start()
{
rig = GetComponent<Rigidbody>();
}
private void Update()
{
Judge();
Deceleration();
}
void Judge()
{
//求两点距离时,用平方会比开方好
realDistance = Vector3.Magnitude(lastNodeTran.position-transform.position);
if (realDistance>nodeDistance*nodeDistance||realDistance<nodeDistance*nodeDistance-allowValue) //用平方来比较
{
//已经超过
transform.position = Vector3.Lerp(lastNodeTran.position, transform.position, nodeDistance / realDistance);
}
}
void Deceleration() //减速
{
if (rig.velocity.sqrMagnitude>25)
{
rig.velocity /= 3;
}
}
}
控制LineRender的脚本,需要LineRender组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SetNode : MonoBehaviour {
//控制绳子的显示
//获得LineRender组件,设置Size等于节点数,设置节点的位置
public Transform node0;
public Transform node1;
public Transform node2;
public Transform node3;
public Transform node4;
public Transform node5;
Vector3[] allNodes;
LineRenderer lineRen;
private void Start()
{
lineRen = GetComponent<LineRenderer>();
Debug.Log(lineRen);
//lineRen.positionCount = 6;
//新建一个数组
lineRen.positionCount = 6;
Debug.Log(lineRen.positionCount);
}
private void Update()
{
allNodes = new Vector3[6] { node0.position, node1.position, node2.position, node3.position, node4.position, node5.position };
lineRen.SetPositions(allNodes);
}
}
ok~ 就是这个思路~