Unity基础包 刚体球类Ball和BallUserControl脚本研究

发表于2017-11-08
评论0 1.3k浏览

今天是两个球体Ball和BallUserControl脚本的分析,利用刚体作用力直接产生移动的方式进行移动,让我想起很早的一个游戏——仓鼠球。

 

我感觉在这类的控制方面,有了刚体之后真的是简便了很多,一个球体放在地上,给与一个力自然就会旋转,不然旋转什么的自己写还是有点麻烦的吧。

 

首先是Ball类,主要提供了移动的方法:

// 球型物体移动类,由刚体实现,注意这边的角阻力设置为了1,设为0话会一直转,停不下来  
public class Ball : MonoBehaviour  
{  
    [SerializeField] private float m_MovePower = 5; //驱动球移动的力量值  
    [SerializeField] private bool m_UseTorque = true; //驱动球的时候是否使用扭转力,即旋转力  
    [SerializeField] private float m_MaxAngularVelocity = 25; //球最大能旋转的速度  
    [SerializeField] private float m_JumpPower = 2; //球跳跃时所产生的力  
    private const float k_GroundRayLength = 1f; //射线确认球是否在地上的长度  
    private Rigidbody m_Rigidbody;  //球的刚体  
    // 初始化  
    private void Start()  
    {  
        m_Rigidbody = GetComponent<Rigidbody>();  
        // 设置最大的角速度,默认是7  
        GetComponent<Rigidbody>().maxAngularVelocity = m_MaxAngularVelocity;  
    }  
    // 移动,由具体的控制器调用  
    public void Move(Vector3 moveDirection, bool jump)  
    {  
        if (m_UseTorque)  
        {  
            // 如果是否旋转力,则在轴线方向添加力,即要向x轴前进,顺时针旋转z轴;向z轴前进,逆时针旋转x轴,最后乘以力的值  
            m_Rigidbody.AddTorque(new Vector3(moveDirection.z, 0, -moveDirection.x)*m_MovePower);  
        }  
        else  
        {  
            // 线性力的话就直接加就行  
            m_Rigidbody.AddForce(moveDirection*m_MovePower);  
        }  
        //如果在地上而且弹跳键被按下,则网上添加一个冲力。这边用了一条射线往下发射,判断是否在地上,就不能用Vector3.down吗,非要用Vector3.up,我愣了三秒为什么要往上发射  
        if (Physics.Raycast(transform.position, -Vector3.up, k_GroundRayLength) && jump)  
        {  
            m_Rigidbody.AddForce(Vector3.up*m_JumpPower, ForceMode.Impulse);  
        }  
    }  
}  

这边就是有两种方式,一种是以旋转力作为移动,而另一种是直接给一个线性力,两种感觉都可以,不过仓鼠球的话旋转力是最真实的吧。


接下来是用户控制类BallUserControl:

// 用户球控制器  
public class BallUserControl : MonoBehaviour  
{  
    private Ball ball; //球移动类的引用  
    private Vector3 move;   //世界坐标中的移动方向,使用相机的前方和用户输入来计算  
    private Transform cam; //主相机  
    private Vector3 camForward; //主相机当前的前方  
    private bool jump; //当前的跳跃键是否被按下  
    private void Awake()  
    {  
        // 设置引用  
        ball = GetComponent<Ball>();  
        //获取主相机  
        if (Camera.main != null)  
        {  
            cam = Camera.main.transform;  
        }  
        else  
        {  
            //在这个例子中我们使用世界坐标来控制,也许这不是他们做希望的,不过我们至少警告一下他们  
            Debug.LogWarning("警告:不存在一个主相机,球需要一个tag为MainCamera的相机,来做相机关联的移动");  
        }  
    }  
    private void Update()  
    {  
        //获取轴线和跳跃的输入  
        float h = CrossPlatformInputManager.GetAxis("Horizontal");  
        float v = CrossPlatformInputManager.GetAxis("Vertical");  
        jump = CrossPlatformInputManager.GetButton("Jump");  
        //计算移动方向  
        if (cam != null)  
        {  
            //计算世界坐标的相机相关的方向  
            camForward = Vector3.Scale(cam.forward, new Vector3(1, 0, 1)).normalized;   //获取相机的正方向,忽略y坐标,不过cam.right为什么不忽略?  
            move = (v * camForward   h * cam.right).normalized;  
            //move = (v*cam.forward   h*cam.right).normalized;  //使用这个,当然也能移动,不过官方写的更加强调正方向,水平方向有输入的情况下,官方的转弯幅度更小  
        }  
        else  
        {  
            //当没有相机时,直接以世界坐标轴作为参考  
            move = (v*Vector3.forward   h*Vector3.right).normalized;  
        }  
    }  
    private void FixedUpdate()  
    {  
        //使用move方法控制球  
        ball.Move(move, jump);  
        jump = false;  
    }  
}  

读入用户的输入,然后计算出对应的方向,最后在FixedUpdate中控制ball移动。这个流程是比较规范的一个写法吧,像我之前一些更新代码都卸载Update中了。

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

标签: