【Unity】入门学习笔记180601——人工智能(8)—AI角色的感知

1、AI角色感知的信息多种多样,通常会包含视觉和听觉信息,也可能包括脚步声、死去的同伴或敌人等。

其中,视线查询几乎是必不可少的,一般通过 Raycast 调用实现


在游戏中,AI角色可以通过两种方式来获得游戏信息——轮询和事件驱动

轮询是积极地观察世界获得信息

而事件驱动是通过坐等消息地方式来获得信息


2、在事件驱动的感知系统中,有一个中心检测系统,被称为“事件管理器”。

——记录每个AI角色所感兴趣的事件,并负责检查处理分发事件。


事件检测机制与事件管理器也常常分开实现,在采用基于触发器的事件检测方法中:

对事件感兴趣的角色通常称为“监听者(listener)”,必须事先向事件管理器注册,以确定被告知何种信息

告知的方法最简单的就是以 事件 为参数,调用某个函数


3、事件驱动感知系统

Trigger、Sensor和TriggerSystemManager

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

//所有触发器的基类,视觉触发器和听觉触发器是它的派生类
//包含所有触发器的共有信息和方法,如当前位置、作用半径、是否已完成使命而需要被移除等

public class Trigger : MonoBehaviour {

    //保存管理中心对象
    protected TriggerSystemManager manager;
    //触发器的位置
    protected Vector3 position;
    //触发器的半径
    public int radius;
    //当前触发器是否需要被移除
    public bool toBeRemoved;
    
    //这个方法检查作为参数的感知器s是否在触发器的作用范围内(或当前触发器是否能真正被感知器s感知到)
    //如果是,那么采取相应的行为。这个方法需要在派生类中实现
    public virtual void Try(Sensor s) { }

    //这个方法更新触发器内部状态,例如,声音触发器的剩余有效时间等;
    public virtual void Updateme() { }

    //这个方法检查感知器s是否在触发器的作用范围内(或当前触发器是否能真正被感知器s感觉到)
    //如果是,返回true,如果不是,返回false,它被Try()调用;需要在派生类中实现
    protected virtual bool isTouchingTrigger(Sensor sensor)
    {
        return false;
    }

    private void Awake()
    {
        //查找管理器并保存
        manager = FindObjectOfType<TriggerSystemManager>();
    }

    protected void Start()
    {
        //这时不需要被移除,置为false;
        toBeRemoved = false;
    }
  
	// Update is called once per frame
	void Update () {
		
	}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//所有感知器的基类,视觉感知其和听觉感知去是它的派生类
//包含对感知器类型的枚举定义和变量,还保存了事件管理器

public class Sensor : MonoBehaviour {

    protected TriggerSystemManager manager;
    public enum SensorType
    {
        sight,
        sound,
        health
    }

    public SensorType sensorType;

    private void Awake()
    {
        //查找管理器并保存
        manager = FindObjectOfType<TriggerSystemManager>();
    }

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}

    public  virtual void Notify(Trigger t)
    {

    }
}
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> triggersToRomove;

	// Use this for initialization
	void Start () {

        sensorsToRemove = new List<Sensor>();
        triggersToRomove = new List<Trigger>();

	}

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

    }

    private void TryTriggers()
    {
        //对于当前感知器列表中的每个感知器s
        foreach(Sensor s in currentSensors)
        {
            //如果s所对应的感知器还存在(没有因死亡而被销毁)
            if (s.gameObject != null)
            {
                //对于当前触发器列表中的每个触发器t
                foreach(Trigger t in currentTriggers)
                {
                    //检查s是否在t的作用范围内,并且做出相应的响应
                    t.Try(s);
                }
            }
            else
            {
                //将感知器s加入到需要移除的感知器列表中
                sensorsToRemove.Add(s);
            }
        }
        //对于需要移除的感知器列表中的每个感知器s,从当前感知器列表中移除s;
        foreach (Sensor s in sensorsToRemove)
            currentSensors.Remove(s);
    }
	
	// Update is called once per frame
	void Update () {

        //更新所有触发器内部状态
        UpdateTriggers();
        //迭代所有感知器和触发器,做出相应的行为;
        TryTriggers();
	}

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

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

4、视觉感知、听觉感知、触觉感知、记忆感知及其他类型的感知



猜你喜欢

转载自blog.csdn.net/Dylan_Day/article/details/80542300