AI 学习

极简状态机:

 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     public class Player : MonoBehaviour {
14 
15         /// <summary>
16         /// 移动速度
17         /// </summary>
18         public float m_moveSpeed = 10.0f;
19 
20         private void Update() {
21             Move();
22         }
23 
24         private void Move() {
25             Vector3 direction = Vector3.zero;
26             if(Input.GetKey(KeyCode.W)) {
27                 direction = transform.forward;
28             }
29             if(Input.GetKey(KeyCode.S)) {
30                 direction = -transform.forward;
31             }
32             if(Input.GetKey(KeyCode.A)) {
33                 direction = -transform.right;
34             }
35             if(Input.GetKey(KeyCode.D)) {
36                 direction = transform.right;
37             }
38             transform.Translate(direction * Time.deltaTime * m_moveSpeed,Space.World);
39         }
40     }
41 }
Player
  1 /*
  2 脚本名称:
  3 脚本作者:
  4 建立时间:
  5 脚本功能:
  6 版本号:
  7 */
  8 using UnityEngine;
  9 using UnityEngine.UI;
 10 using System.Collections;
 11 
 12 namespace VoidGame {
 13 
 14     /// <summary>
 15     /// 状态
 16     /// </summary>
 17     public enum FSMState {
 18         /// <summary>
 19         /// 巡逻
 20         /// </summary>
 21         Patrol,
 22         /// <summary>
 23         /// 追逐
 24         /// </summary>
 25         Chase,
 26         /// <summary>
 27         /// 攻击
 28         /// </summary>
 29         Attack,
 30         /// <summary>
 31         /// 死亡
 32         /// </summary>
 33         Dead
 34     }
 35 
 36     public class Enemy : MonoBehaviour {
 37 
 38         /// <summary>
 39         /// 玩家
 40         /// </summary>
 41         public Transform m_player;
 42 
 43         /// <summary>
 44         /// 路标列表
 45         /// </summary>
 46         public Transform[] m_waypoints;
 47         /// <summary>
 48         /// 目标路标索引
 49         /// </summary>
 50         private int m_targetWaypointIndex;
 51 
 52         /// <summary>
 53         /// 移动速度
 54         /// </summary>
 55         public float m_moveSpeed = 0.1f;
 56 
 57         /// <summary>
 58         /// 状态
 59         /// </summary>
 60         public FSMState m_fsmState;
 61 
 62         /// <summary>
 63         /// 和玩家的距离
 64         /// </summary>
 65         public float m_distance;
 66 
 67         /// <summary>
 68         /// 追逐距离
 69         /// </summary>
 70         private float m_chaseDistance = 5f;
 71         /// <summary>
 72         /// 攻击距离
 73         /// </summary>
 74         private float m_attackDistance = 2f;
 75 
 76         [Space(10)]
 77         public Text m_text;
 78 
 79         private void Start() {
 80             //初始状态:巡逻
 81             m_fsmState = FSMState.Patrol;
 82             //设置初始目标路标索引
 83             m_targetWaypointIndex = 0;
 84         }
 85 
 86         private void Update() {
 87             //根据状态切换
 88             switch(m_fsmState) {
 89             case FSMState.Patrol:
 90                 UpdatePatrolState();
 91                 break;
 92             case FSMState.Chase:
 93                 UpdateChaseState();
 94                 break;
 95             case FSMState.Attack:
 96                 UpdateAttackState();
 97                 break;
 98             case FSMState.Dead:
 99                 break;
100             }
101 
102             DisplayDistance();
103         }
104 
105         private void OnDrawGizmos() {
106             //画自身的前方向
107             iTween.DrawLine(new Vector3[] { transform.position,transform.position + transform.forward },Color.yellow);
108 
109             //根据状态画和玩家之间的关联线
110             switch(m_fsmState) {
111             case FSMState.Patrol:
112                 
113                 break;
114             case FSMState.Chase:
115                 DrawLine(Color.green);
116                 break;
117             case FSMState.Attack:
118                 DrawLine(Color.red);
119                 break;
120             case FSMState.Dead:
121                 break;
122             }
123             
124 
125         }
126 
127         /// <summary>
128         /// 更新巡逻状态
129         /// </summary>
130         private void UpdatePatrolState() {
131             if(!IsArrived()) {
132                 Move(m_waypoints[m_targetWaypointIndex]);
133             }
134             if(CalculateDistance() <= m_chaseDistance) {
135                 m_fsmState = FSMState.Chase;
136             }
137         }
138 
139         /// <summary>
140         /// 更新追逐状态
141         /// </summary>
142         private void UpdateChaseState() {
143             Move(m_player);
144             //小于等于攻击距离,攻击
145             if(CalculateDistance() <= m_attackDistance) {
146                 m_fsmState = FSMState.Attack;
147             //大于攻击距离并且小于等于追逐距离,追逐
148             } else if(CalculateDistance() > m_attackDistance && CalculateDistance() <= m_chaseDistance) {
149                 m_fsmState = FSMState.Chase;
150             //其余情况也就是大于追逐距离,巡逻
151             } else {
152                 m_fsmState = FSMState.Patrol;
153             }
154         }
155 
156         /// <summary>
157         /// 更新攻击状态
158         /// </summary>
159         private void UpdateAttackState() {
160             //大于攻击距离并且小于等于追逐距离,追逐
161             if(CalculateDistance() > m_attackDistance && CalculateDistance() <= m_chaseDistance) {
162                 m_fsmState = FSMState.Chase;
163             //大于追逐距离,巡逻
164             } else if(CalculateDistance() > m_chaseDistance) {
165                 m_fsmState = FSMState.Patrol;
166             }
167         }
168 
169         private void UpdateDeadState() {
170 
171         }
172 
173         /// <summary>
174         /// 画和玩家之间的线
175         /// </summary>
176         private void DrawLine(Color color) {
177             iTween.DrawLine(new Transform[] { transform,m_player.transform },color);
178         }
179 
180         /// <summary>
181         /// 显示玩家的距离
182         /// </summary>
183         private void DisplayDistance() {
184             float distance = Vector3.Distance(transform.position,m_player.position);
185             m_text.text = "State:"+m_fsmState+"
Distance:"+ distance.ToString();
186         }
187 
188         /// <summary>
189         /// 计算和玩家的距离
190         /// </summary>
191         private float CalculateDistance() {
192             return Vector3.Distance(transform.position,m_player.position);
193         }
194         
195         /// <summary>
196         /// 是否到达路标
197         /// </summary>
198         private bool IsArrived() {
199             float distance = Vector3.Distance(transform.position,m_waypoints[m_targetWaypointIndex].position);
200             if(distance < 0.1f) {
201                 m_targetWaypointIndex++;
202                 m_targetWaypointIndex = m_targetWaypointIndex % 4;
203                 return true;
204             }
205             return false;
206         }
207 
208         private void Move(Transform target) {
209             transform.LookAt(target);
210             transform.Translate(transform.forward * Time.deltaTime * m_moveSpeed,Space.World);
211         }
212     }
213 }
Enemy

