Aprende a desarrollar una IA para tus NPCs parte 4

By Danilo Giardina, 10 julio, 2017

inteligencia artificial Unity (IA)

Hola a todos, bienvenidos a una nueva edición de como hacer una inteligencia artificial en Unity. Como había prometido hoy les traigo como desarrollar sensores para la detección de obstáculos en el entorno.Para comenzar vamos a ir a nuestra pestaña de proyectos, carpeta scripts, creamos un nuevo C# script y escribimos el siguiente código.

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

public class CoordinatesSensors : MonoBehaviour {
    public GameObject sForward,sBackward, sRight, sLeft;
    private GameObject obstacle;
	
	void Update () {
        Forward();
        Backward();
        Left();
        Right();
	}
    void Forward()
    {
        Vector3 point_A = gameObject.transform.position;
        Vector3 point_B = sForward.transform.position;
        Vector3 direction = point_B - point_A;
        float distance = Vector3.Distance(point_A, point_B);

        Ray ray = new Ray(gameObject.transform.position, sForward.transform.position);
        Debug.DrawRay(ray.origin, direction * 1.0f, Color.red);

        RaycastHit[] hit;
        hit = Physics.RaycastAll(ray);

        if (hit.Length > 0)
        {
            foreach (RaycastHit h in hit)
            {
                obstacle = h.transform.gameObject;
                Vector3 posObstacle = obstacle.transform.position;
                Vector3 directionObstacle = posObstacle - point_A;
                float distanceObstacle = Vector3.Distance(point_A, posObstacle);
                Debug.Log("adelante " + h.transform.gameObject.name + " a distancia: " 
                + distanceObstacle);
                Debug.DrawRay(ray.origin, directionObstacle * 1.0f, Color.magenta);
                break;
            }
        }
    }
    void Backward()
    {
        Vector3 point_A = gameObject.transform.position;
        Vector3 point_B = sBackward.transform.position;
        Vector3 direction = point_B - point_A;
        float distance = Vector3.Distance(point_A, point_B);

        Ray ray = new Ray(gameObject.transform.position, sBackward.transform.position);
        Debug.DrawRay(ray.origin, direction * 1.0f, Color.red);

        RaycastHit[] hit;
        hit = Physics.RaycastAll(ray);

        if (hit.Length > 0)
        {
            foreach (RaycastHit h in hit)
            {
                obstacle = h.transform.gameObject;
                Vector3 posObstacle = obstacle.transform.position;
                Vector3 directionObstacle = posObstacle - point_A;
                float distanceObstacle = Vector3.Distance(point_A, posObstacle);
                Debug.Log("atras " + h.transform.gameObject.name + " a distancia: "
               + distanceObstacle);
                Debug.DrawRay(ray.origin, directionObstacle * 1.0f, Color.magenta);
                break;
            }
        }
    }
    void Right()
    {
        Vector3 point_A = gameObject.transform.position;
        Vector3 point_B = sRight.transform.position;
        Vector3 direction = point_B - point_A;
        float distance = Vector3.Distance(point_A, point_B);

        Ray ray = new Ray(gameObject.transform.position, sRight.transform.position);
        Debug.DrawRay(ray.origin, direction * 1.0f, Color.red);

        RaycastHit[] hit;
        hit = Physics.RaycastAll(ray);

        if (hit.Length > 0)
        {
            foreach (RaycastHit h in hit)
            {
                obstacle = h.transform.gameObject;
                Vector3 posObstacle = obstacle.transform.position;
                Vector3 directionObstacle = posObstacle - point_A;
                float distanceObstacle = Vector3.Distance(point_A, posObstacle);
                Debug.Log("derecha " + h.transform.gameObject.name + " a distancia: " 
                + distanceObstacle);
                Debug.DrawRay(ray.origin, directionObstacle * 1.0f, Color.magenta);
                break;
            }
        }
    }
    void Left()
    {
        Vector3 point_A = gameObject.transform.position;
        Vector3 point_B = sLeft.transform.position;
        Vector3 direction = point_B - point_A;
        float distance = Vector3.Distance(point_A, point_B);

        Ray ray = new Ray(gameObject.transform.position, sLeft.transform.position);
        Debug.DrawRay(ray.origin, direction * 1.0f, Color.red);

        RaycastHit[] hit;
        hit = Physics.RaycastAll(ray);

        if (hit.Length > 0)
        {
            foreach (RaycastHit h in hit)
            {
                obstacle = h.transform.gameObject;
                Vector3 posObstacle = obstacle.transform.position;
                Vector3 directionObstacle = posObstacle - point_A;
                float distanceObstacle = Vector3.Distance(point_A, posObstacle);
                Debug.Log("izquierda " + h.transform.gameObject.name + " a distancia: " 
                + distanceObstacle);
                Debug.DrawRay(ray.origin, directionObstacle * 1.0f, Color.magenta);
                break;
            }
        }
    }
}

