勇哥注:
夹子的应用有我们常见的气缸。它的基本原理就是Fixed Joint 连接器。
如下图所示,那个Cube添加Fixed Joint链接器后,配置好“已连接实体”,即可以实现链接。
当你移动Cube时,球体会跟随移动


下面构建夹子的简易演示,工程对象如下图所示:

(图1)

(图2)
对base添加夹子脚本

(图3)
先在“场景”视图把夹子对象降下来。

(图4)
然后转到 “游戏”视图,按space键把夹子夹住球体。

(图5)
再转到“场景”把夹子抬上去。

(图6)
转到“游戏”视图后,可以观察到球体被夹子带上来。
此时按space键,可以松开夹子,可以观察到球体就会掉下来。

(图7)
夹子代码:
public class Clip_Function : MonoBehaviour
{
    public GameObject clipBase;
    public GameObject leftClip;
    public GameObject rightClip;
    public GameObject targetObject;
    public float clipDistance = 0.01f;
    public float clipTime = 1f;
    public bool grabbed = false;
    bool working = false;
    GameObject triggedObject;
    GameObject clippedObject;
    [Range(-1, 1)]
    int grabDirection = 0;
    [Header("debug")]
    public KeyCode debugKeycode;
    private void Start()
    {
        clipBase.AddComponent<FixedJoint>();
        clipBase.GetComponent<Rigidbody>().isKinematic = true;        
    }
    public IEnumerator ClipFunction()
    {
        if (working == false)
        {
            if (grabDirection == 0)
            {
                grabDirection = 1;
            }
            else
            {
                grabDirection = -grabDirection;
            }
            working = true;
            for (int i = 0; i < 60; i++)
            {
                leftClip.transform.Translate(new Vector3(0, 0, -grabDirection * clipDistance / 60));
                rightClip.transform.Translate(new Vector3(0, 0, grabDirection * clipDistance / 60));
                yield return new WaitForSecondsRealtime(clipTime / 60);
            }
            working = false;
            if (clipBase.GetComponent<FixedJoint>().connectedBody == null)
            {
                if (triggedObject != null)
                {
                    clippedObject = triggedObject;
                    clipBase.GetComponent<FixedJoint>().connectedBody = clippedObject.GetComponent<Rigidbody>();
                    grabbed = true;
                }
            }
            else
            {
                clippedObject.GetComponent<Rigidbody>().isKinematic = true;
                clippedObject.GetComponent<Rigidbody>().isKinematic = false;
                clippedObject = null;
                clipBase.GetComponent<FixedJoint>().connectedBody = null;
                grabbed = false;
            }
        }        
    }
    private void OnTriggerStay(Collider other)
    {
        if(other.name.Contains(targetObject.name))triggedObject = other.gameObject;        
    }
    public void ClipWorking()
    {
        if (working == false) 
        {
            StartCoroutine("ClipFunction");
        }
    }
    #region debug
    private void Update()
    {
        if (Input.GetKeyDown(debugKeycode))
        {
            ClipWorking();
        }
    }
    #endregion
}下面勇哥解释一下代码。
(1)脚本的字段
public GameObject clipBase; //两个夹子中间那个cube,做为触发器来使用了
public GameObject leftClip; //左夹子
public GameObject rightClip; //右夹子
public GameObject targetObject; //要被夹住的对象,可以是任何东西
public float clipDistance = 0.01f; //夹子移动的距离
public float clipTime = 1f; //夹子开合的速度
public bool grabbed = false; //夹住时为true,否则为false
对应下图所示的内容:

(2)控制夹子开合方向
[Range(-1, 1)]
int grabDirection = 0;
Range是一个特性。
(3)调试按键
[Header("debug")]
public KeyCode debugKeycode;
(4) 设置Fixed Joint链接器
private void Start()
{
clipBase.AddComponent<FixedJoint>();
clipBase.GetComponent<Rigidbody>().isKinematic = true;
}
(5)夹子功能主函数
public IEnumerator ClipFunction()
{}
它是一个标准的协和函数,这个是unity里特有的。
(6)触发器的触发函数
private void OnTriggerStay(Collider other)
{
if(other.name.Contains(targetObject.name))triggedObject = other.gameObject;
}
(7)按键调试用的函数
private void Update()
{
if (Input.GetKeyDown(debugKeycode))
{
ClipWorking();
}
}
下面来看下夹子的那个主功能函数ClipFunction()
(1)下在这句是为了防止重复触发。
if (working == false)
(2)下面这几句是夹子开合方向的控制。
if (grabDirection == 0)
{
grabDirection = 1;
}
else
{
grabDirection = -grabDirection;
}
(3)下面是夹子开合动画的绘制。
for (int i = 0; i < 60; i++)
{
leftClip.transform.Translate(new Vector3(0, 0, -grabDirection * clipDistance / 60));
rightClip.transform.Translate(new Vector3(0, 0, grabDirection * clipDistance / 60));
yield return new WaitForSecondsRealtime(clipTime / 60);
}
yield return 这个是协程的标准写法。
它是让循环在规定时间点结束。
(4)夹子开/合时联接器的设置。
如果夹住时链接器生效,小球会被带走; 如果松开夹子时链接器失效,小球就会掉下来。
if (clipBase.GetComponent<FixedJoint>().connectedBody == null)
{
if (triggedObject != null)
{
clippedObject = triggedObject;
clipBase.GetComponent<FixedJoint>().connectedBody = clippedObject.GetComponent<Rigidbody>();
grabbed = true;
}
}
else
{
clippedObject.GetComponent<Rigidbody>().isKinematic = true;
clippedObject.GetComponent<Rigidbody>().isKinematic = false;
clippedObject = null;
clipBase.GetComponent<FixedJoint>().connectedBody = null;
grabbed = false;
}


少有人走的路


















