无论是愤怒的小鸟,还是弓箭发射功能,亦或者模拟炮弹受重力影响等抛物线轨迹,都可以使用本文的方法,模拟绝对真实。
和往常一样,先说原理。就是抛物运动,在垂直方向上做加速度运动,在水平方向上,做匀速运动。
在unity上的具体实现为,使用transform进行位移模拟。至于为何不使用刚体的物理模拟,大家自行脑补或者测试。
那么如何使用transform模拟呢?让物体同时在两个方向产生位移就行了,一个是初速度方向,一个是垂直方向。
垂直方向的速度 = a*t,a代表重力加速度,t代表已经运行的时间。

直接把这个脚本托给一个物体,效果就有了。
好现在我们来看看一个简单的弓箭轨迹是怎么产生的吧,上代码:

 

using UnityEngine;
using System.Collections;
/// <summary>
/// 弓箭轨迹模拟
/// 使用:直接挂载在一个物体上,物体就会像抛物线一样抛射出去
/// </summary>
public class SimulateArrow : MonoBehaviour
{

    public float Power = 10;//这个代表发射时的速度/力度等,可以通过此来模拟不同的力大小
    public float Angle = 45;//发射的角度,这个就不用解释了吧
    public float Gravity = -10;//这个代表重力加速度
    public bool IsOne = false;


    private Vector3 MoveSpeed;//初速度向量
    private Vector3 GritySpeed = Vector3.zero;//重力的速度向量,t时为0
    private float dTime;//已经过去的时间

    private Vector3 currentAngle;
    // Use this for initialization
    void Start()
    {
        //通过一个公式计算出初速度向量
        //角度*力度
        MoveSpeed = Quaternion.Euler(new Vector3(0, 0, Angle)) * Vector3.right * Power;
        currentAngle = Vector3.zero;
    }

    // Update is called once per frame
    void FixedUpdate()
    {

        //计算物体的重力速度
        //v = at ;
        GritySpeed.y = Gravity * (dTime += Time.fixedDeltaTime);
        //位移模拟轨迹
        transform.position += (MoveSpeed + GritySpeed) * Time.fixedDeltaTime;
        currentAngle.z = Mathf.Atan((MoveSpeed.y + GritySpeed.y) / MoveSpeed.x) * Mathf.Rad2Deg;
        transform.eulerAngles = currentAngle;


    }
}

 

三维空间,Y轴朝上,重力加速度为大小为g, 已知A(x1, y1, z1), B(x2, y2, z2)是三维空间中的两个点,现在从A点发射一个物体,希望该物体经过时间t之后,落在B点,请给出计算发射速度向量。
说到这,请把unity相关的API全部忘记吧,因为这道题是考察物理和几何的,跟unity API,引擎无关。(话说我面试的公司虽然招unity,可连一句unity的知识都没问啊!)
怎么做呢?在思考题目的解法之前,我先说说这个目的实用价值,你在做AI的时候绝对用得着。就算不写AI,拿个简单的例子,愤怒的小鸟中,可以实现“金手指”功能,给个时间,角度和力度都算出来了,
多神气啊。再举个例子,做动态过场动画的时候,例如需要一发炮弹击中某物体,如果你写的炮弹准确度不高,那过场动画不就完了(当然也有其他方案可以避免),我的意思
就是说,可以使用这个方案实现炮弹的精确打击,而且一切又是那么自然,有重力,也有抛物线,多美好的轨迹啊!
好吧,我说这么多,就是提醒大家,如果在学习中遇到一些有意思的算法或者功能,可以结合到项目实际中去,这样的才发挥他的价值。
嗯,是时候写出答案了。伪代码如下:

//发射初速度V在X,Y,Z轴的速度分量Vx,Vy,Vz,abs(float value)是绝对值函数
 Vx =  abs (x2-x1)   /t;
 Vy =abs (y1-y2)/t+(1/2f)gt;
 Vz =  abs (y2-y1)    /t;
 V =Vector3 (Vx,Vy,Vz);


V就是我们要求的结果。看上去这个式子没什么大不了的,现在来看看把他怎么放到工程里面吧。
我们自己掌握的变量:时间T,坐标P1,坐标P2,有了这三个,一道完美的轨迹就出现了!
代码如下:

using UnityEngine;
using System.Collections;

public class TestSpeed : MonoBehaviour {
    public float time=3;//代表从A点出发到B经过的时长
    public Transform pointA;//点A
    public Transform pointB;//点B
    public float g=-10;//重力加速度
    // Use this for initialization
    private Vector3 speed;//初速度向量
    private Vector3 Gravity;//重力向量
    void Start () {

        transform.position = pointA.position;//将物体置于A点
        //通过一个式子计算初速度
        speed = new Vector3((pointB.position.x - pointA.position.x)/time,
            (pointB.position.y-pointA.position.y)/time-0.5f*g*time, (pointB.position.z - pointA.position.z) / time);
        Gravity = Vector3.zero;//重力初始速度为0
    }
    private float dTime=0;
    // Update is called once per frame
    void FixedUpdate () {

        Gravity.y = g * (dTime += Time.fixedDeltaTime);//v=at
        //模拟位移
        transform.Translate(speed*Time.fixedDeltaTime);
        transform.Translate(Gravity * Time.fixedDeltaTime);
    }
}