unity设备动作代码解析(3):夹子代码解析

勇哥注:

夹子的应用有我们常见的气缸。它的基本原理就是Fixed Joint 连接器。

如下图所示,那个Cube添加Fixed Joint链接器后,配置好“已连接实体”,即可以实现链接。

当你移动Cube时,球体会跟随移动


image.png

image.png


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

image.png

(图1)


image.png

(图2)

对base添加夹子脚本

image.png

(图3)

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

image.png

(图4)

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

image.png

(图5)

再转到“场景”把夹子抬上去。

image.png

(图6)

转到“游戏”视图后,可以观察到球体被夹子带上来。

此时按space键,可以松开夹子,可以观察到球体就会掉下来。

image.png

(图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

对应下图所示的内容:

image.png


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

 }


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:
本帖最后由 勇哥,很想停止 于 2024-10-17 21:30:23 编辑

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864