Crear una IA simple de C # en Unity

imagen

Casi cualquier juego requiere inteligencia artificial (IA) que interactúa con el usuario, la mayoría de las veces en forma de una fuerza hostil para el jugador. En algunos casos, la IA debería ayudar al jugador, en otros debería combatirlo, pero todos los personajes controlados por la computadora tienen algunas similitudes. Dependiendo de los requisitos del proyecto, la IA puede usar comportamientos simples o complejos. Dichos requisitos pueden ser diplomacia con otro jugador o un simple vagar por la plataforma. Sea como fuere, es necesario asegurarse de que la IA haga su trabajo de manera eficiente.

En este proyecto, demostraré una inteligencia artificial muy simple. Supongamos que creamos un juego en el que un jugador debe colarse cerca del cuartel general enemigo. Cuando un jugador es notado por una cámara de seguridad, los enemigos se crean cerca y por un corto período de tiempo persiguen al jugador. Eso es lo que estamos implementando en el proyecto en el nivel más simple. Al finalizar el proyecto, recibirás un objeto de jugador controlado, un círculo utilizado como cámara del enemigo y un objeto del enemigo que perseguirá al jugador cuando el objeto de la cámara informa sobre su presencia.

Preparación


Primero necesitamos crear un proyecto 3D. Haga clic en el botón Nuevo en la parte superior de la ventana después de iniciar Unity, como se muestra en la Figura 1.


Figura 1: crear un nuevo proyecto

Asigne un nombre a su proyecto de IA y asegúrese de que sea un proyecto 3D. Después de elegir un lugar en la computadora para almacenar el proyecto, haga clic en el botón Crear proyecto en la parte inferior, que se muestra en la Figura 2.


Figura 2: pantalla de configuración del proyecto

Después de crear el proyecto, lo primero que debemos hacer es configurar las carpetas en la ventana Activos para organizar nuestro trabajo. Haga clic derecho en la ventana Activos y seleccione Crear → Carpeta para crear una nueva carpeta. Nombre esta carpeta Materiales . Luego cree una segunda carpeta y asígnele el nombre Scripts . La Figura 3 muestra cómo debería verse.


Figura 3: crear una nueva carpeta

Después de todo esto, la ventana Activos debería verse como la que se muestra en la Figura 4.


Figura 4: Ventana de activos .

Luego, cree un piso sobre el cual se colocarán todos los objetos. En la ventana Jerarquía , seleccione Crear → Objeto 3D → Plano para crear un objeto plano que se utilizará como piso.


Figura 5: Creación de un objeto plano.

Nombre este objeto Floor y cambie su valor de Escala X a 7, y el valor de Escala Z a 3. Después de eso, la ventana del Inspector con el objeto Floor seleccionado debería verse como se muestra en la Figura 6.


Figura 6: Configuración de las propiedades del objeto Floor .

Ahora necesitamos crear un nuevo material para Floor para distinguirlo del resto de los objetos que se colocarán en la escena. En la carpeta Materiales de la ventana Activos , cree un nuevo material haciendo clic derecho en la ventana Activos y seleccionando Crear → Material .


Figura 7: crear nuevo material

Cuando termine, nombre el material Piso .


Figura 8: Material del piso .

En la parte superior de la ventana del Inspector con Piso seleccionado, seleccione un selector de color.


Figura 9: elegir un selector de color.

Por supuesto, puede elegir cualquier color para el piso, pero en este ejemplo elegí rojo-marrón, como se muestra en la Figura 10.


Figura 10: selector de color.

Seleccione el objeto Piso en la ventana Jerarquía , y en el componente Representador de malla , seleccione la flecha pequeña junto a Materiales .


Figura 11: Preparación para un cambio de material.

Arrastre el material del piso desde la ventana Activos al campo Elemento 0 del componente Renderizador de malla en la ventana Inspector .


Figura 12: Definición del material del piso como el material del objeto del piso .

Habiendo terminado con el objeto Floor , necesitamos crear alrededor del área de la pared para que el jugador no pueda caerse del borde. Regrese a Crear → Objeto 3D → Plano para crear un nuevo plano. Llamamos a este plano Muro y lo configuramos con las mismas dimensiones que Piso , es decir, Escala X con un valor de 7 y Escala Z con un valor de 3. Luego crea tres muros más, selecciona un objeto y presiona Ctrl + D tres veces. Después de eso, coloca los muros alrededor género de acuerdo con los datos de la tabla.