视频:https://pan.baidu.com/s/1mioIk6c

项目:https://pan.baidu.com/s/1cpc9T8

SlotMachineWeighted

  1 using UnityEngine;
  2 using System.Collections;
  3 
  4 public class SlotMachineWeighted : MonoBehaviour {
  5     
  6     public float spinDuration = 2.0f;
  7     public int numberOfSym = 10;
  8     public GameObject betResult;
  9     
 10     private bool startSpin = false;
 11     private bool firstReelSpinned = false;
 12     private bool secondReelSpinned = false;
 13     private bool thirdReelSpinned = false;
 14     
 15     private int betAmount = 100;
 16     
 17     private int creditBalance = 1000;
 18     private ArrayList weightedReelPoll = new ArrayList();    
 19     private int zeroProbability = 30;
 20     
 21     private int firstReelResult = 0;
 22     private int secondReelResult = 0;
 23     private int thirdReelResult = 0;
 24     
 25     private float elapsedTime = 0.0f;
 26     
 27     // Use this for initialization
 28     void Start () {
 29         betResult.GetComponent<GUIText>().text = "";
 30         
 31         for (int i = 0; i < zeroProbability; i++) {
 32             weightedReelPoll.Add(0);        
 33         }
 34         
 35         int remainingValuesProb = (100 - zeroProbability)/9;
 36         
 37         for (int j = 1; j < 10; j++) {
 38             for (int k = 0; k < remainingValuesProb; k++) {
 39                 weightedReelPoll.Add(j);
 40             }
 41         }
 42     }
 43     
 44     void OnGUI() {
 45         
 46         GUI.Label(new Rect(150, 40, 100, 20), "Your bet: ");
 47         betAmount = int.Parse(GUI.TextField(new Rect(220, 40, 50, 20), betAmount.ToString(), 25));        
 48         
 49         GUI.Label(new Rect(300, 40, 100, 20), "Credits: " + creditBalance.ToString());
 50         
 51         if (GUI.Button(new Rect(200,300,150,40), "Pull Lever")) {
 52             betResult.GetComponent<GUIText>().text = "";            
 53             startSpin = true;
 54         }
 55     }
 56     
 57     void checkBet() {
 58         if (firstReelResult == secondReelResult && secondReelResult == thirdReelResult) {
 59             betResult.GetComponent<GUIText>().text = "JACKPOT!";
 60             creditBalance += betAmount * 50;
 61         }
 62         else if (firstReelResult == 0 && thirdReelResult == 0) {            
 63             betResult.GetComponent<GUIText>().text = "YOU WIN " + (betAmount/2).ToString();
 64             creditBalance -= (betAmount/2);
 65         }
 66         else if (firstReelResult == secondReelResult) {            
 67             betResult.GetComponent<GUIText>().text = "AWW... ALMOST JACKPOT!";
 68         }
 69         else if (firstReelResult == thirdReelResult) {            
 70             betResult.GetComponent<GUIText>().text = "YOU WIN " + (betAmount*2).ToString();
 71             creditBalance -= (betAmount*2);
 72         }
 73         else {
 74             betResult.GetComponent<GUIText>().text = "YOU LOSE!";
 75             creditBalance -= betAmount;
 76         }
 77     }
 78     
 79     // Update is called once per frame
 80     void FixedUpdate () {        
 81         if (startSpin) {
 82             elapsedTime += Time.deltaTime;
 83             int randomSpinResult = Random.Range(0, numberOfSym);
 84             if (!firstReelSpinned) {
 85                 GameObject.Find("firstReel").GetComponent<GUIText>().text = randomSpinResult.ToString();
 86                 if (elapsedTime >= spinDuration) {
 87                     int weightedRandom = Random.Range(0, weightedReelPoll.Count);    
 88                     GameObject.Find("firstReel").GetComponent<GUIText>().text = weightedReelPoll[weightedRandom].ToString();
 89                     firstReelResult = (int)weightedReelPoll[weightedRandom];
 90                     firstReelSpinned = true;
 91                     elapsedTime = 0;
 92                 }
 93             }
 94             else if (!secondReelSpinned) {
 95                 GameObject.Find("secondReel").GetComponent<GUIText>().text = randomSpinResult.ToString();
 96                 if (elapsedTime >= spinDuration) {
 97                     secondReelResult = randomSpinResult;
 98                     secondReelSpinned = true;
 99                     elapsedTime = 0;
100                 }
101             }
102             else if (!thirdReelSpinned) {
103                 GameObject.Find("thirdReel").GetComponent<GUIText>().text = randomSpinResult.ToString();
104                 if (elapsedTime >= spinDuration) {                        
105                     if ((firstReelResult == secondReelResult) &&
106                         randomSpinResult != firstReelResult) {
107                         //the first two reels have resulted the same symbol
108                         //but unfortunately the third reel missed
109                         //so instead of giving a random number we'll return a symbol which is one less than the other 2
110                         
111                         randomSpinResult = firstReelResult - 1;
112                         if (randomSpinResult < firstReelResult) randomSpinResult = firstReelResult - 1;
113                         if (randomSpinResult > firstReelResult) randomSpinResult = firstReelResult + 1;
114                         if (randomSpinResult < 0) randomSpinResult = 0;
115                         if (randomSpinResult > 9) randomSpinResult = 9;
116                         
117                         GameObject.Find("thirdReel").GetComponent<GUIText>().text = randomSpinResult.ToString();    
118                         thirdReelResult = randomSpinResult;
119                     }
120                     else {
121                         int weightedRandom = Random.Range(0, weightedReelPoll.Count);    
122                         GameObject.Find("thirdReel").GetComponent<GUIText>().text = weightedReelPoll[weightedRandom].ToString();
123                         thirdReelResult = (int)weightedReelPoll[weightedRandom];
124                     }
125                     
126                     startSpin = false;
127                     elapsedTime = 0;
128                     firstReelSpinned = false;
129                     secondReelSpinned = false;
130                     
131                     checkBet();
132                 }
133             }
134         }
135     }
136 }
SlotMachineWeighted

 极简感应器:

 

 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     /// <summary>
