【Unity】【C#】《U3d人工智能编程精粹》学习心得--------AI角色的感知方式-视觉感知实现解读

视觉感知:

sightSensor 与 sightTrigger 实现

视觉感知前提:

  • 需要判断是否有物体的视觉触发器处于其他物体的视觉感知器的范围内

感知视觉触发器的感知器-------sightSensor类

  1. 可视角度,
  2. 最远可视距离
  3. 绘制可视距离
  4. 绘制与视觉目标的连线

判断是否被视觉感知器触发的触发器--------sightTrigger类

  1. 判断感知器是否为视觉感知器
  2. 通过获取感知器上的信息与当前位置,计算出当前物体是否处于视觉感知器的范围内
  3. 更新触发器位置(触发器位置跟随着物体改变)

sightSensor类:

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

public class SightSensor : Sensor {
    //定义这个AI角色的视域范围
    public float fieldOfView = 45;
    //定义这个AI角色最远能看到的距离
    public float viewDistance = 100.0f;
    //private AIController controller;
    
	// Use this for initialization
	void Start () {
        //controller = GetComponent<AIController>();
        //设置感知器类型
        sensorType = SensorType.sight;
        //向管理器注册
        manager.RegisterSensor(this);
	}
	
	// Update is called once per frame
	void Update () {
		
	}

    public override void Notify(Trigger trigger)
    {
        //当感知器能够真正感觉到某个触发器的信息时被调用产生相应的行为决策
        print("i see a " + this.gameObject.name + "!");
        //画出与触发目标的连接线
        Debug.DrawLine(transform.position, trigger.transform.position, Color.red);
        //controller.MoveToTarget(trigger.transform.position);
    }

    private void OnDrawGizmos()
    {
        Vector3 frontRayPoint = transform.position + (transform.forward * viewDistance);
        //把45度转换成 Π/4
        float fieldOfViewinRadians = fieldOfView * 3.14f / 180.0f;

        Vector3 leftRayPoint = transform.TransformPoint(new Vector3(viewDistance * Mathf.Sin(fieldOfViewinRadians), 0, viewDistance * Mathf.Cos(fieldOfViewinRadians)));

        Vector3 rightRayPoint = transform.TransformPoint(new Vector3(-viewDistance * Mathf.Sin(fieldOfViewinRadians), 0, viewDistance * Mathf.Cos(fieldOfViewinRadians)));

        Debug.DrawLine(transform.position + new Vector3(0, 1, 0), frontRayPoint+ new Vector3(0, 1, 0), Color.green);

        Debug.DrawLine(transform.position + new Vector3(0, 1, 0), leftRayPoint + new Vector3(0, 1, 0), Color.green);

        Debug.DrawLine(transform.position + new Vector3(0, 1, 0), rightRayPoint + new Vector3(0, 1, 0), Color.green);

    }
}

sightTrigger类:

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

public class SightTrigger : Trigger {
    public override void Try(Sensor sensor)
    {
        base.Try(sensor);
    }

    //判断感知器是否能感知到这个触发器
    public override bool isTouchingTrigger(Sensor sensor)
    {
        GameObject g = sensor.gameObject;
        //如果这个感知器能够感知视觉信息
        if (sensor.sensorType == Sensor.SensorType.sight)
        {
            RaycastHit hit;
            Vector3 rayDirection = transform.position - g.transform.position;
            rayDirection.y = 0;
            //判断感知体的前方向于物体所在的方向的夹角,是否在实现的范围内
            if((Vector3.Angle(rayDirection,g.transform.forward))<(sensor as SightSensor).fieldOfView)
            {
                //在实现距离内是否存在其他障碍物遮挡,如果没有障碍物,返回true;
                if(Physics.Raycast(g.transform.position+new Vector3(0,1,0),rayDirection,out hit,(sensor as SightSensor).viewDistance))
                {
                    if (hit.collider.gameObject == this.gameObject)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    //更新触发器内部消息,由于带有视觉触发器的AI角色可能是运动的,因此需要不停地更新这个触发器的位置
    public override void Updateme()
    {
        position = transform.position;
    }

    // Use this for initialization
    void Start () {
        base.Start();
        manager.RegisterTrigger(this);
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

 

绘制可视范围(解读):

涉及公式:

a为夹角度数 

b为a的度数近似值     

度数近似值 = 度数 * 3.14 / 180b= a* 3.14 / 180

red为红色线长度,redx为红色虚线长度

sin(b)=red/redx

由图右上文字可知,

x=redx,y=redx

求出绿色坐标点的坐标

通过TransformPoint()将该本地坐标转换成世界坐标。

实现效果:

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

猜你喜欢

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