Titulo
Posición X
Posición Y
Posición z
Rotación x
Rotación z
Pared
-35
21
0 0
0 0
-90
Pared (1)-1
11
-15
90
0 0
Pared (2)
-1
11
13,5
-90
0 0
Pared (3)
34
21
0 0
0 0
90

Tabla 1: Posiciones y rotaciones de todos los objetos de Muro .

Una vez completado todo esto, debe cambiar la posición de la cámara para que mire el piso desde arriba. Seleccione el objeto de la cámara principal y establezca la posición Y en 30, la posición Z en 0 y la rotación X en 80.


Figura 13: configuración del objeto de la cámara.

La escena está preparada, por lo que es hora de crear el personaje del jugador. En la ventana Jerarquía , haga clic en Crear → Objeto 3D → Esfera para crear un objeto de esfera. Denomine este objeto Player y luego haga clic en el botón Agregar componente en la parte inferior de la ventana del Inspector .


Figura 14: agregar un nuevo componente.

Ahora encuentra el cuerpo rígido . Después de eso, seleccione el componente Rigidbody de la lista y agregue el Rigidbody al objeto Player .


Figura 15: agregar un componente Rigidbody .

A continuación, debe asignar una etiqueta al jugador, que luego nos será útil en el código. Haga clic en el menú desplegable Etiqueta en la esquina superior izquierda de la ventana del Inspector y seleccione la etiqueta Reproductor .


Figura 16: Definición de una nueva etiqueta.

Necesitamos establecer la posición del jugador para que no esté debajo del objeto Floor . En el ejemplo, coloqué al jugador en la esquina superior izquierda con una posición X igual a 26, una posición Y igual a 1 y una posición Z igual a -9.


Figura 17: colocación del jugador.

Para que nuestro código futuro funcione correctamente, por supuesto, debemos adjuntarlo al objeto. Regrese a la ventana Jerarquía y esta vez seleccione Crear → Objeto 3D → Cubo . Llame a este cubo Guard , agregue el componente Rigidbody y el componente NavMesh Agent utilizando el botón Agregar componente en la ventana del Inspector . Luego, colóquelo en algún lugar en la esquina superior izquierda de la escena. Después de eso, la ventana del Inspector del objeto Guardia se verá así:


Figura 18: Objeto protector en la ventana del Inspector .

Y este objeto debe ubicarse así:


Figura 19: Colocación del objeto Guard .

Finalmente, necesitamos un objeto usado como el "ojo" del objeto Guardia , que notificará a la Guardia que el jugador lo está tocando. Por última vez, vaya a la ventana Jerarquía y seleccione Crear → Objeto 3D → Esfera para crear otro objeto de esfera. Nombre este objeto Looker . Esta vez no necesitamos agregarle ningún otro componente. Sin embargo, cambiaremos el tamaño del objeto. Después de elegir Looker , cambie las siguientes variables del componente Transformar en la ventana del Inspector .

  • Escala X a las 9.
  • Escala Y a 0.5.
  • Escala Z a las 9.

Después de eso, coloque el Looker de manera que esté ubicado en la parte superior media del piso, como se muestra en la Figura 20.


Figura 20: Ubicación del Looker.

Es el momento adecuado para darle a Looker un material único para que pueda ver que vale la pena evitarlo. En la carpeta Materiales de la ventana Activos , haga clic con el botón derecho y cree un nuevo material. Nómbralo Looker y dale un color rojo brillante. Después de eso, designe este material como el material del objeto Looker para cambiar su color. Después de eso, la escena debería verse así:


Figura 21: Objeto de aspecto con material nuevo.

Lo único que nos queda es crear una malla de navegación para la Guardia , sobre la cual pueda moverse. Hay un menú Ventana en la parte superior del editor de Unity. Elija Ventana → Navegación para abrir la ventana de Navegación que se muestra en la Figura 22.


Figura 22: Ventana de navegación .

Seleccione el objeto Piso en la Jerarquía y luego, en la ventana Navegación , seleccione la casilla de verificación Estática de navegación .


Figura 23: Navegación estática .

Luego, seleccione la opción Hornear en la parte superior de la ventana.


Figura 24: Cambie al menú Hornear .

Se abre el menú Bake , en el que puede cambiar las propiedades de la malla de navegación que vamos a crear. En nuestro ejemplo, nada necesita ser cambiado. Simplemente haga clic en el botón Hornear en la esquina inferior derecha.


Figura 25: creación de una nueva malla de navegación.

En este punto, Unity le pedirá que guarde la escena. Guárdelo, después de lo cual se creará una malla de navegación. Ahora la escena se verá así:


Figura 26: La escena actual con la malla de navegación agregada.

