Unity教程:路径移动

发表于2017-03-28
评论0 3.2k浏览
Path Following 大多数用在 AI 的路径移动,针对事前规划好的移动路径,呈现出 AI 在移动巡逻的行为,下面就给大家介绍下在Unity中规划 AI 的移动路径的教程。
 
原理相当简单
大家看完后也可以自行使用不同的方法应用
 
先建立一个新专案
接著建立一个 Path.cs 脚本
这个脚本是用来规划 AI 的移动路径
并将其显示以供游戏开发者调整
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using UnityEngine;
using System.Collections;
 
public class Path : MonoBehaviour {
 
    //Display the path
    public bool showPath = true;
    public Color pathColor = Color.red;
 
    //The path is loop or not
    public bool loop = true;
 
    //The waypoint radius
    public float Radius = 2.0f;
 
    //Waypoints array
    public Transform[] wayPoints;
 
    //The Reset fuction is one of Unity API.
    //MonoBehaviour.Reset()
    //This function is only called in editor mode.
    void Reset() {
 
        //Reset the wayPoint array
        wayPoints = new Transform[ GameObject.FindGameObjectsWithTag ("WayPoint").Length ];
 
        for( int cnt = 0; cnt < wayPoints.Length; cnt++ ) {
 
            wayPoints[cnt] = GameObject.Find( "WayPoint_" + (cnt + 1).ToString() ).transform;
 
        }
 
    }
 
    //Get the length of wayPoint array
    public float Length {
 
        get {
 
            return wayPoints.Length;
         
        }
     
    }
 
    //Get the position in the array with its index number
    public Vector3 GetPosition(int index) {
 
        return wayPoints[index].position; 
     
    }
 
 
    //The OnDrawGizmos function is one of Unity API
    //MonoBehaviour.OnDrawGizmos()
    //This function will display gizmo in Scene and will not display in Game
    void OnDrawGizmos() {
 
        //If showPath is false, return
        if (!showPath) return;
 
        //Draw the path line
        for ( int i = 0; i < wayPoints.Length; i++ ) {
 
            if (i + 1 < wayPoints.Length) {
 
                Debug.DrawLine( wayPoints[i].position, wayPoints[i + 1].position, pathColor );
             
            }
            else {
 
                if( loop ) {
 
                    Debug.DrawLine( wayPoints[i].position, wayPoints[0].position, pathColor );
 
                }
 
            }
         
        }
     
    }
 
}
6~17
一些基本参数的定义
 
19~34 Reset
接著要介绍 Unity 中的一个实用方法
MonoBehaviour.Reset()
这个方法是应用在 Inspector 中 Component 的 Reset 裡
 
它可以帮助使用者快速的重新定义
这裡就是使用它来重新抓取命名为:WayPoint_X 的物件
所以如果使用者有多的物件时
不需要一个一个重新抓取
只需要点一下 Reset 就可以立即更新
36~45 Length
阵列 wayPoints 的封装
 
47~52 GetPosition
取得对应 waypoint 的位置
 
55~84 OnDrawGizmos
MonoBehavior.OnDrawGizmos()
这个方法可以在 Scene 页面上绘出一些基本线段、图形
而不会在 Game 页面上显示
方便开发者调整
 
这裡使用这个方法来做路径的显示
使用者可以观察目前移动路径并即时调整
 
接下来建立一个空物件命名为 Path
并将 Path.cs 拖拉至该物件上
调整实际画面如下
目前路径规划已经完成
接下来要创造出一台会跟著我们定义出的路径移动的车子
 
建立一个 PathFollowing.cs 脚本
此脚本用来控制车子的移动
接著创建一个 Cube 并命名为 Car
并把 PathFollowing.cs 脚本拖拉至 Car 身上
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using UnityEngine;
using System.Collections;
  
public class PathFollowing : MonoBehaviour {
      
    public Path path;//The path
  
    public float speed = 20.0f;//following speed
    public float mass = 5.0f;//this is for object mass for simulating the real car
  
    public bool isLooping = true;//the car will loop or not
      
    private float curSpeed;//Actual speed of the car
    private int curPathIndex;
    private float pathLength;
    private Vector3 targetPosition;
  
    private Vector3 curVelocity;
  
    void Start () {
  
        pathLength = path.Length;
  
        curPathIndex = 0;
  
        //get the current velocity of the vehicle
        curVelocity = transform.forward;
      
    }
      
    void Update () {
  
        //Unify the speed
        curSpeed = speed * Time.deltaTime;
  
        targetPosition = path.GetPosition( curPathIndex );
  
        //If reach the radius within the path then move to next point in the path
        if ( Vector3.Distance(transform.position, targetPosition) < path.Radius ) {
  
            //Don't move the vehicle if path is finished
            if ( curPathIndex < pathLength - 1 )
                curPathIndex++;
            else if ( isLooping )
                curPathIndex = 0;
            else
                return;
          
        }
  
        //Calculate the acceleration towards the path
        curVelocity += Accelerate( targetPosition );
  
        //Move the car according to the velocity
        transform.position += curVelocity;
        //Rotate the car towards the desired Velocity
        transform.rotation = Quaternion.LookRotation( curVelocity );
      
    }
  
    //Steering algorithm to steer the vector towards the target
    public Vector3 Accelerate( Vector3 target ) {
  
        //Calculate the directional vector from the current position towards the target point
        Vector3 desiredVelocity = target - transform.position;
  
        //Normalise the desired Velocity
        desiredVelocity.Normalize();
  
        desiredVelocity *= curSpeed;
  
        //Calculate the force Vector
        Vector3 steeringForce = desiredVelocity - curVelocity;
        Vector3 acceleration = steeringForce / mass;
  
        return acceleration;
      
    }
  
}
6~18
参数定义
要注意的是 curPathIndex 这个参数
这个参数是用来记录当前的目标点
车子会依照这个 int 来做目标点的转换
 
20~29 Start
MonoBehaviour.Start()
 
31~59 Update
MonoBehavior.Update()
每 frame 都会执行一次 Update 裡的方法
 
为了统一速度参数而使用了 Time.deltaTime
当我们把参数乘上 Time.deltaTime
在这个范例中可以把它想成:每秒移动 curSpeed 公尺
如果不使用 Time.deltaTime 的话则是:每 frame 移动 curSpeed 公尺
两者会有极大的差距
Time.deltaTime
 
接著就是判断 car 与目标的位置如果接近到一定距离
则将目标点设为下一点
并计算其加速度
 
这裡还可以到 Quaternion.LookRotation() 这个方法
这个方法是用来返回一个 Quaternion
因为 transform.rotation 本身定义是一个 Quaternion
所以需要使用这个方法才不会导致编译出错
 
61~78 Accelerate
计算加速度
这裡只是简单的数学运算
要注意的只有 desiredVelocity.Normalize()
Vector3.Normalize() 是将向量规一化
将向量规一化后在乘上我们的速度就能得到下一步的移动速度
 
接著回到 Hierarchy 进行设定
将 Path 物件拖拉至 PathFollowing 中
并填入想要的速度及重量
执行结果
可以试试调整不同的速度及重量
看看不同的执行结果

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