1. 通俗来说贝塞尔曲线

在游戏开发中,经常会用到抛物线,例如导弹抛物线飞行,用贝塞尔曲线很容易实现。通俗来讲,贝塞尔曲线就是通过三个点,产生一条曲线,通过一个变量 t,可以取到曲线上的某一个点的位置,这里的 t 取值是从0.0~1.0之间。例如 t0.5,就是取曲线相对来说中间的位置点。我觉得这里的 0.0~1.0可以当作一个百分比来用。

2. 曲线函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <summary>
/// 返回曲线在某一时间t上的点
/// </summary>
/// <param name="_point0">起始点</param>
/// <param name="_point1">中间点</param>
/// <param name="_point2">终止点</param>
/// <param name="t">当前时间t(0.0~1.0)</param>
/// <returns></returns>
public static Vector3 GetCurvePoint(Vector3 _point0, Vector3 _point1, Vector3 _point2, float t)
{
t = Mathf.Clamp(t, 0.0f, 1.0f);
float x = ((1 - t) * (1 - t)) * _point0.x + 2 * t * (1 - t) * _point1.x + t * t * _point2.x;
float y = ((1 - t) * (1 - t)) * _point0.y + 2 * t * (1 - t) * _point1.y + t * t * _point2.y;
float z = ((1 - t) * (1 - t)) * _point0.z + 2 * t * (1 - t) * _point1.z + t * t * _point2.z;
Vector3 pos = new Vector3(x, y, z);
return pos;
}

例如一个炮弹从A点要打到B点,在A和B的上方使用一个点作为中间点,就可以拉出一条曲线来,然后通过时间增量t,在Update中不断取这条曲线上的点,赋予炮弹,就可以让炮弹按抛物线飞行。

3. 一个大概的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using UnityEngine;
using System.Collections;

public class CurveTest : MonoBehaviour
{
public Transform fromPoint; // 起始点
public Transform middlePoint; // 中间点
public Transform endPoint; // 终止点
public Transform moveObj; // 要移动的物体

private float ticker = 0.0f;

private float attackTime = 2.0f; // 假设要用2秒飞到目标点

/// <summary>
/// 返回曲线在某一时间t上的点
/// </summary>
/// <param name="_p0">起始点</param>
/// <param name="_p1">中间点</param>
/// <param name="_p2">终止点</param>
/// <param name="t">当前时间t(0.0~1.0)</param>
/// <returns></returns>
public static Vector3 GetCurvePoint(Vector3 _p0, Vector3 _p1, Vector3 _p2, float t)
{
t = Mathf.Clamp(t, 0.0f, 1.0f);
float x = ((1 - t) * (1 - t)) * _p0.x + 2 * t * (1 - t) * _p1.x + t * t * _p2.x;
float y = ((1 - t) * (1 - t)) * _p0.y + 2 * t * (1 - t) * _p1.y + t * t * _p2.y;
float z = ((1 - t) * (1 - t)) * _p0.z + 2 * t * (1 - t) * _p1.z + t * t * _p2.z;
Vector3 pos = new Vector3(x, y, z);
return pos;
}

private void Update()
{
ticker += Time.deltaTime;
float t = ticker / attackTime; // 这里是计算当前已用时间占计划用时间的百分比,当作增量t
t = Mathf.Clamp(t, 0.0f, 1.0f);
Vector3 p1 = fromPoint.position;
Vector3 p2 = middlePoint.position;
Vector3 p3 = endPoint.position;
Vector3 currPos = GetCurvePoint(p1, p2, p3, timeValue);
moveObj.position = currPos;

if(t == 1.0f)
{
// 到达目标点
}
}
}

4. 维基百科上对于贝塞尔曲线的解释

image

图片来自维基百科