Unity中的曲线绘制(五)——样条曲线的应用

发表于2016-10-31
评论0 3.4k浏览
导语
       前面几篇文章介绍了样条曲线的原理以及在Scene视图中的绘制,将它应用于实际的游戏场景中更佳,例如使用一条样条曲线作为path,让Unity中的游戏对象沿着指定路径运动,或者在场景中绘制实用的图形等。

样条曲线的应用
应用1:物体沿轨道运动
      新建一个SplineWalker类,在Update中处理物体的位置改变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using UnityEngine;
 
public class SplineWalker : MonoBehaviour {
 
    public BezierSpline spline;
 
    public float duration;
 
    private float progress;
 
    private void Update () {
        progress += Time.deltaTime / duration;
        if (progress > 1f) {
            progress = 1f;
        }
        transform.localPosition = spline.GetPoint(progress);
    }
}
        创建一个游戏对象,绑定SplineWalker,设置一个duration(运动时间),在play模式下观察它的运动。在这里,创建一个cube沿着样条曲线运动,并为它创建两个子对象,模拟眼睛,来表示它的朝向。



        点击play,Walker对象会沿着曲线在duration时间内完成运动。现在我们希望它的面向始终对着spline的切线方向,正好,BezierSpline中有一个方法可以得到点的切线,即GetDirection。
1
2
3
4
5
6
7
8
9
10
11
12
13
public bool lookForward;
 
private void Update () {
    progress += Time.deltaTime / duration;
    if (progress > 1f) {
        progress = 1f;
    }
    Vector3 position = spline.GetPoint(progress);
    transform.localPosition = position;
    if (lookForward) {
        transform.LookAt(position + spline.GetDirection(progress));
    }
}
     还可以提供一些选项,为SplineWalker提供不同的运动方式。
1
2
3
4
5
public enum SplineWalkerMode {
    Once,// 到达终点即停止
    Loop,// 到达终点后继续沿曲线循环运动
    PingPong// 到达终点后掉头
}
       在SplineWalker中加入if判断,在cube到达曲线终点时要根据SplineWalkerMode处理progress的值。
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
public SplineWalkerMode mode;
 
private bool goingForward = true;
 
private void Update () {
    if (goingForward) {
        progress += Time.deltaTime / duration;
        if (progress > 1f) {
            if (mode == SplineWalkerMode.Once) {
                progress = 1f;
            }
            else if (mode == SplineWalkerMode.Loop) {
                progress -= 1f;
            }
            else {
                progress = 2f - progress;
                goingForward = false;
            }
        }
    }
    else {
        progress -= Time.deltaTime / duration;
        if (progress < 0f) {
            progress = -progress;
            goingForward = true;
        }
    }
 
    Vector3 position = spline.GetPoint(progress);
    transform.localPosition = position;
    if (lookForward) {
        transform.LookAt(position + spline.GetDirection(progress));
    }
}


应用2:沿曲线路径摆放物体
        除此以外,还有一个有趣的实例是,沿着曲线放置一些物体,效果类似与串珠或者项链。同样为每个物体定义朝向。新建SplineDecorator类,然后为相同种类的物体定制预置体(prefab),将预置体放在items数组中。
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
using UnityEngine;
 
public class SplineDecorator : MonoBehaviour {
 
    public BezierSpline spline;
 
    public int frequency;// 同类item出现的频率
 
    public bool lookForward;
 
    public Transform[] items;
 
    private void Awake () {
        if (frequency <= 0 || items == null || items.Length == 0) {
            return;
        }
        float stepSize = 1f / (frequency * items.Length);
        for (int p = 0, f = 0; f < frequency; f++) {
            for (int i = 0; i < items.Length; i++, p++) {
                Transform item = Instantiate(items[i]) as Transform;
                Vector3 position = spline.GetPoint(p * stepSize);
                item.transform.localPosition = position;
                if (lookForward) {
                    item.transform.LookAt(position + spline.GetDirection(p * stepSize));
                }
                item.transform.parent = transform;
            }
        }
    }
}



       当样条曲线是环时,物体可以从头铺到尾,但是如果曲线不是环,终点之前的部分,物体不会很好地覆盖住。我们可以通过改变stepSize来解决这个问题,当loop为false的时候,stepSize的分母减一。
1
2
3
4
5
6
7
8
9
10
if (frequency <= 0 || items == null || items.Length == 0) {
    return;
}
float stepSize = frequency * items.Length;
if (spline.Loop || stepSize == 1) {
    stepSize = 1f / stepSize;
}
else {
    stepSize = 1f / (stepSize - 1);
}
    看了上面的文章 热爱游戏创作的你是不是已经开始热血沸腾了呢?是不是迫不及待的想加入游戏团队成为里面的一员呢?
  福利来啦~赶快加入腾讯GAD交流群,人满封群!每天分享游戏开发内部干货、教学视频、福利活动、和有相同梦想的人在一起,更有腾讯游戏专家手把手教你做游戏!
腾讯GAD游戏程序交流群:484290331

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引