Ahora todo en Unity está configurado, por lo que es hora de crear los scripts necesarios para que el proyecto funcione. En la ventana Activos , haga clic con el botón derecho y seleccione Crear → Script de C # . Nombra este script Player . Repita esta operación dos veces más, creando scripts con los nombres Guard y Looker .


Figura 27: crear un nuevo script.

Después de eso, la carpeta Scripts en la ventana Activos se verá así:


Figura 28: Carpeta de secuencias de comandos .

Primero, comenzaremos a escribir el código del script Player . Haga doble clic en la secuencia de comandos del reproductor en la ventana Activos para abrir Visual Studio y comenzar a crear el código.

Código


El script del jugador es bastante simple, todo lo que hace es dejar que el usuario mueva el objeto bola. Bajo la declaración de clase, necesitamos obtener un enlace al componente Rigidbody que creamos previamente en el proyecto.

private Rigidbody rb; 

Justo después de eso, en la función Inicio , ordenamos a Unity que establezca el componente Rigidbody actual del objeto Player en rb .

 rb = GetComponent<Rigidbody>(); 

Después de eso, el script del jugador se verá así:


Figura 29: Script del jugador en este momento.

Ahora que se asigna el valor rb , debemos dejar que el objeto Player se mueva cuando presionamos las teclas de flecha. Para mover el objeto, usaremos física, aplicando fuerza al objeto cuando el usuario presione las teclas de flecha. Para hacer esto, simplemente agregue el siguiente código a la función Actualizar :

 if (Input.GetKey(KeyCode.UpArrow)) rb.AddForce(Vector3.forward * 20); if (Input.GetKey(KeyCode.DownArrow)) rb.AddForce(Vector3.back * 20); if (Input.GetKey(KeyCode.LeftArrow)) rb.AddForce(Vector3.left * 20); if (Input.GetKey(KeyCode.RightArrow)) rb.AddForce(Vector3.right * 20); 

Con esto hemos completado el script del jugador . El guión terminado se verá así:


Figura 30: el script del jugador terminado.

Guarda tu trabajo y vuelve a Unity. Esta vez, seleccione la secuencia de comandos Guardia en la ventana Activos . Para que el código de Guard funcione, debe agregar la construcción de uso en la parte superior del script.

 using UnityEngine.AI; 

A continuación, declare las siguientes variables inmediatamente después de la declaración de clase.

 public GameObject player; private NavMeshAgent navmesh; 

El objeto Player se usa como el valor de la variable jugador del objeto Guard . Será útil más tarde cuando le ordenemos al objeto Guardia que persiga al jugador. Luego se declara que la variable navmesh recibe el componente NavMeshAgent del objeto. Lo usaremos más tarde cuando el Guardia comience a perseguir al jugador después de que se entere de que el jugador está tocando el objeto Looker . En la función Inicio , debemos establecer el valor de la variable navmesh en el componente NavMesh Agent del objeto:

 navmesh = GetComponent<NavMeshAgent>(); 

Luego, en la función Actualizar , agregamos una sola línea de código:

 navmesh.destination = player.transform.position; 

Esta línea establece el destino para el objeto Guard . En nuestro caso, tomará la posición actual del objeto Player y se moverá a este punto. Después de la operación, el objeto perseguirá constantemente al jugador. La pregunta es, ¿cómo se realiza el proceso de respuesta? No se codificará en el script Guard , sino en el script Looker . Antes de pasar a la secuencia de comandos Looker, mire la Figura 31 para verificar su código de secuencia de comandos Guard .


Figura 31: el guión de Guardia terminado.

Inside Looker, nuevamente necesitamos declarar las siguientes variables:

 public GameObject guard; private float reset = 5; private bool movingDown; 

Después de eso, comentamos la función de Inicio , que no necesitamos en este script. Pasemos a la función Actualizar y agreguemos el siguiente código:

 if (movingDown == false) transform.position -= new Vector3(0, 0, 0.1f); else transform.position += new Vector3(0, 0, 0.1f); if (transform.position.z > 10) movingDown = false; else if (transform.position.z < -10) movingDown = true; reset -= Time.deltaTime; if (reset < 0) { guard.GetComponent<Guard>().enabled = false; GetComponent<SphereCollider>().enabled = true; } 

