天天看點

小球的平面彈射問題

最近參與的項目總是會涉及到物體的平面反彈問題,于是我就仔細研究了一下,得到一個适用于任何開發工具的通用性方法;下面我将這個方法分享給大家,歡迎大家提出問題、與我讨論

一、問題概述

首先明白任務的需求:對于在場景中任意位置任意角度生成的一根橫杆,實作小球與橫杆發生碰撞後能夠實作平面反射,且要求使用的方法能夠适用于任何引擎。

這個問題的需求其實非常簡單,需要用到一些高中的數學和實體知識,主要涉及到向量的運算,隻要明白其中的原理,實作起來并不是非常困難的事。這篇文章會先從理論上讨論通用的方法,再使用Unity引擎模拟這個過程。

二、理論分析

首先,我們的研究對象是在場景中生成的橫杆,對于這根橫杆,我們需要先得到它的方向向量,這是一件很容易做到的事情,因為橫杆的生成也是由我們控制的,隻要在生成時保留下來随機的相對于水準線的角度值,就可以根據這個角度值求得方向向量。我們設這個随機的角的弧度值為θ(三角函數的運算通常使用的是弧度值,設角度值為ω,那麼弧度值θ=ω*π/180°,之後将不再贅述),橫杆的方向向量為

小球的平面彈射問題

,那麼

小球的平面彈射問題

,這裡我們使用1作為模長,是因為我們希望将我們所有的方向向量都轉化為機關向量,友善我們進行之後的計算。

小球的平面彈射問題

圖1

接下來我們來求一下橫杆的法線的方向向量

小球的平面彈射問題

,因為我們知道一條直線的法線與該直線必然相差90°,是以可以求得         

小球的平面彈射問題

,同樣我們知道法向量其實也可以是

小球的平面彈射問題

,到目前為止并不能判斷哪一條是我們需要的,不過這并沒有關系,因為

小球的平面彈射問題

,需要時可以随時轉化,我們後面會看到這一點。是以這裡我們就取

小球的平面彈射問題

然後我們随便畫出一條入射向量

小球的平面彈射問題

,再根據該入射向量畫出反射向量

小球的平面彈射問題

,然後根據平行四邊形法則再分别畫出

小球的平面彈射問題

小球的平面彈射問題

。根據平面反射可知,入射角等于反射角,易得向量

小球的平面彈射問題

小球的平面彈射問題

小球的平面彈射問題

小球的平面彈射問題

的模長均相等,即ABCD是一個菱形,如圖2所示。

小球的平面彈射問題

圖2

我們讓

小球的平面彈射問題

就等于小球飛行過來時的方向向量,設為

小球的平面彈射問題

,是以我們現在的任務就是根據

小球的平面彈射問題

和法向量

小球的平面彈射問題

要求出反射向量

小球的平面彈射問題

。接下來就是求解的過程:

首先根據向量運算法則知道

小球的平面彈射問題

=

小球的平面彈射問題

=

小球的平面彈射問題

+

小球的平面彈射問題

,現在

小球的平面彈射問題

是已知的,重點就是要求向量

小球的平面彈射問題

的值,我們又知道

小球的平面彈射問題

是法線的方向向量,但方向并不确定,在

小球的平面彈射問題

小球的平面彈射問題

同向的情況下,

小球的平面彈射問題

= λ

小球的平面彈射問題

,隻要求得λ即|

小球的平面彈射問題

|,問題就解決了;如果

小球的平面彈射問題

小球的平面彈射問題

方向相反,我們隻要讓

小球的平面彈射問題

取反,問題一樣可以得到解決。是以我們需要先判斷

小球的平面彈射問題

小球的平面彈射問題

是否同向,這裡可以計算一下

小球的平面彈射問題

小球的平面彈射問題

的夾角

小球的平面彈射問題

(向量夾角計算公式:夾角的餘弦值等于兩個向量點乘除以兩個向量的模的乘積,即

小球的平面彈射問題

=

小球的平面彈射問題

·

小球的平面彈射問題

/ |

小球的平面彈射問題

|*|

小球的平面彈射問題

|)很顯然在

小球的平面彈射問題

小球的平面彈射問題

同向的情況下,

小球的平面彈射問題

必然大于π/2,由此就可以判斷

