游戏中AI的感知用的最多的是看到或者听到,也就是:
1.视觉感知
2.听觉感知
视觉感知:
视觉感知一般会有一个视野范围,这个范围与角色的朝向有关,只有在视觉范围内角色才有可能感知得到,这个范围与一个扇形接近,可以直接用半径和角度来控制。
潜在目标除了需要在视视觉范围内之外,探索者的视线还不能被其他障碍物遮挡,这里可以用射线来检测——发出一条从探索者到潜在目标的射线,如果目标是这条射线撞到的第一个单位,则该单位可以被看到,否则被忽略。
1 using System.Collections.Generic;
2 using UnityEngine;
3
4 public class AIViewPerception : MonoBehaviour
5 {
6 //视野半径
7 public float radius=10f;
8 //视野的角度范围
9 public float angel=120f;
10
11 //侦察的结果
12 public List<GameObject> PerceptionResult { get; private set; }
13
14 /// <summary>
15 /// 进行一次侦察
16 /// </summary>
17 /// <param name="explorer">探索者</param>
18 /// <param name="targets">潜在目标集</param>
19 public void Check(GameObject explorer,List<GameObject> targets)
20 {
21 PerceptionResult.Clear();
22
23 foreach(var item in targets)
24 {
25 //距离判断,这里用平方减少系统开根号的计算量
26 Vector3 offset = item.transform.position - explorer.transform.position;
27 if (offset.sqrMagnitude > radius*radius)
28 continue;
29
30 //角度判断,是否在视线范围内
31 float angel = Vector3.Angle(explorer.transform.forward, offset.normalized);
32 if (angel > this.angel * 1.0f / 2)
33 continue;
34
35 //射线判断,是否被其它目标或障碍物阻挡
36 Ray ray = new Ray(explorer.transform.position, offset);
37 RaycastHit info;
38 if (Physics.Raycast(ray,out info,radius))
39 {
40 if (info.collider.gameObject == item)
41 {
42 PerceptionResult.Add(item);
43 }
44 }
45 }
46 }
47
48 void Start()
49 {
50 //测试
51 PerceptionResult = new List<GameObject>();
52 var targets =new List<GameObject>(GameObject.FindGameObjectsWithTag("Target"));
53 Check(gameObject, targets);
54 foreach(var result in PerceptionResult)
55 {
56 Debug.Log(result.name);
57 }
58 }
听觉感知:
听觉感知不像视觉感知那样跟朝向有关,也没有一个角度范围,但听觉感知一般与声源的距离有关;距离越远声音越小,在距离相对较远的地方由于接收到的音量逐渐变小,更好的处理方式是根据距离的远近有感知丢失的可能性。
这里采用两个听力半径作为区分,一个是安全听力半径,一个是最大听力半径,在安全听力半径内一定能感知到声源,但超过安全半径后,直到最大听力范围,感知到声源的概率呈现线性降低,直到最大听力范围处为0。
1 using System.Collections.Generic;
2 using UnityEngine;
3
4 public class AIListenPerception : MonoBehaviour
5 {
6 //最大听力半径
7 public float maxRadius = 10f;
8 //安全听力半径
9 public float safeRadius = 5f;
10
11 //侦听结果
12 public Dictionary<AudioSource,float> PerceptionResult { get; private set; }
13
14 /// <summary>
15 /// 进行一次侦听
16 /// </summary>
17 /// <param name="explorer">探索者</param>
18 /// <param name="targets">声源目标集</param>
19 public void Check(GameObject explorer, List<AudioSource> targets)
20 {
21 PerceptionResult.Clear();
22
23 foreach(var item in targets)
24 {
25 //最大听力范围判断
26 Vector3 offset = item.transform.position - explorer.transform.position;
27 if (offset.sqrMagnitude > maxRadius * maxRadius)
28 continue;
29
30 //侦听丢失的概率判断:计算出一个声源距离比例权重,距离越远,权重越大,侦听丢失的概率越大
31 float distance = offset.magnitude;
32 float weight = (distance - safeRadius) * 1.0f / (maxRadius - safeRadius);
33 if (Random.value < weight)
34 continue;
35
36 //计算真实的侦听到音量,与距离成反比
37 float volume = item.volume *(1- distance / maxRadius);
38 PerceptionResult.Add(item, volume);
39 }
40 }
41
42 private void Start()
43 {
44 //测试
45 PerceptionResult = new Dictionary<AudioSource, float>();
46 var targets = new List<GameObject>(GameObject.FindGameObjectsWithTag("Target"));
47 List<AudioSource> audioSources = new List<AudioSource>();
48 foreach(var item in targets)
49 {
50 audioSources.Add(item.GetComponent<AudioSource>());
51 }
52 Check(gameObject, audioSources);
53 foreach (var result in PerceptionResult)
54 {
55 Debug.Log("audioSource : " + result.Key.gameObject.name);
56 Debug.Log("volume : "+ result.Value);
57 }
58 }