洪流学堂,让你快人几步。你好,我是郑洪智。

洪流学堂公众号回复捉妖,可以获取本教程的源码工程


小新:“智哥,今天咱们来开发封妖灵珠?”

大智:“好啊,你觉得实现封妖灵珠需要哪些步骤?”

小新:“我觉得大概是这样的:”

  • 首先要封妖灵珠能跟随手指移动
  • 手指松开时能计算扔出去的速度
  • 将手指在屏幕上的速度,换算成给球施加的力,将球抛出去

大智:“思路不错嘛,就按这个来尝试实现吧。”

封妖灵珠能跟随手指移动

大智:“封妖灵珠跟随手指移动的关键是将手指触摸屏幕的屏幕空间二维坐标转换成三维空间中灵珠的坐标。具体的API可以尝试Camera.ScreenToWorldPoint。”

小新:“那灵珠在三维空间的坐标有三个轴,第三个轴如何计算呢?”

大智:“这第三个轴就需要你来告诉它了。默认情况下使用Input.mousePosition作为参数传入API转换出来,Z轴的坐标会是和相机世界位置的z值是一样的。这是因为Input.mousePosition的Z是0,如果你修改一下,将z改为3,那么转换出来的坐标就是距离相机z距离的世界坐标。大概就是下面这样的代码:”

var pos = Input.mousePosition;
pos.z = 3;
var worldPos = Camera.main.ScreenToWorldPoint(pos);

小新:“那我大概明白了,我去写一下完整的功能。”

public Transform Ball;

void BallUpdate()
{
    if (Input.GetMouseButton(0))
    {
        var pos = Input.mousePosition;
        pos.z = BallDistance;
        var worldPos = Camera.main.ScreenToWorldPoint(pos);
        Ball.position = worldPos;
    }
}

大智:“没毛病,可以接着看下一个功能了。”

计算手指松开时的速度

小新:“那计算速度有没有直接的API能使用的呢?”

大智:“这个好像真没有,不过初高中就学过速度的计算公式,是什么呢?”

小新:“速度 = 位移 / 时长 嘛”

大智:“对,这个公式到哪里都不会变的,放到虚拟世界中一样是这么计算。”

小新:“哦,我有点明白了,我先试试。”

var current = Input.mousePosition;
// 计算触摸的偏移量
var delta = current - lastMousePosition;
var velocity = delta / Time.deltaTime;
// 记录当前帧光标/触摸的位置,用于下一帧的计算
lastMousePosition = current;

大智:“对,这几行代码放到Update中就能计算出来光标当前的速度。”

换算成给球施加的力

小新:“那最后就是想办法将这个速度换算成给球施加的力咯?”

大智:“对,同样因为这个速度是屏幕空间中的速度,你得想办法转换成世界空间中的力。”

小新:“那我可不可以将光标速度的X轴转换成球在水平方向的力,然后将光标速度的Y轴转换成球在竖直方向上的力?”

大智:“那这个球可就不会往前抛了啊?”

小新:“哦哦,那我可以把光标速度的Y轴转换成施加给球的力时是往斜上方的。”

大智:“那就对啦,这样就可以把球丢出去啦。但是还有个需要注意的点,就是:屏幕空间的光标速度如果直接用到球的力上,会非常大,需要通过一个系数转换一下,这个系数大概可以参考0.001。”

小新:“好嘞,我先去码代码啦”

总结

小新:“最后的代码如下:”

using UnityEngine;

public class TouchManager : MonoBehaviour
{
    public Transform Ball;
    public float BallDistance = 1;
    public float SpeedFactor = 0.001f;

    private Vector3 lastMousePosition;
    private Rigidbody ballRigid;

    void Start()
    {
        ballRigid = Ball.GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        BallUpdate();
        var current = Input.mousePosition;
        var delta = current - lastMousePosition;

        var velocity = delta / Time.deltaTime;

        if (Input.GetMouseButtonUp(0))
        {
            var ballVelocity = Camera.main.transform.forward * velocity.y / 1.414f + 
                                Camera.main.transform.up * velocity.y / 1.414f + 
                                Camera.main.transform.right * velocity.x;

            Debug.Log(ballVelocity);

            ballRigid.isKinematic = false;
            ballRigid.AddForce(ballVelocity * SpeedFactor, ForceMode.Impulse);
        }

        // 记录当前帧光标/触摸的位置,用于下一帧的计算
        lastMousePosition = current;
    }

    void BallUpdate()
    {
        if (Input.GetMouseButton(0))
        {
            ballRigid.isKinematic = true;
            var pos = Input.mousePosition;
            pos.z = BallDistance;
            var worldPos = Camera.main.ScreenToWorldPoint(pos);
            Ball.position = worldPos;
        }
    }
}

洪流学堂公众号回复捉妖,可以获取本教程的源码工程

今日思考题

大智:“动手将今天的工程部署到真机上体验一下。”
小新:“好嘞!”
大智:“收获别忘了分享出来!也别忘了分享给你学Unity的朋友,也许能够帮到他。”


《大话Unity2019》,大智带小新学Unity2019的有趣经历,让你学Unity更简单。