14     /// 玩家
15     /// </summary>
16     public class Player : MonoBehaviour {
17 
18         /// <summary>
19         /// 移动目标
20         /// </summary>
21         public Transform m_target;
22 
23         /// <summary>
24         /// 移动速度
25         /// </summary>
26         public float m_moveSpeed = 10f;
27 
28         private void Update() {
29             Move();
30         }
31 
32         /// <summary>
33         /// 移动
34         /// </summary>
35         private void Move() {
36             if(Vector3.Distance(transform.position,m_target.position) < 1.0f) {
37                 return;
38             }
39 
40             Vector3 position = m_target.position;
41             position.y = transform.position.y;
42 
43             Quaternion lookQuaternion = Quaternion.LookRotation(position - transform.position);
44             transform.rotation = Quaternion.Slerp(transform.rotation,lookQuaternion,0.1f);
45             transform.Translate(Vector3.forward * Time.deltaTime * 10);
46         }
47 
48         private void OnDrawGizmos() {
49             iTween.DrawLine(new Vector3[] { transform.position,transform.position + transform.forward });
50         }
51     }
52 }
Player
 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     /// <summary>
14     /// 鼠标点击指示
15     /// </summary>
16     public class Target : MonoBehaviour {
17 
18         private void Update() {
19             if(Input.GetMouseButtonDown(0)) {
20                 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
21                 RaycastHit hitInfo;
22                 if(Physics.Raycast(ray.origin,ray.direction,out hitInfo)) {
23                     Vector3 position = hitInfo.point;
24                     position.y = 1;
25                     transform.position = position;
26                 }
27             }
28         }
29     }
30 }
Target
 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     /// <summary>
