¿Cómo utilizar la cámara Unity para determinar la línea de visión del agente de IA?
Mi idea es vincular una cámara a cada agente inteligente y sensor de visión. La cámara está configurada con un cierto campo de visión y un plano lejano. Unity tiene dos métodos muy convenientes para probar la cámara. El primero devuelve 6 secciones para definir el tronco de la cámara y el segundo indica si un objeto delimitador está dentro o fuera del tronco de la cámara.
Ahora podemos saber si un objeto de juego está dentro de nuestra vista, pero no si podemos verlo, ya que puede estar ocluido por otro objeto más cercano a la posición de la cámara. Entonces uso linecasts para saber si podemos ver este objeto. ¿Pero qué posición debo convertir? La posición central del objeto es una buena elección, pero no necesariamente lo suficientemente precisa. Utilizo un borde de cuadrícula de objetos y reviso todas las posiciones del borde, deteniéndome cuando la transmisión de línea no pasa por nada, entonces sé si se puede ver el objeto.
La forma perfecta sería hacer un linecast entre cada vértice de la malla, pero llevaría demasiado tiempo.
Obtener todos los GameObjects
Ahora que tenemos una función que nos dice si un objeto específico está dentro de la línea de visión de la IA, simplemente pruebo cada objeto, dada la posición de la cámara como el origen. La verificación del rango de superposición se realiza utilizando la distancia desde el plano lejano de la cámara como radio. Llamo a la función SeeGameObject anterior para cada objeto y guardo los objetos a la vista en una matriz.
public bool SeeGameObject(GameObject go)
{
// si el objeto tiene un renderizador y es visible para cualquier cámara y está en esta cámara frustum
if(go.renderer != null && go.renderer.isVisible && GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(_camera), go.renderer.bounds))
{
RaycastHit hitInfo;
// por defecto usamos los límites aproximados del renderizador
Vector3 center = go.renderer.bounds.center;
Vector3 extends = go.renderer.bounds.extents;
float coefreduc = 0.8f;
Vector3[] gobounds; // puntos para verificar la transmisión de línea desde la cámara
MeshFilter meshfilter = go.GetComponent
if(meshfilter != null) // Casi todos los objetos interesantes del juego que se renderizan tienen una malla
{
centro = go.transform.position;
extensiones = meshfilter.mesh.bounds.extents;
extensiones.Scale(go.transform.lossyScale);
gobounds = new Vector3[33]{ // Podemos agregar más o eliminar algunos, aumenta la precisión sin demasiado tiempo ni costo de memoria
Vector3.zero,
go.transform.TransformDirection(nuevo Vector3(extents.x,extents.y,extents.z)*0.9f),
go.transform.TransformDirection(nuevo Vector3(extents.x,exten
ts.y,-extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.9f), p> p>
go.transform.TransformDirection(nuevo Vector3(extents.x,-extents.y,-extents.z)*0.9f),
go.transform.TransformDirection(nuevo Vector3 (- extensiones.x, extensiones.y, extensiones.z)*0.9f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,-extents.z)* 0.9f ),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,extents.z)*0.9f),
go.transform. TransformDirection( nuevo Vector3(-extents.x,-extents.y,-extents.z)*0.9f),
go.transform.TransformDirection(nuevo Vector3(extents.x,extents.y,extents .z )*0.5f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,-extents.z)*0.5f),
go .transform .TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y ,- extensiones.z)*0.5f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,extents.z)*0.5f),
go.transform.TransformDirection(nuevo Vector3(-extents.x,extents.y,-extents.z)*0.5f),
go.transform.TransformDirection(nuevo Vector3(-extents.x ,- extensiones.y,extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,-extents.z)*0.5f) ,
go.transform.TransformDirection(nuevo Vector3(extents.x,extents.y,extents.z)*0.75f),
go.transform.TransformDirection(nuevo Vector3( extensiones.x,extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(new
Vector3(extensión.x,-extensión.y,extensión.z)*0.75f),
go.transform.TransformDirection(nuevo Vector3(extensión.x,-extensión.y,-extensión.z) *0.75f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,extents.z)*0.75f),
go.transform. TransformDirection(nuevo Vector3(-extents.x,extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(nuevo Vector3(-extents.x,-extents.y, extensiones.z)*0.75f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(extents.x,extents. y,-extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,-extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(-extents. x,extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,-extents.z)*0.25f),
go.transform.TransformDirection(nuevo Vector3(-extents.x,-extents.y,extents.z)*0.25f),
go.transform.TransformDirection(nuevo Vector3 (-extents.x,-extents.y,-extents.z)*0.25f)
};
}
else // Solo si el objeto del juego no tiene malla (= casi nunca) (Más o menos verificando los puntos usando los límites del renderizador y no los límites de la malla)
{
gobounds = nuevo Vector3[9]{
Vector3.zero,
nuevo Vector3(extents.x,extents.y,extents.z)* coefreduc,
nuevo Vector3(extents.x,extents.y,-extents.z)*coefreduc,
nuevo Vector3(extents.x,-extents.y,extents.z )*coefreduc,
nuevo Vector3(extents.x,-extents.y,-extents.z)*coefreduc,
nuevo Vector3(-extents.x,extents.y, extensiones.z)*coefreduc,
nuevo Vector3(-extents.x,extents.y,-extents.z)*coefreduc,
nuevo Vector3(-extents.x,- extensiones.y,extents.z)*coefreduc,
nuevo Vector3(-extents.x,-extents.y,-extents.z)*coefreduc
};
}
foreach(Vector3 v in gobounds)
{
// prueba si puede ver el objeto del juego
if (GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(_camera), new Bounds(v+center, Vector3.zero)) // si apunta a ver el frustrum
&& (!Physics.Linecast(transform.position, v +centro, fuera hitInfo) || hitInfo.collider.gameObject == ir )) //
si no hay nada entre la posición de visualización y el punto
{
if(graphicalDebug)
{
Debug.DrawLine(transform.position, v +center,Color.red, 0.01f, false);
}
devuelve verdadero;
}
}
}
return false;
}
Si aún no entiendes nada, puedes buscar en Baidu: Memorias de programación, son Ahora, al grabar tutoriales en esta área, todos comenzamos desde cero y avanzamos desde lo menos profundo a lo más avanzado.