unity3D:游戏分解之曲线

Posted fish_yu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity3D:游戏分解之曲线相关的知识,希望对你有一定的参考价值。

一提到曲线,很多新手就头疼了,包括我。查了很多资料,终于有个大概的了解。想深入了解曲线原理的,推荐一个链接http://www.cnblogs.com/jay-dong/archive/2012/09/26/2704188.html

之前写了一篇博文unity3D:游戏分解之角色移动和相机跟随,里面用到了曲线插值,这里算是对上篇博文的一个补充

先看一下曲线的效果

 

在使用NGUI的过程中,发现iTween.cs里面有两个很有用的方法,一个是输入指定路点数组,一个就是曲线的插值算法。今天我们主要就用到这两个方法来实现曲线效果。

 1 public static Vector3[] PathControlPointGenerator(Vector3[] path)
 2     {
 3         Vector3[] suppliedPath;
 4         Vector3[] vector3s;
 5 
 6         //create and store path points:
 7         suppliedPath = path;
 8 
 9         //populate calculate path;
10         int offset = 2;
11         vector3s = new Vector3[suppliedPath.Length + offset];
12         Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
13 
14         //populate start and end control points:
15         //vector3s[0] = vector3s[1] - vector3s[2];
16         vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
17         vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
18 
19         //is this a closed, continuous loop? yes? well then so let\'s make a continuous Catmull-Rom spline!
20         if (vector3s[1] == vector3s[vector3s.Length - 2])
21         {
22             Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
23             Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
24             tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
25             tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
26             vector3s = new Vector3[tmpLoopSpline.Length];
27             Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
28         }
29 
30         return (vector3s);
31     }
32 
33     //andeeee from the Unity forum\'s steller Catmull-Rom class ( http://forum.unity3d.com/viewtopic.php?p=218400#218400 ):
34     public static Vector3 Interp(Vector3[] pts, float t)
35     {
36         int numSections = pts.Length - 3;
37         int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
38         float u = t * (float)numSections - (float)currPt;
39 
40         if(currPt == 0)
41         {
42             int dsd = 0;
43         }
44 
45         Vector3 a = pts[currPt];
46         Vector3 b = pts[currPt + 1];
47         Vector3 c = pts[currPt + 2];
48         Vector3 d = pts[currPt + 3];
49 
50         return .5f * (
51             (-a + 3f * b - 3f * c + d) * (u * u * u)
52             + (2f * a - 5f * b + 4f * c - d) * (u * u)
53             + (-a + c) * u
54             + 2f * b
55         );
56     }

 

直接上完整代码,把这个脚本放到相机上,然后在场景中拖几个物件作为路点,就可以实现上面的效果

  1 using System;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 namespace Fish.Study.Curve
  6 {
  7     /// <summary>
  8     /// 曲线测试
  9     /// </summary>
 10     public class CurveTest : MonoBehaviour
 11     {
 12         //路点
 13         public GameObject[] GameObjectList;
 14         //各路点的坐标
 15         public List<Vector3> TransDataList = new List<Vector3>();
 16 
 17         void Start()
 18         {
 19         }
 20 
 21         //Gizmos
 22         void OnDrawGizmos()
 23         {
 24             //1个点是不能画出曲线的,2个点实际上是直线
 25             if (GameObjectList.Length <= 1) return;
 26 
 27             TransDataList.Clear();
 28             for (int i = 0; i < GameObjectList.Length; ++i)
 29             {
 30                 TransDataList.Add(GameObjectList[i].transform.position);
 31             }
 32 
 33             if (TransDataList != null && TransDataList.Count > 1)
 34             {
 35                 DrawPathHelper(TransDataList.ToArray(), Color.red);
 36             }
 37         }
 38 
 39         public Vector3[] GetCurveData()
 40         {
 41             if (TransDataList != null && TransDataList.Count > 1)
 42             {
 43                 var v3 = (TransDataList.ToArray());
 44                 Vector3[] vector3s = PathControlPointGenerator(v3);
 45                 return vector3s;
 46             }
 47 
 48             return null;
 49         }
 50 
 51         //NGUI iTween.cs中的方法,输入路径点
 52         public static Vector3[] PathControlPointGenerator(Vector3[] path)
 53         {
 54             Vector3[] suppliedPath;
 55             Vector3[] vector3s;
 56 
 57             //create and store path points:
 58             suppliedPath = path;
 59 
 60             //populate calculate path;
 61             int offset = 2;
 62             vector3s = new Vector3[suppliedPath.Length + offset];
 63             Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
 64 
 65             //populate start and end control points:
 66             vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
 67             vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
 68 
 69             //is this a closed, continuous loop? yes? well then so let\'s make a continuous Catmull-Rom spline!
 70             if (vector3s[1] == vector3s[vector3s.Length - 2])
 71             {
 72                 Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
 73                 Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
 74                 tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
 75                 tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
 76                 vector3s = new Vector3[tmpLoopSpline.Length];
 77                 Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
 78             }
 79 
 80             return (vector3s);
 81         }
 82 
 83         //曲线插值函数
 84         public static Vector3 Interp(Vector3[] pts, float t)
 85         {
 86             int numSections = pts.Length - 3;
 87             int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
 88             float u = t * (float)numSections - (float)currPt;
 89 
 90             Vector3 a = pts[currPt];
 91             Vector3 b = pts[currPt + 1];
 92             Vector3 c = pts[currPt + 2];
 93             Vector3 d = pts[currPt + 3];
 94 
 95             return .5f * (
 96                 (-a + 3f * b - 3f * c + d) * (u * u * u)
 97                 + (2f * a - 5f * b + 4f * c - d) * (u * u)
 98                 + (-a + c) * u
 99                 + 2f * b
100             );
101         }
102 
103         //画曲线
104         private void DrawPathHelper(Vector3[] path, Color color)
105         {
106             Vector3[] vector3s = PathControlPointGenerator(path);
107 
108             //Line Draw:
109             Vector3 prevPt = Interp(vector3s, 0);
110             int SmoothAmount = path.Length * 20;
111             for (int i = 1; i <= SmoothAmount; i++)
112             {
113                 float pm = (float)i / SmoothAmount;
114                 Vector3 currPt = Interp(vector3s, pm);
115 
116                 Gizmos.color = color;
117                 Gizmos.DrawSphere(currPt, 0.2f);
118                 prevPt = currPt;
119             }
120         }
121     }
122 }

 

以上是关于unity3D:游戏分解之曲线的主要内容,如果未能解决你的问题,请参考以下文章

unity3d游戏开发学习分享之表面着色器讲解

Unity3D实战RPG黑暗之光:游戏分解及各系统的实现

Unity3D游戏开发之从Unity3D项目版本号控制说起

《Unity3D动作游戏开发实战》如何扩展?

《Unity3D动作游戏开发实战》笔记及扩展2.1

Unity3D游戏开发之简单的碰撞检測