14     /// 漫游
15     /// </summary>
16     public class Wander : MonoBehaviour {
17 
18         /// <summary>
19         /// 目标位置
20         /// </summary>
21         private Vector3 m_targetPosition;
22         /// <summary>
23         /// 移动速度
24         /// </summary>
25         private float m_moveSpeed = 5.0f;
26         //private float rotSpeed = 2.0f;
27         /// <summary>
28         /// 移动范围
29         /// </summary>
30         private float minX, maxX, minZ, maxZ;
31 
32         void Start() {
33             minX = -20.0f;
34             maxX = 20.0f;
35 
36             minZ = -20.0f;
37             maxZ = 20.0f;
38 
39             GetNextPosition();
40         }
41 
42         void Update() {
43             if(Vector3.Distance(m_targetPosition,transform.position) <= 1.0f)
44                 GetNextPosition();
45 
46             Vector3 position = transform.position;
47             position.y = 0.5f;
48 
49             Quaternion targetRotation = Quaternion.LookRotation(m_targetPosition - position);
50             transform.rotation = Quaternion.Slerp(transform.rotation,targetRotation,Time.deltaTime);
51 
52             transform.Translate(new Vector3(0,0,m_moveSpeed * Time.deltaTime));
53         }
54 
55         void GetNextPosition() {
56             m_targetPosition = new Vector3(Random.Range(minX,maxX),0.5f,Random.Range(minZ,maxZ));
57         }
58     }
59 }
Wander
 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     /// <summary>
