Unity C# 操控行为类

备注:因为这篇博客是根据《游戏人工智能编程案例精粹》写的,而这本书是由c++写的。所以在这篇文章里只是有ai的逻辑,但并没有很好地用在Unity身上。后来我发现了一本书,也是根据《游戏人工智能编程案例精粹》这本书写的,而且专门是为了Unity写的。因此下面的代码理解一下就好,实际应用的话可以参考那本书的第一章。那本书就是《Unity 5.x Game AI Programming Cookbook(PACKT,2016)》  网上有pdf版下载。—— 2017/06/16

在游戏中,操控一个对象的行为是很必要的操作。今天来将之前学的《游戏人工智能编程案例精粹》改成C#版供大家参考参考。

我就直接放代码和项目了,想了解为甚么这么写可以直接看这本书或者看代码注释然后自己画图理解,最好看书吧~书就是最好的学习笔记。

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 public enum MoverState
  6 {
  7     Null,
  8     Seek,
  9     Flee,
 10     Arrive,
 11     Pursuit,
 12     Evade,
 13     Wander,
 14     Interpose,
 15     Hiding,
 16     OffsetPursuit
 17 }
 18 
 19 public class MovingEntity : MonoBehaviour
 20 {
 21     /// <summary>
 22     /// 当前智能体的速度
 23     /// </summary>
 24     [HideInInspector]
 25     public Vector3 m_vVelocity;
 26 
 27     /// <summary>
 28     /// 当前智能体的位置信息
 29     /// </summary>
 30     [HideInInspector]
 31     public Transform selfTransform;
 32 
 33     /// <summary>
 34     /// 当前智能体所达到的最大速率
 35     /// </summary>
 36     public float m_fMaxSpeed = 1f;
 37 
 38     /// <summary>
 39     /// 徘徊圈半径
 40     /// </summary>
 41     public float m_fWanderRadius = 10f;
 42     /// <summary>
 43     /// 徘徊圈凸到智能体前面的距离
 44     /// </summary>
 45     //public float m_fWanderDistance = 0f;  //可不用
 46     /// <summary>
 47     /// 徘徊圈上的目标位置跳动阈值
 48     /// </summary>
 49     public float m_fWanderJitter = 50f;
 50     /// <summary>
 51     /// 徘徊目标
 52     /// </summary>
 53     public Vector3 m_vWanderTarger = Vector3.zero;
 54     /// <summary>
 55     /// 徘徊目标时间间隔
 56     /// </summary>
 57     private float wanderTime = 1.5f;
 58     /// <summary>
 59     /// 徘徊计时器
 60     /// </summary>
 61     private float timer;
 62 
 63     /// <summary>
 64     /// 当前智能体的行为状态
 65     /// </summary>
 66     public MoverState state;
 67 
 68     /// <summary>
 69     /// 当前与智能体互动的目标
 70     /// </summary>
 71     public MovingEntity target;
 72     public MovingEntity targetB;
 73     public MovingEntity leader;
 74     public Vector3 offsetPos;
 75 
 76     /// <summary>
 77     /// 当前智能体的操控行为类
 78     /// </summary>
 79     SteeringBehavior m_pSteering;
 80     
 81     /// <summary>
 82     /// 用来测试得到智能体的隐藏点
 83     /// </summary>
 84     Vector3 posTarget;
 85 
 86     private void Awake()
 87     {
 88         m_pSteering = new SteeringBehavior(this);
 89         selfTransform = this.transform;
 90         timer = wanderTime;
 91         posTarget = selfTransform.position;
 92     }
 93 
 94     private void Update()
 95     {
 96         switch (state)
 97         {
 98             case MoverState.Null:
 99                 break;
100             case MoverState.Seek:
101                 Vector3 seekVel = m_pSteering.Seek(target.selfTransform.position);
102                 selfTransform.Translate(seekVel * Time.deltaTime);
103                 // 图形调试:画出智能体移动的方向
104                 Debug.DrawRay(selfTransform.position, seekVel * 10f, Color.green);
105                 break;
106             case MoverState.Flee:
107                 Vector3 fleeVel = m_pSteering.Flee(target.selfTransform.position);
108                 selfTransform.Translate(fleeVel * Time.deltaTime);
109                 // 图形调试:画出智能体移动的方向
110                 Debug.DrawRay(selfTransform.position, fleeVel * 10f, Color.green);
111                 break;
112             case MoverState.Arrive:
113                 Vector3 arriveVel = m_pSteering.Arrive(target.selfTransform.position, 1f, 1f);
114                 selfTransform.Translate(arriveVel * Time.deltaTime);
115                 // 图形调试:画出智能体移动的方向
116                 Debug.DrawRay(selfTransform.position, arriveVel * 10f, Color.green);
117                 break;
118             case MoverState.Pursuit:
119                 Vector3 pursuiteVel = m_pSteering.Pursuit(target);
120                 selfTransform.Translate(pursuiteVel * Time.deltaTime);
121                 // 图形调试:画出智能体移动的方向
122                 Debug.DrawRay(selfTransform.position, pursuiteVel * 10f, Color.green);
123                 break;
124             case MoverState.Evade:
125                 Vector3 evadeVel = m_pSteering.Evade(target);
126                 selfTransform.Translate(evadeVel * Time.deltaTime);
127                 // 图形调试:画出智能体移动的方向
128                 Debug.DrawRay(selfTransform.position, evadeVel * 10f, Color.green);
129                 break;
130             case MoverState.Wander:
131                 timer += Time.deltaTime;
132                 if (timer >= wanderTime)
133                 {
134                     m_pSteering.Wander();
135                     timer = 0f;
136                 }
137                 m_vWanderTarger.y = selfTransform.position.y;
138                 Vector3 wanderVel = m_pSteering.Seek(m_vWanderTarger);
139                 selfTransform.Translate(wanderVel * Time.deltaTime);
140                 // 图形调试:画出智能体移动的方向
141                 Debug.DrawRay(selfTransform.position, wanderVel * 10f, Color.green);
142                 // 图形调试:画出智能体徘徊范围
143                 Debug.DrawLine(selfTransform.position, m_vWanderTarger, Color.red, 1000f);
144                 break;
145             case MoverState.Interpose:
146                 Vector3 interposeVel = m_pSteering.Interpose(target, targetB);
147                 selfTransform.Translate(interposeVel * Time.deltaTime);
148                 // 图形调试:画出智能体移动的方向
149                 Debug.DrawRay(selfTransform.position, interposeVel * 10f, Color.green);
150                 break;
151             case MoverState.Hiding:
152                 Vector3 hidingPos = m_pSteering.GetHidingPosition(target.selfTransform.position, 3f, posTarget);
153                 Vector3 arriveVel1 = m_pSteering.Arrive(hidingPos, 1f, 1f);
154                 selfTransform.Translate(arriveVel1 * Time.deltaTime);
155                 // 图形调试:画出智能体移动的方向
156                 Debug.DrawRay(selfTransform.position, arriveVel1 * 10f, Color.green);
157                 break;
158             case MoverState.OffsetPursuit:
159                 Vector3 offsetPursuitVel = m_pSteering.OffsetPursuit(leader,offsetPos);
160                 selfTransform.Translate(offsetPursuitVel * Time.deltaTime);
161                 // 图形调试:画出智能体移动的方向
162                 Debug.DrawRay(selfTransform.position, offsetPursuitVel * 10f, Color.green);
163                 break;
164         }
165     }
166 
167     private void OnDrawGizmos()
168     {
169         //Gizmos.DrawLine(Vector3.zero,target.position);
170         //Gizmos.DrawWireSphere(Vector3.zero, m_fWanderRadius);
171     }
172 }
MovingEntity
  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 public class SteeringBehavior
  6 {
  7     /// <summary>
  8     /// 操控行为类的操控对象
  9     /// </summary>
 10     private MovingEntity mover;
 11 
 12     /// <summary>
 13     /// SteeringBehavior构造函数,初始化操控行为类
 14     /// </summary>
 15     /// <param name="mover"></param>
 16     public SteeringBehavior(MovingEntity mover)
 17     {
 18         this.mover = mover;
 19     }
 20 
 21     /// <summary>
 22     /// 返回靠近目标位置的速度
 23     /// </summary>
 24     /// <param name="targetPos"></param>
 25     /// <returns></returns>
 26     public Vector3 Seek(Vector3 targetPos)
 27     {
 28         // 对靠近目标位置的理想速度
 29         Vector3 desiredVel = mover.m_fMaxSpeed * Vector3.Normalize(targetPos - mover.selfTransform.position);
 30         // 理想速度-当前速度=结果速度,这样行动方向是收受到当前的速度影响,比较合理
 31         return desiredVel - mover.m_vVelocity;
 32     }
 33 
 34     /// <summary>
 35     /// 返回远离目标位置的速度
 36     /// </summary>
 37     /// <param name="targetPos"></param>
 38     /// <returns></returns>
 39     public Vector3 Flee(Vector3 targetPos)
 40     {
 41         // 对远离目标位置的理想速度
 42         Vector3 desiredVel = mover.m_fMaxSpeed * Vector3.Normalize(mover.selfTransform.position - targetPos);
 43         // 理想速度-当前速度=结果速度,这样行动方向是收受到当前的速度影响,比较合理
 44         return desiredVel - mover.m_vVelocity;
 45     }
 46 
 47     /// <summary>
 48     /// 根据智能体与目标位置的距离,返回到达目标距离的速度
 49     /// 若到达了则速速为Vector3.zero
 50     /// </summary>
 51     /// <param name="targetPos">目标位置</param>
 52     /// <param name="stopDistance">据目标多少米停止移动</param>
 53     /// <param name="tweaker">用于调整即将到达目标位置时速率大小,tweaker越大则即将到达时运动速率越小,但有最大速度限制</param>
 54     /// <returns></returns>
 55     public Vector3 Arrive(Vector3 targetPos, float stopDistance, float tweaker)
 56     {
 57         // 智能体到目标位置的预期速度
 58         Vector3 toTarget = targetPos - mover.selfTransform.position;
 59 
 60         // 智能体与目标位置的距离
 61         float dist = toTarget.magnitude;
 62 
 63         // 判读是否到达停止距离
 64         if (dist > stopDistance)
 65         {
 66             // 与目标点距离越近则运动速率越小,tweaker越大则运动速率越小
 67             float speed = dist / tweaker;
 68             // 确保不超过最大速率
 69             speed = Mathf.Min(speed, mover.m_fMaxSpeed);
 70             // 类似Seek
 71             Vector3 desiredVel = toTarget / dist * speed;
 72             return desiredVel - mover.m_vVelocity;
 73         }
 74 
 75         return Vector3.zero;
 76     }
 77 
 78     /// <summary>
 79     /// 返回智能体追逐目标的速度
 80     /// </summary>
 81     /// <param name="evader">被智能体追逐的逃避者</param>
 82     /// <returns></returns>
 83     public Vector3 Pursuit(MovingEntity evader)
 84     {
 85         // 智能体到逃避者的预期速度
 86         Vector3 toEvader = evader.selfTransform.position - mover.selfTransform.position;
 87 
 88         // 智能体与逃避者前方向的点积运算
 89         float relativeHeading = Vector3.Dot(evader.selfTransform.forward,mover.selfTransform.forward);
 90 
 91         //这里视角判定逃避者是否在智能体前面视角范围36度左右的
 92         if (relativeHeading < -0.95 //acos(0.95) = 18degs 
 93            && Vector3.Dot(toEvader, mover.selfTransform.forward) > 0) //智能体朝向与预期速度之间的夹角  大于0为锐角  所以逃避者肯定不会在智能体朝向的后面
 94         {
 95             //确定逃避者在智能体前面36°视角范围,直接Seek
 96             return Seek(evader.selfTransform.position);
 97         }
 98 
 99         //预估相遇时间  相遇时间是和两者距离成正比,和追逐者速率和逃避者速率成反比
100         float LookAheadTime = toEvader.magnitude / (mover.m_fMaxSpeed + evader.m_fMaxSpeed);
101 
102         //靠近相遇地点(逃避者的被预测位置)
103         return Seek(evader.selfTransform.position + evader.m_vVelocity * LookAheadTime);
104     }
105 
106     /// <summary>
107     /// 返回智能体逃避追逐者的速度
108     /// </summary>
109     /// <param name="pursuer">追逐智能体的追逐者</param>
110     /// <returns></returns>
111     public Vector3 Evade(MovingEntity pursuer)
112     {
113         /*不需要检查是否面向*/
114 
115         Vector3 toPursuer = pursuer.selfTransform.position - mover.selfTransform.position;
116 
117         //预估相遇时间
118         float LookAheadTime = toPursuer.magnitude / (mover.m_fMaxSpeed + pursuer.m_fMaxSpeed);
119         //逃离相遇地点
120         return Flee(pursuer.selfTransform.position + pursuer.m_vVelocity * LookAheadTime);
121     }
122 
123     /// <summary>
124     /// 返回在徘徊圈位置的速度
125     /// </summary>
126     /// <returns></returns>
127     public void Wander()
128     {
129         // 给目标点增加随机位移
130         mover.m_vWanderTarger += Random.insideUnitSphere * mover.m_fWanderJitter;
131 
132         // 目标点回归到圆上
133         mover.m_vWanderTarger.Normalize();
134         mover.m_vWanderTarger *= mover.m_fWanderRadius;
135     }
136 
137     /// <summary>
138     /// 返回插入两个智能体之间的到达速度
139     /// </summary>
140     /// <param name="agentA"></param>
141     /// <param name="agentB"></param>
142     /// <returns></returns>
143     public Vector3 Interpose(MovingEntity agentA, MovingEntity agentB)
144     {
145         // 插入的两个智能体之间的位置的中点
146         Vector3 MidPoint = (agentA.selfTransform.position + agentB.selfTransform.position) / 2.0f;
147 
148         // 计算当前智能体到达MidPoint的时间
149         float TimeToReachMinPoint = Vector3.Distance(mover.selfTransform.position, MidPoint) / mover.m_fMaxSpeed;
150 
151         // 假设AB两个智能体在时间T继续前行
152         Vector3 APos = agentA.selfTransform.position + agentA.m_vVelocity * TimeToReachMinPoint;
153         Vector3 BPos = agentB.selfTransform.position + agentB.m_vVelocity * TimeToReachMinPoint;
154 
155         // 重新计算中点
156         MidPoint = (APos + BPos) / 2.0f;
157 
158         return Arrive(MidPoint, 0f, 1f);
159 
160     }
161 
162     /// <summary>
163     /// 得到目标位置到障碍物之间的隐藏点
164     /// </summary>
165     /// <param name="posOb"></param>
166     /// <param name="radiusOb"></param>
167     /// <param name="posTarget"></param>
168     /// <returns></returns>
169     public Vector3 GetHidingPosition(Vector3 posOb, float radiusOb, Vector3 posTarget)
170     {
171         // 计算从目标到物体的朝向
172         Vector3 toOb = Vector3.Normalize(posOb - posTarget);
173 
174         // 确定大小并加到障碍物的位置,得到隐藏点
175         return (toOb * radiusOb) + posOb;
176     }
177 
178     /// <summary>
179     /// 偏移追逐
180     /// </summary>
181     /// <param name="leader">追逐的领头者</param>
182     /// <param name="offset">与领头者之间的偏移(间隔)</param>
183     /// <returns></returns>
184     public Vector3 OffsetPursuit(MovingEntity leader, Vector3 offset)
185     {
186         //在世界空间中计算偏移的位置
187         Vector3 worldOffsetPos = leader.selfTransform.TransformPoint(offset);
188         Vector3 toOffset = worldOffsetPos - mover.selfTransform.position;
189 
190         //预期时间 与领头者和追逐者的距离成正比,与速度之和成反比
191         float lookAheadTime = toOffset.magnitude / (mover.m_fMaxSpeed + leader.m_vVelocity.magnitude);
192 
193         //偏移的预测位置
194         return Arrive(worldOffsetPos + leader.m_vVelocity * lookAheadTime, 0f, 1f);
195     }
196 }
SteeringBehavior

测试项目地址:https://git.oschina.net/TMoon-Net/SteeringBehavior

 

posted on 2017-03-26 22:20  爱裸奔的小亮亮  阅读(346)  评论(0编辑  收藏  举报

导航