Bueno como podrán apreciar para los que están siguiendo esta saga, este código es muy similar al que ya habíamos visto en la edición anterior salvo algunos cambios. Básicamente lo que hicimos fue separarlo de alguna manera y lanzar un rayo en cada dirección.

Explicación del código

Ahora pasamos a explicar los cambios que hemos realizados en el código.

public GameObject sForward,sBackward, sRight, sLeft;

Lo que hemos hecho acá es dividir la variable target en 4 variables llamadas sensor+dirección, por ejemplo sIzquierda o en su traducción al ingles sLeft.

void Update () {
        Forward();
        Backward();
        Left();
        Right();
	}

Ya no tenemos escrito todo nuestro código en el método Update, sino que creamos 4 métodos individuales y los llamamos desde el Update.

void Forward()
    {
        Vector3 point_A = gameObject.transform.position;
        Vector3 point_B = sForward.transform.position;
        Vector3 direction = point_B - point_A;
        float distance = Vector3.Distance(point_A, point_B);

        Ray ray = new Ray(gameObject.transform.position, sForward.transform.position);
        Debug.DrawRay(ray.origin, direction * 1.0f, Color.red);
       //Continua...

Este es uno de los métodos individuales para cada dirección, en este caso es para la dirección hacia adelante. Lo único que modificamos en esto es cambiar la variable target por la variable correspondiente a la dirección del método en donde estamos.

inteligencia artificial Unity (IA)

 

Puesta en marcha

 

Bien, ya tenemos nuestro código listo pero aun no esta funcional, ya que debemos hacer algunos cambios en nuestra escena.Primero antes que nada tenemos que crear paredes a modo de obstáculos que servirán a nuestro NPC para detectar su entorno, pueden tener o no la misma forma que presentamos en la imagen.Segundo debemos crear 4 cubos dentro de nuestro NPC, a estos cubos le debemos sacar la colisión, desactivar el mesh renderer para que no se vean y colocarlo a 4 unidades de distancia desde el NPC. Es decir que debemos tener estos 4 cubos como hijo de nuestro NPC.Para colocarlo en 4 unidades seria de esta manera cuboDerecha (x=4), cuboIzquierda (x=-4), cuboAdelante(z=4), cuboAtrás(z=-4).Tercero para poder visualizar los sensores solo en la vista de escena, debemos cambiarle el icono a cada uno de ellos, esto se hace haciendo click en el cubo celeste que esta junto al nombre del objeto en la pestaña inspector.Y por último debemos borrar nuestro antiguo script de nuestro NPC, agregar este script y asignarle los 4 cubos según correspondan a sus direcciones.
Bueno eso seria todo espero que les haya gustado, nos veremos en la siguiente edición. Si te ha gustado el post no te olvides de comentarlo y compartir.
Siguiente edición Como rotar y mover nuestro NPC hacia el waypoint.
curso sobre desarrollo de videojuegos en unity

Pulsa en la imagen para ir al curso.

What do you think?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *