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 }
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+"\nDistance:"+ 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 }
视频: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 }
极简感应器:
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 }
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 }
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 }
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 }
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 }
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 }
项目: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 }
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 }
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 }
项目:https://pan.baidu.com/s/1pL0N6OV