Unity3D教程:运用物理方法实现无限摆钟

发表于2016-11-07
评论0 7k浏览
       无限摆钟有时候会在一些游戏场景中使用到,为了帮助大家项目的开发,下面就给大家介绍下在Unity3D中是运用物理方法实现无限摆钟的方法,想知道可以看一看。
一、概述
  某一天,我想在游戏中实现一个钟摆式的陷阱,大致如下图所示


  虽然Unity内置了Physx物理引擎,提供了铰链关节、Distance Joint2D之类的物理组件,但是我试过之后发现,虽然能实现钟摆,但会有能量的损失,无法做到无限摆钟。我又试着在物理材质中去掉摩擦力,也还是行不通。在全局变量中也没有找到空气阻力之类的参数。所以,只好自己来实现了,幸好用到的物理公式都很简单。我们来看看吧。

二、原理

                                                                                                      

  如上图所示,O点是圆点,P点是摆钟的某一时刻的位置。则摆钟受到一个地心引力,重力加速度为g。
  首先,摆钟是属于物理中的转动,与我们平时所常用的平动有联系,但也有区别。相关知识在大学物理中会学到,但不幸的是我们专业课并没有开设大学物理。那么我们现在来学习一下吧。
  对于平动而言,有如下等式成立:


  上面两个式子很简单直白,那么我们接着来看在转动中相关的等式是怎样的:


  那么,对于我们上述的问题来说,我们已知钟摆受到重力加速度g,这是属于平动的物理量,我们怎么把它转换为转动中的角加速度呢?运用下面的式子:


  现在,知道了a(通过重力加速度g求解),我们就可以求出钟摆的角加速度,然后依次推出某一时刻的角速度,以及角位移,这样钟摆的问题就得到求解了,我们接下来来看具体推导过程。

                 

  回到上图,角A是点P处切线PQ与垂线的夹角,已知钟摆在P点受到重力加速度g,那么可以求得其在PQ方向上的加速度a:


  通过公式3,求得PQ方向上的角加速度:


  联立公式2,求出角速度:


  如图,对于cos(A)来说,有:


  已知O点和P点的坐标,则L可求解。下面来看具体的实现。

三、实现
  通过上述公式可以求出角速度以及角位移,然后我们可以调用Unity3D的transform.RotateAround(Vector3 point, Vector3 axis, float angle)来实现钟摆。此函数的作用是让物体绕着经过point点的轴axis旋转angle角度。注意angle的单位是角度,不是弧度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using UnityEngine;
using System.Collections;
public class Pendulum : MonoBehaviour {
    public Transform m_anchor;        //圆点
    public float g = 9.8f;            //重力加速度
    private Vector3 m_rotateAxis;    //旋转轴
    private float w=0;                //角速度
    // Use this for initialization
    void Start () {
        //求出旋转轴
        m_rotateAxis = Vector3.Cross (transform.position-m_anchor.position, Vector3.down);
    }
    void DoPhysics()
    {
        float r = Vector3.Distance(m_anchor.position, transform.position);
        float l = Vector3.Distance (new Vector3 (m_anchor.position.x, transform.position.y, m_anchor.position.z), transform.position);
        //当钟摆摆动到另外一侧时,l为负,则角加速度alpha为负。
        Vector3 axis = Vector3.Cross (transform.position-m_anchor.position, Vector3.down);
        if (Vector3.Dot (axis, m_rotateAxis) < 0) {
            l = -l;
        }
        float cosalpha = l/r;
        //求角加速度
        float alpha = (cosalpha*g)/r;
        //累计角速度
        w += alpha * Time.deltaTime;
        //求角位移(乘以180/PI 是为了将弧度转换为角度)
        float thelta = w * Time.deltaTime*180.0f/Mathf.PI;
        //绕圆点m_ahchor的旋转轴m_rotateAxis旋转thelta角度
        transform.RotateAround (m_anchor.position, m_rotateAxis, thelta);
    }
    // Update is called once per frame
    void Update () {
        DoPhysics ();
    }
}

  至此,我们的实现就结束了。
  下面是知乎上的一个关于转动的帖子,对我很有帮助:
  https://www.zhihu.com/question/24218339

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引