小球的平面彈射問題

的方向。

接下來我們要求解|

小球的平面彈射問題

|的值,顯然由于ABCD是菱形,是以

小球的平面彈射問題

,幸運的是∠ABD正好與我們前面所求得的

小球的平面彈射問題

相關,當

小球的平面彈射問題

時,

小球的平面彈射問題

,即

小球的平面彈射問題

;當

小球的平面彈射問題

時,

小球的平面彈射問題

,即

小球的平面彈射問題

,至此,反射相關的問題基本上已經得到解決,剩下的隻是程式的實作,圖3是完整的計算過程。

小球的平面彈射問題

圖3

 不過,除了反射以外,我們同樣還需要考慮一下碰撞檢測的通用方法。現在我們知道橫杆的方向向量和橫杆的位置坐标,那麼可以很輕松的求出橫杆所在的直線方程,設直線方程

小球的平面彈射問題

,接下來再通過點到直線距離公式就可以得到小球到橫杆的最短距離d(設小球的位置

小球的平面彈射問題

,那麼

小球的平面彈射問題

),這樣,我們就可以每一幀都監聽d的大小,當d小于一個極小值ε時,即為滿足反射條件,如圖4所示。

小球的平面彈射問題

圖4

至此,小球反彈問題已經從理論上得到解決,接下來是我們嘗試用Unity模拟這個過程。(注:Unity中已存在Vector2.Reflect()函數,傳入入射向量和法向量即可實作核心的反射功能,我們在理論階段的工作相當于實作了Reflect()的底層,為了保證方法在任何引擎中都适用,這是必須的,是以,我們在Unity的模拟工作中也不會使用其自帶的Reflect()函數;此外,Unity中也存在一些自帶的數學方法,能夠實作求兩個向量的夾角、角度值和弧度值的轉化等等,因為這些問題比較簡單,也不是我們這次讨論的核心問題,是以友善起見,我們會在程式模拟的時候使用)

三、代碼實作

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BallManager : MonoBehaviour
{
    public Vector3 direction;
    //小球移動的方向向量
    public float flySpeed;
    //小球移動速度

    private void Update()
    {
        if (Mathf.Abs(this.transform.position.x) > 9 || Mathf.Abs(this.transform.position.y) > 5)
            GameObject.Destroy(this.gameObject);
        //越界銷毀
    }

    private void FixedUpdate()
    {
        this.transform.Translate(direction * flySpeed * Time.fixedDeltaTime, Space.World);
        //小球移動
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("Wall"))
        {
            float normalAngle = (collision.GetComponent<Transform>().eulerAngles.z + 90) * Mathf.Deg2Rad;
            //法線的角度值與橫杆相差90°,Mathf.Deg2Rad是一個常數,可直接将角度值轉化為弧度值
            Vector3 normalDir = new Vector3(Mathf.Cos(normalAngle), Mathf.Sin(normalAngle), 0);
            //求法線的方向向量

            direction = Reflect(direction, normalDir);
            //改變小球移動方向為反射向量
        }
    }
    //偷個小懶,直接使用Unity的内置方法進行碰撞檢測

    private Vector3 Reflect(Vector3 inDir, Vector3 nDir)
    {
        float angleTemp = 0;
        //定義一個變量儲存θ2

        if (Vector3.Angle(inDir, nDir) > 90)
        {
            angleTemp = 180 - Vector3.Angle(inDir, nDir);
            //若向量夾角大于90°,則θ2為向量角的補角
            //Vector3.Angle方法可以直接求得兩向量的夾角
        }
        else
        {
            angleTemp = Vector3.Angle(inDir, nDir);
            nDir = -nDir;
            //若向量夾角小于90°,則θ2等于向量角,法向量取反
        }

        Vector3 outDir = Mathf.Cos(angleTemp * Mathf.Deg2Rad) * 2 * nDir + inDir;
        //求反射向量

        return outDir;
    }
    //反射函數
}
           

四、效果示範

小球的平面彈射問題
小球的平面彈射問題

五、擴充

上面讨論的問題均是在2D情景下實作的,如果擴充到3D情景下原理其實也基本相同,感興趣的同學可以嘗試實作。

小球的平面彈射問題

圖5

繼續閱讀