1. 程式人生 > >unity畫線之模擬小球拋物線運動軌跡

unity畫線之模擬小球拋物線運動軌跡

模擬小球的拋物線運動,如圖所示:
這裡寫圖片描述
這裡有點像打檯球遊戲,模擬在發射之前模擬其軌跡。
劃線用的是LineRenderer,不清楚的童鞋可以自行查閱咯。其實也很簡單就是掛個LineRenderer指令碼,設定它的座標點就行了,關鍵是這座標點如何計算的問題了。
高中物理知識,科普一波 首先位移公式,S = V0t+1/2at^2。此次位移的分解,物體在Y軸方向做加速度為重力加速度g的加速運動,在X軸方向勻速運動。則物體在X軸的位移為:Sx=Vxt ,Y軸位移Sy = Vyt+1/2gt^2。
知道公式之後,我們就可以按時間點計算物體的位移了,而unity中都是用座標表示那麼這種公式轉換為程式碼的邏輯就更加簡單了:

int posCount = 50;
List<Vector3> posList = new List<Vector3>();
for (int i = 1; i < posCount ; i++)
    {
        float x = Vec0.x * deltaTime*i;
        float y = 1f / 2f * Physics.gravity.y * Mathf.Pow(deltaTime, 2) + Vec0.y * deltaTime*i;
        posList.Add(oldPos + new Vector2(x, y));
    }

這樣就計算了出來了50個點,將這50個點全部賦值給LineRenderer就基本模擬完成了。

 public void SetPoint(List<Vector2> posList)
    {
        lineRenderer.positionCount = posList.Count;
        for (int i = 0; i < posList.Count; i++)
        {
            lineRenderer.SetPosition(i, posList[i]);
        }
    }

為什麼要說基本完成呢,這種模擬只是模擬球的最開始的軌跡,在遊戲中球會發生碰撞,碰撞之後會反彈,那麼這種反彈的軌跡如何實現呢?如圖:
這裡寫圖片描述


首先要知道球在什麼時候發生碰撞,碰撞的面法向量是啥?如果知道面的法向量,入射角那麼就可以求出線的反射角了。如何知道在什麼時候發生碰撞呢?
這裡我用的方法是計算每一段時間球的位移,將這一段時間的位移看作是直線,然後利用unity提供的射線來檢測是否碰撞,這種方法由於每一段是直線所以檢測出來碰撞值也是近似值,當然也沒有考慮球碰撞時的摩擦力對球的影響,總之算是一個粗略的解決方法,如果大家有什麼更好的方法,希望評論告知,在下感激不盡,首先拋磚迎玉,實現的具體程式碼如下:

  public List<Vector2> CalculateTrajectory(Vector2 startVel)
    {
        List<Vector2> posList = new List<Vector2>();

        Vector2 curPos = Vector2.zero;
        Vector2 changePos = Vector2.zero;

    float detlaTime =0.01f;
        Vector2 vel0 = startVel;
        Vector2 nextPos = Vector2.zero;
        int timeCount = 0;
        Vector2 direction = startVel.normalized; //速度的實時方向

        for (int i = 0; i < 100; i++)
        {
            //總的時間
            float time = detlaTime * timeCount;

            float x = vel0.x * time;
            float y = 1f / 2f * Physics.gravity.y * Mathf.Pow(time, 2) + vel0.y * time;
            nextPos = changePos + new Vector2(x, y);

            // Ray ray = new Ray(curPos + (Vector2)OriginalPos, curSpeedVec);
            direction = new Vector2(vel0.x, Physics.gravity.y * time + vel0.y).normalized;
            RaycastHit hit;
            if (Physics.SphereCast(curPos + (Vector2)OriginalPos, ballCollider.radius, direction, out hit, Vector2.Distance(curPos, nextPos), ~LayerMask.GetMask("Ball")))
            {
                Vector2 N = hit.normal;
                changePos = nextPos;// hit.point - OriginalPos + hit.normal * ballCollider.radius;

                vel0 = new Vector2(vel0.x, Physics.gravity.y * time + vel0.y);

                vel0 = vel0 - 2 * (Vector2.Dot(vel0, N)) * N;//改變初始度
                timeCount = 0;
            }
            timeCount++;
            posList.Add(curPos + (Vector2)OriginalPos);
            curPos = nextPos;
        }
        return posList;
    }