Unity中的曲线绘制(五)——样条曲线的应用
发表于2016-10-31
导语
创建一个游戏对象,绑定SplineWalker,设置一个duration(运动时间),在play模式下观察它的运动。在这里,创建一个cube沿着样条曲线运动,并为它创建两个子对象,模拟眼睛,来表示它的朝向。
还可以提供一些选项,为SplineWalker提供不同的运动方式。
在SplineWalker中加入if判断,在cube到达曲线终点时要根据SplineWalkerMode处理progress的值。
前面几篇文章介绍了样条曲线的原理以及在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); } } |
点击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)); } } |
1 2 3 4 5 | public enum SplineWalkerMode { Once, // 到达终点即停止 Loop, // 到达终点后继续沿曲线循环运动 PingPong // 到达终点后掉头 } |
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交流群,人满封群!每天分享游戏开发内部干货、教学视频、福利活动、和有相同梦想的人在一起,更有腾讯游戏专家手把手教你做游戏!