14     /// 感观
15     /// </summary>
16     public class Sense : MonoBehaviour {
17 
18         public Aspect.aspect aspectName = Aspect.aspect.Enemy;
19 
20         /// <summary>
21         /// 检测频率
22         /// </summary>
23         public float detectionRate = 1.0f;
24         /// <summary>
25         /// 距上一次检测经过的时间
26         /// </summary>
27         protected float elapsedTime = 0.0f;
28 
29         /// <summary>
30         /// 初始化
31         /// </summary>
32         protected virtual void Initialise() { }
33         /// <summary>
34         /// 更新感官
35         /// </summary>
36         protected virtual void UpdateSense() { }
37 
38         void Start() {
39             elapsedTime = 0.0f;
40             Initialise();
41         }
42         void Update() {
43             UpdateSense();
44         }
45     }
46 }
Sense
 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     /// <summary>
14     /// 视觉
15     /// </summary>
16     public class Perspective : Sense {
17 
18         /// <summary>
19         /// 视场角度
20         /// </summary>
21         public int FieldOfView = 45;
22         /// <summary>
23         /// 视野距离
24         /// </summary>
25         public int ViewDistance = 100;
26 
27         /// <summary>
28         /// 玩家
29         /// </summary>
30         private Transform playerTrans;
31         /// <summary>
32         /// 射线方向
33         /// </summary>
34         private Vector3 rayDirection;
35 
36         protected override void Initialise() {
37             playerTrans = GameObject.FindGameObjectWithTag("Player").transform;
38             aspectName = Aspect.aspect.Player;
39         }
40 
41         protected override void UpdateSense() {
42             elapsedTime += Time.deltaTime;
43 
44             if(elapsedTime >= detectionRate) {
45                 //elapsedTime = 0;
46                 DetectAspect();
47             }
48         }
49 
50         /// <summary>
51         /// 检测切面
52         /// </summary>
53         void DetectAspect() {
54             RaycastHit hit;
55             //射线方向位从自身到玩家的方向
56             rayDirection = playerTrans.position - transform.position;
57 
58             //如果自身的朝向和从自身到玩家的方向之间的夹角小于视场角度,射线检测
59             if((Vector3.Angle(rayDirection,transform.forward)) < FieldOfView) {
60                 if(Physics.Raycast(transform.position,rayDirection,out hit,ViewDistance)) {
61                     Aspect aspect = hit.collider.GetComponent<Aspect>();
62                     if(aspect != null) {
63                         if(aspect.aspectName == aspectName) {
64                             print("Enemy Detected");
65                         }
66                     }
67                 }
68             }
69         }
70 
71         void OnDrawGizmos() {
72 
73             //红线连接自身和玩家
74             Debug.DrawLine(transform.position,playerTrans.position,Color.red);
75 
76             //正前方射线
77             Vector3 frontRayPoint = transform.position + (transform.forward * ViewDistance);
78             Debug.DrawLine(transform.position,frontRayPoint,Color.green);
79 
80             //左前方射线
81             Vector3 leftRayPoint = frontRayPoint;
82             leftRayPoint.x += FieldOfView * 0.5f;
83             Debug.DrawLine(transform.position,leftRayPoint,Color.green);
84 
85             //右前方射线
86             Vector3 rightRayPoint = frontRayPoint;
87             rightRayPoint.x -= FieldOfView * 0.5f;
88             Debug.DrawLine(transform.position,rightRayPoint,Color.green);
89         }
90     }
91 }
Perspective
 1 /*
 2 脚本名称:
 3 脚本作者:
 4 建立时间:
 5 脚本功能:
 6 版本号:
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 
11 namespace VoidGame {
12 
13     /// <summary>
14     /// 切面
15     /// </summary>
16     public class Aspect : MonoBehaviour {
17 
18         /// <summary>
19         /// 角色
20         /// </summary>
21         public enum aspect {
22             Player,
23             Enemy
24         }
25         public aspect aspectName;
26     }
27 }
Aspect

项目:https://pan.baidu.com/s/1i581isP

路径跟随和引导

  1 using UnityEngine;
  2 using System.Collections;
  3 
  4 /// <summary>
  5 /// 跟随脚本
  6 /// </summary>
  7 public class VehicleFollowing : MonoBehaviour 
  8 {
  9     /// <summary>
 10     /// 路径
 11     /// </summary>
 12     public Path path;
 13     /// <summary>
 14     /// 速度
 15     /// </summary>
 16     public float speed = 20.0f;
 17     /// <summary>
 18     /// 质量
 19     /// </summary>
 20     public float mass = 5.0f;
 21     /// <summary>
 22     /// 是否循环
 23     /// </summary>
 24     public bool isLooping = true;
 25 
 26     /// <summary>
 27     /// 当前速度
 28     /// </summary>
 29     private float curSpeed;
 30 
 31     /// <summary>
 32     /// 当前路径索引
 33     /// </summary>
 34     private int curPathIndex;
 35     /// <summary>
 36     /// 路径长度
 37     /// </summary>
 38     private float pathLength;
 39     /// <summary>
 40     /// 目标位置
 41     /// </summary>
 42     private Vector3 targetPoint;
 43 
 44     Vector3 velocity;
 45 
 46     void Start () 
 47     {
 48         pathLength = path.Length;
 49         curPathIndex = 0;
 50 
 51         velocity = transform.forward;
 52     }
 53     
 54     // Update is called once per frame
 55     void Update () 
 56     {
 57         
 58         curSpeed = speed * Time.deltaTime;
 59 
 60         //根据当前路径点索引获取路径的位置
 61         targetPoint = path.GetPoint(curPathIndex);
 62 
 63         //如果自身位置和目标位置的距离小于路径点的半径,则表示到达位置
 64         if(Vector3.Distance(transform.position, targetPoint) < path.Radius)
 65         {
 66             //如果不是最后一个路径点
 67             if (curPathIndex < pathLength - 1)
 68                 curPathIndex ++;
 69             //如果是循环模式,重置下一个路标位置为0
 70             else if (isLooping)
 71                 curPathIndex = 0;
 72             //停止
 73             else
 74                 return;
 75         }
 76 
 77         if (curPathIndex >= pathLength )
 78             return;
 79 
 80         if(curPathIndex >= pathLength - 1 && !isLooping)
 81             velocity += Steer(targetPoint, true);
 82         else
 83             velocity += Steer(targetPoint);
 84 
 85         //应用速度
 86         transform.position += velocity;
 87         //应用旋转
 88         transform.rotation = Quaternion.LookRotation(velocity);
 89     }
 90 
 91     public Vector3 Steer(Vector3 target, bool bFinalPoint = false)
 92     {
 93         //计算自身朝向
 94         Vector3 desiredVelocity = (target - transform.position);
 95         //获取距离长度
 96         float dist = desiredVelocity.magnitude;
 97 
 98         //归一化速度
 99         desiredVelocity.Normalize();
100 
101         if (bFinalPoint && dist < 10.0f)
102             desiredVelocity *= (curSpeed * (dist / 10.0f));
103         else 
104             desiredVelocity *= curSpeed;
105         
106         Vector3 steeringForce = desiredVelocity - velocity; 
107         Vector3 acceleration = steeringForce / mass;
108 
109         return acceleration;
110     }
111 }
VehicleFollowing
 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class Path: MonoBehaviour
 5 {
 6     /// <summary>
 7     /// 路径点半径
 8     /// </summary>
 9     public float Radius = 2.0f;
10     /// <summary>
11     /// 路径点
12     /// </summary>
13     public Vector3[] pointA;
14 
15     /// <summary>
16     /// 路径长度
17     /// </summary>
18     public float Length
19     {
20         get
21         {
22             return pointA.Length;
23         }
24     }
25 
26     public Vector3 GetPoint(int index)
27     {
28         return pointA[index];
29     }
30 
31     /// <summary>
32     /// Show Debug Grids and obstacles inside the editor
33     /// </summary>
34     void OnDrawGizmos()
35     {
36         for (int i = 0; i < pointA.Length; i++)
37         {
38             if (i + 1 < pointA.Length)
39             {
40                 Debug.DrawLine(pointA[i], pointA[i + 1], Color.red);
41             }
42         }
43     }
44 }
Path
 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class VehicleAvoidance : MonoBehaviour 
 5 {
 6     /// <summary>
 7     /// 移动速度
 8     /// </summary>
 9     public float speed = 20.0f;
10     /// <summary>
11     /// 质量
12     /// </summary>
13     public float mass = 5.0f;
14     /// <summary>
15     ///16     /// </summary>
17     public float force = 50.0f;
18     /// <summary>
19     /// 避开障碍的最小距离
20     /// </summary>
21     public float minimumDistToAvoid = 20.0f;
22 
23     /// <summary>
24     /// 当前速度
25     /// </summary>
26     private float curSpeed;
27     /// <summary>
28     /// 目标位置
29     /// </summary>
30     private Vector3 targetPoint;
31 
32     void Start () 
33     {
34         mass = 5.0f;        
35         targetPoint = Vector3.zero;
36     }
37 
38     void Update () 
39     {
40         RaycastHit hit;
41         var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
42 
43         if(Input.GetMouseButtonDown(0) && Physics.Raycast(ray, out hit, 100.0f))
44         {
45             targetPoint = hit.point;
46         }
47 
48         //计算自身朝向
49         Vector3 dir = (targetPoint - transform.position);
50         //归一化
51         dir.Normalize();
52 
53         AvoidObstacles(ref dir);
54 
55         //判断和目标的距离
56         if(Vector3.Distance(targetPoint, transform.position) < 3.0f)
57             return;
58 
59         curSpeed = speed * Time.deltaTime;
60 
61         var rot = Quaternion.LookRotation(dir);
62         transform.rotation = Quaternion.Slerp(transform.rotation, rot, 5.0f *  Time.deltaTime);
63 
64         transform.position += transform.forward * curSpeed;
65     }
66 
67     /// <summary>
68     /// 避开障碍
69     /// </summary>
70     public void AvoidObstacles(ref Vector3 dir)
71     {
72         RaycastHit hit;
73 
74         //只检测障碍物层
75         int layerMask = 1 << 8;
76 
77         if (Physics.Raycast(transform.position, transform.forward, out hit, minimumDistToAvoid, layerMask))
78         {
79             //获取碰撞点的法向量
80             Vector3 hitNormal = hit.normal;
81             //不改变y轴
82             hitNormal.y = 0.0f;
83 
84             //计算新的方向
85             dir = transform.forward + hitNormal * force;
86         }
87     }
88 
89     private void OnDrawGizmos() {
90         Debug.DrawLine(transform.position,transform.position + transform.forward * minimumDistToAvoid,Color.red);
91     }
92 }
VehicleAvoidance

 项目:https://pan.baidu.com/s/1pL0N6OV

原文地址:https://www.cnblogs.com/revoid/p/6519313.html