Aquí es donde tienen lugar las principales acciones del proyecto, así que analicemos el código. En primer lugar, dependiendo del valor de la variable booleana movingDown , el objeto al que se adjunta este script se moverá hacia arriba o hacia abajo. Tan pronto como llegue a cierto punto, cambiará de dirección. A continuación, Looker reducirá el valor de reinicio en función del tiempo real. Tan pronto como el temporizador sea menor que cero, tomará el guión de Guard del objeto Guard y lo desactivará, después de lo cual el objeto Guard comenzará a moverse a la última posición conocida del jugador hasta este momento, y luego se detendrá. Looker también vuelve a encender su colisionador para que todo el proceso pueda comenzar de nuevo. Ahora nuestro script se ve así:


Figura 32: Script de Looker .

Hablando de colisionadores: es hora de crear un código de conflicto que restablezca el temporizador Looker e incluya el script Guard . En la función Actualizar , cree el siguiente código:

 private void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Player") { guard.GetComponent<Guard>().enabled = true; reset = 5; GetComponent<SphereCollider>().enabled = false; } } 

OnCollisionEnter Unity lo reconoce automáticamente como un código de colisión y, por lo tanto, lo ejecuta cuando se produce una colisión con otro objeto. En nuestro caso, primero verifica si el objeto en colisión tiene una etiqueta Player . Si no, ignora el resto del código. De lo contrario, activa la secuencia de comandos Guard , establece el temporizador de reinicio en 5 (es decir, cinco segundos) y desactiva su colisionador para que el jugador pueda moverse a través del objeto y no quedar atrapado accidentalmente en el objeto Looker . La función se muestra en la Figura 33.


Figura 33: Código de colisión para Looker.

¡Eso es todo, el código del proyecto está listo! Puedes hacer un par de cosas más antes de terminar el proyecto. Guarde todo el trabajo y regrese a Unity.

Proyecto terminado


Para completar el proyecto, solo necesitamos adjuntar scripts a los objetos correspondientes y establecer varias variables. Primero, vaya desde la ventana de Navegación a la ventana del Inspector :


Figura 34: transición a la ventana del Inspector.

Después de eso, comencemos con el objeto Player . Selecciónelo en la ventana Jerarquía y luego, en la parte inferior de la ventana del Inspector , haga clic en el botón Agregar componente y agregue el script del reproductor . Esto completa el objeto Player .


Figura 35: Componente de script del reproductor.

A continuación, seleccione el objeto Guardia . Como antes, adjunte la secuencia de comandos Guard al objeto. Esta vez necesitamos decirle al Guardián quién es el jugador. Para hacer esto, arrastre el objeto Player de la Jerarquía al campo Player del componente de script Guard , como se muestra en la Figura 36.


Figura 36: Convertir el objeto del jugador en el valor del campo del jugador .

También necesitamos deshabilitar el script Guard . En nuestro proyecto, Guardia perseguirá al jugador después de encender su guión. Este script de Guardia debe incluirse solo después de que el jugador toque el objeto Looker . Todo lo que necesita hacer es desmarcar la casilla junto al texto Guard (Script) en el componente:


Figura 37: Deshabilitar la secuencia de comandos Guard .

Finalmente, pasemos al objeto Looker y adjuntemos el script Looker al mismo. Esta vez, el objeto Looker necesitará un objeto Guard como el valor de su variable Guard . Así como asignamos el objeto Player a la variable Player del script Guard , haremos lo mismo con el objeto Guard y el script Looker . Arrastre la Guardia desde la Jerarquía al campo Guardia de la secuencia de comandos Looker . ¡Y el proyecto está terminado! Haga clic en el botón Reproducir en la parte superior del editor de Unity para probar su proyecto.


Figura 38: Prueba de un proyecto.

Intenta mover el objeto Player al objeto Looker (¡recuerda que el movimiento se realiza con flechas!). Tenga en cuenta que después de esto, el objeto Guard comenzará a perseguir al jugador. Continuará la búsqueda durante unos 5 segundos, después de lo cual se dará por vencido.


Figura 39: Un proyecto completamente completado en acción.

Conclusión


Esta IA es muy simple, pero puede expandirse fácilmente. Supongamos que si imaginamos que el objeto Looker es una cámara y el guardia mira a través de él para encontrarte, será lógico darle al objeto Guard su propio par de ojos. El jugador puede acercarse a las cámaras, pero deben tener en cuenta los ojos del guardia. También puedes combinar este proyecto con el concepto de encontrar el camino : dale al guardia el camino que seguirá, creando así un ambiente más interesante para el jugador.

Una IA tan simple se puede desarrollar de muchas maneras diferentes. Es posible que no desee hacer nada de lo anterior y decida hacer algo por su cuenta. Te aconsejo que experimentes, quizás tengas la idea de un proyecto interesante, que vale la pena llevar al final.

Source: https://habr.com/ru/post/es419641/


All Articles