Unity人工智能-----感知系统-----视觉实现(1)

概念

概念:感知系统:
在软件领域中:模拟人【或动物】的感觉的软件系统。
【代码 数据类型】
人的基本感觉:视觉、听觉、触觉、【嗅觉、味觉】
视觉、听觉:目前是对视觉听觉模拟!

智能感知系统架构:可以用于任何需要的系统中。

感应器:拥有XX能力
触发器:拥有被XX能力
例如:
视觉感应器:拥有视觉能力
视觉触发器:拥有被发现能力

感知系统架构图:

在这里插入图片描述

感知触发系统类图

在这里插入图片描述

抽象感应器(AbstractSensor)

using System;
using System.Collections.Generic;
using UnityEngine;
namespace AI.Perception
{
    /// <summary>
    /// 抽象感应器
    /// </summary>
    public abstract class AbstractSensor:MonoBehaviour
    {
        /// <summary>
        /// 是否移除,是否禁用
        /// </summary>
        public bool isRemove;

        /// <summary>
        /// 没有感知事件:F1>F2【没有行为发生 触发什么事件】
        /// </summary>
        public event Action OnNonPerception;
        /// <summary>
        /// 感知事件事件:F1>F2【行为发生 触发什么事件】
        /// </sumeptiomary>
        public event Action<List<AbstractTrigger>> OnPerception;

        /// <summary>
        /// 初始化
        /// </summary>
        private void Start()
        {
            Init();
            //把当前感应器放到 感应系统中
            SensorTriggerSystem.Instance.AddSensor(this);
        }

        /// <summary>
        /// 预留初始化方法
        /// </summary>
        abstract public void Init();

        /// <summary>
        /// 销毁方法
        /// </summary>
        private void OnDestroy()
        {
            isRemove = true;//把当前感应器从 感应系统中移除
        }

        /// <summary>
        /// 检测触发器:检查所有的触发器【触发 条件】
        /// </summary>
        public void OnTestTrigger(List<AbstractTrigger> listTriggers)
        {
            //找到启用的所有触发器  
            listTriggers = listTriggers.FindAll(t => t.enabled
            && t.gameObject!=this.gameObject
            && TestTrigger(t));
            //触发感知事件
            if (listTriggers.Count > 0)
            {
                if (OnPerception != null)
                    OnPerception(listTriggers);
            }
            else
            {
                if (OnNonPerception != null)
                    OnNonPerception();
            }
        }
        /// <summary>
        /// 检测触发器  是能够感知
        /// </summary>
        abstract protected bool TestTrigger(AbstractTrigger trigger);
    }
}

抽象触发器(AbstractTrigger)

using UnityEngine;
namespace AI.Perception
{
    /// <summary>
    /// 抽象触发器
    /// </summary>
    public abstract class AbstractTrigger:MonoBehaviour
    {
        /// <summary>
        /// 是否删除,是否禁用
        /// </summary>
        public bool isRemove;
        /// <summary>
        /// 触发器类型
        /// </summary>
        public TriggerType triggerType;

        /// <summary>
        /// 初始化
        /// </summary>
        private void Start()
        {
            Init();
            //把当前触发器  加入到感应触发系统中(中介)
            SensorTriggerSystem.Instance.AddTrigger(this);
        }

        /// <summary>
        /// 初始化方法
        /// </summary>
        abstract public void Init();

        /// <summary>
        /// 销毁方法:把当前触发器从 感应触发系统中移除
        /// </summary>
        public void OnDestroy()
        {
            isRemove = true;
        }
    }
}

触发器的类型(TriggerType)

namespace AI.Perception
{
    //触发器的类型
    public enum TriggerType
    {
        Sight,//视觉
        Sound,//听觉
    }
}

视觉感应器(SightSensor)

using UnityEngine;

namespace AI.Perception
{
    /// <summary>
    /// 视觉感应器
    /// </summary>
    public class SightSensor : AbstractSensor
    {
        //字段
        //视距 
        public float sightDistance;
        //视角 
        public float sightAngle;
        //启用角度检测 
        public bool enableAngle;
        //启用遮挡检测
        public bool enableRay;
        //视线发射点
        public Transform sendPos;

        public override void Init()
        {//给视线发射位置    如果未赋值初始化
            if (sendPos == null) sendPos = transform;
        }
        /// <summary>
        /// 检测触发器 是否应该触发   
        /// </summary>
        /// <param name="trigger">被检测到的物体身上触发器</param>
        /// <returns>距离 角度 遮挡 功能能否触发触发器</returns>
        protected override bool TestTrigger(AbstractTrigger trigger)
        {
            //如果当前触发器类型不是视觉触发器  则触发器不能被触发
            if (trigger.triggerType != TriggerType.Sight) return false;
            var tempTrigger = trigger as SightTrigger;
            //计算物体与视觉发射点距离  如果超过视距  则返回false
            var dir = tempTrigger.recievePos.position - sendPos.position;
            var result = dir.magnitude < sightDistance;
            //启用角度检测 
            if (enableAngle)//视线发射点前方位置  是否在视角范围内
            {
                bool b1 = Vector3.Angle(sendPos.transform.forward, dir) < sightAngle / 2;
                result = result && b1;
            }
            //遮挡 1 射中物体 2 射中的是触发器
            RaycastHit hit;
            //启用遮挡检测
            if (enableRay)//视线发射点发射射线检测   到触发器之间有无其他物体遮挡
            {
                bool b1 = Physics.Raycast(sendPos.position, dir, out hit, sightDistance)
                    && hit.collider.gameObject == trigger.gameObject;
                result = result && b1;
            }
            return result;
        }
    }
}

视觉触发器(SightTrigger)

using UnityEngine;
namespace AI.Perception
{
    /// <summary>
    /// 视觉触发器
    /// </summary>
    public class SightTrigger : AbstractTrigger
    {
        //记录当前物体触发器的位置
        public Transform recievePos;
        //初始化
        public override void Init()
        {
            if(recievePos == null)
            {
                recievePos = transform;
                triggerType = TriggerType.Sight;
            }
        }
    }
}

感知触发系统(SensorTriggerSystem)

using System.Collections.Generic;

namespace AI.Perception
{
    /// <summary>
    /// 感知触发系统:感知系统  中介者
    /// </summary>
    public class SensorTriggerSystem
        :SingleCase<SensorTriggerSystem>//继承父类 单例模式
    {
        //单例模式  防止被外界随便new
        private SensorTriggerSystem() { }
        /// <summary>
        /// 检测时间间隔
        /// </summary>
        public float checkInterval = 0.2f;
        /// <summary>
        /// 感应器列表
        /// </summary>
        private List<AbstractSensor> listSensor = new List<AbstractSensor>();
        /// <summary>
        /// 触发器列表
        /// </summary>
        private List<AbstractTrigger> listTrigger = new List<AbstractTrigger>();

        /// <summary>
        /// 添加感应器
        /// </summary>
        public void AddSensor(AbstractSensor sensor)
        {
            listSensor.Add(sensor);
        }

        /// <summary>
        /// 添加触发器
        /// </summary>
        public void AddTrigger(AbstractTrigger trigger)
        {
            listTrigger.Add(trigger);
        }

        /// <summary>
        /// 检测触发条件:每个感应器 检查 对应所有触发器
        /// </summary>
        private void CheckTrigger()
        {
            for(int i = 0; i < listSensor.Count; i++) {
                if (listSensor[i].enabled)
                {//当前在列表中的所有触发器进行检测能否被感应器感应到
                    listSensor[i].OnTestTrigger(listTrigger);
                }
            }
        }

        /// <summary>
        /// 更新系统
        /// </summary>
        private void UpdateSystem()
        {
            listSensor.RemoveAll(s => s.isRemove);
            listTrigger.RemoveAll(t => t.isRemove);
        }
        private void OnCheck()
        {
            UpdateSystem();
            CheckTrigger();
        }
        private void OnEnable()//时刻刷新系统
        {
            InvokeRepeating("OnCheck", 0, checkInterval);
        }

        private void OnDisable()
        {
            CancelInvoke("OnCheck");
        }
    }
}

测试用例

  • 创建一个cube 放视觉感应器
  • 再创建sphere做物体放视觉触发器
  • 设置属性值: cube自己作为接收点sphere自己作为发出点视觉距离 视觉角度
  • 添加测试代码挂在cube上
  • 如果看见了,就输出对方的名称
  • 如果看不见,就打出看不见
using System.Collections.Generic;
using UnityEngine;
using AI.Perception;
/// <summary>
/// 测试代码
/// </summary>
public class TestSight : MonoBehaviour
{
    void Start()
    {
        //1 注册视觉感应器的事件
        GetComponent<SightSensor>().OnPerception 
            += TestSight_OnPerceptions;
        GetComponent<SightSensor>().OnNonPerception 
            += OnNonPerception;
    }
    //2 事件处理程序 F1事件》F2方法
    void TestSight_OnPerceptions(List<AbstractTrigger> list)
    {
        list.ForEach(t => print("看见了:" + t.name));
    }
    void OnNonPerception()
    {
        print("看不到任何东西了");
    }
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值