【Unity】【C#】《U3d人工智能编程精粹》学习心得--------AI角色的感知方式(Trigger,Sensor,TriggerSystemManager)基类实现解读

游戏中角色对世界信息获取的方式:

  • 轮询         (主动查找是否发生事件)

       当多个角色需要进行轮询查找的时候,可以建立轮询中心来匹配信息,来节省多个角色重复轮询的消耗。

  • 事件驱动  (等待事件发生触发)

      Unity中的触发器类似于事件驱动方式

实现游戏感知(物体感知)前提:

  • 需要拥有能被人感受的 触发器 ----Trigger类
  1. 保存触发器到事件管理器中
  2. 触发器位置
  3. 触发器触发范围
  4. 持续触发的触发器是否触发完毕(是否应该被移除)
  5. 检测是否被对应的感受器触发
  6. 触发与否需要执行的行为
  7. 更新持续触发的信息
  • 需要拥有感知其他物体的 感知体(感知器)----Sensor类
  1. 保存感受器到事件管理器中
  2. 感受器类型
  3. 感受器向触发器发送消息/内容(例:这个攻击范围代表的攻击是什么效果的)
  • 一般在游戏中具有多种感知方式,我们可以通过使用事件管理器来管理多种感知行为。 -----TriggerSystemManager类
  1. 所有物体上感知器的存储列表
  2. 所有物体上触发器的存储列表
  3. 需要被移除的感知器列表(例:释放出去的火焰魔法效果消失)
  4. 需要被移除的触发器列表(例:某目标身上的灼伤效果消失)
  5. 注册/添加触发器行为
  6. 注册/添加感受器行为
  7. 更新所有的触发器和感受器(例:将失效的效果添加进删除列表中进行删除)
  8. 继续执行剩下的触发器和感受器的行为(例:由更新可知,剩下的效果还没消失,继续执行效果)

Trigger类:


public class Trigger : MonoBehaviour {
    //触发器所处位置
    public Vector3 position;
    //触发器范围(圆形触发器)半径
    public int radius;
    //添加到管理器中
    public TriggerSystemManager manager;
    //触发器是否去除
    public bool toBeRemoved;
    //判断触发器是否被对应感受器触发
    public virtual bool isTouchingTrigger(Sensor sensor) { return false; }
    //通过上面检测是否为对应感受器触发,是,执行行为,否,返回
    public virtual void Try(Sensor sensor)
    {
        if (isTouchingTrigger(sensor))
            sensor.Notify(this);
    }
    //更新触发器内部消息,例如触发器位置,时限等
    public virtual void Updateme() { }
    private void Awake()
    {
        //初始化触发器状态
        toBeRemoved = false;
    }
    protected void Start () {
        //存入管理中
        manager = FindObjectOfType<TriggerSystemManager>();
	}
}

Sensor类:

public class Sensor : MonoBehaviour {
    protected TriggerSystemManager manager;
    public enum SensorType
    {
        sight,
        sound,
        health
    }
    public SensorType sensorType;
    private void Awake()
    {
        manager = FindObjectOfType<TriggerSystemManager>();
    }
    //负责通知消息
    public virtual void Notify(Trigger trigger) { }
}

TriggerSystemManager类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TriggerSystemManager : MonoBehaviour {
    //当前感知器列表
    List<Sensor> currentSensors = new List<Sensor>();
    //当前触发器列表
    List<Trigger> currentTriggers = new List<Trigger>();
    //记录当前时刻需要被移除的感知器,例如感知体死亡,需要移除感知器时
    List<Sensor> sensorsToRemove;
    //需要被移除的触发器,触发器已过期
    List<Trigger> triggersToRemove;

	// Use this for initialization
	void Start () {
        sensorsToRemove = new List<Sensor>();
        triggersToRemove = new List<Trigger>();
	}

    private void UpdateTriggers()
    {
        //对于当前触发器列表中的触每个触发器
        foreach(Trigger t in currentTriggers)
        {
            //如果t需要被移除
            if (t.toBeRemoved)
            {
                //将t加入需要移除的触发器列表中(这是由于不能再foreach中直接移除,否则会报错)
                triggersToRemove.Add(t);
            }
            else
            {
                t.Updateme();
            }
        }
        foreach (Trigger t in triggersToRemove)
            currentTriggers.Remove(t);
    }

    private void TryTriggers()
    {
        //对于当前感知器列表中的每个感知器s
        foreach(Sensor s  in currentSensors)
        {
            //如果s所对应的感知体还存在(没有因死亡而被销毁)
            if(s.gameObject!=null)
            {
                foreach(Trigger t in currentTriggers)
                {
                    //检查s是否在t的作用范围,并作出响应
                    t.Try(s);
                }
            }
            else
            {
                sensorsToRemove.Add(s);
            }
        }
        //删除需要删除的感知器
        foreach(Sensor s in sensorsToRemove)
        {
            currentSensors.Remove(s);
        }
    }
	
	// Update is called once per frame
	void Update () {
        //更新触发器内部状态
        UpdateTriggers();
        //迭代感知器和触发器,并做出行为
        TryTriggers();
	}

    //用于注册触发器
    public void RegisterTrigger(Trigger trigger)
    {
        print("registering trigger:" + trigger.name);
        //将参数触发器t加入到当前触发器列表中
        currentTriggers.Add(trigger);
    }

    //用于注册感知器
    public void RegisterSensor(Sensor sensor)
    {
        print("registering sensor:" + sensor.name);
        //将参数 感知器加入到当前感知器列表中
        currentSensors.Add(sensor);
    }
}

参考书籍:《unity3d人工智能编程精粹》 王洪源等著

猜你喜欢

转载自blog.csdn.net/Terrell21/article/details/82623864