Curso de Inteligencia Artificial con ML-Agents de UNITY. Introducción.
Entrenamos dos agentes simultaneamente con ML Agents de UNITY
Cualquier duda o comentario de la lección podéis dejarla en el foro del curso.
Entrenamos dos agentes al mismo tiempo. El segundo de ellos se han modificado los premios y los castigos para que intente frenar la llegada de los rivales al monolito.
La única modificación introducida han sido las observaciones y los premios y castigos. Recibe un premio pequeño cada segundo que el otro jugador no esta en el monolito y un castigo grande cada vez que su rival esta tocando o dentro del monolito. Como observaciones se ha incorporado la posición del rival, así como su distancia al monolito.
Con estas modificaciones el segundo Agente, usando el motor de Machine Learning de ML Agents de Unity, ha conseguido aprender a mantener alejado a sus contrincantes de monolito, y a echarlos en caso de que lleguen.
El proceso de incorporación de esta feature al NPC ha sido mucho mas sencillo que si se hubiese tenido que desarrollar por código. Con lo que demuestra la flexibilidad y potencia que dan los ML Agents a los desarrolladores de juegos Indie que pueden despreocuparse de programar NPC’s complejos.
El script del agente utilizado:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using Unity.MLAgents; using Unity.MLAgents.Sensors; public class HumanoidML : Agent { [Header("Velocidad")] [Range(0f, 5f)] public float _speed; [Header("Velocidad de giro")] [Range(50f, 300f)] public float _turnSpeed; public bool _training = true; protected Rigidbody _rb; [SerializeField] protected Transform _target; protected Animator _anim; protected Vector3 _previous; public Text _contadorText = null; public float _puntos = 0; public override void Initialize() { _rb = GetComponent<Rigidbody>(); _anim = GetComponent<Animator>(); _previous = transform.position; //MaxStep forma parte de la clase Agent if (!_training) MaxStep = 0; } public override void OnEpisodeBegin() { _rb.velocity = Vector3.zero; _rb.angularVelocity = Vector3.zero; MoverPosicionInicial(); _previous = transform.position; } public override void OnActionReceived(float[] vectorAction) { float lForward = vectorAction[0]; float lTurn = 0; if (vectorAction[1] == 1) { lTurn = -1; } else if (vectorAction[1] == 2) { lTurn = 1; } _rb.MovePosition(transform.position + transform.forward * lForward * _speed * Time.deltaTime); transform.Rotate(transform.up * lTurn * _turnSpeed * Time.deltaTime); } public virtual void Update() { float velocity = ((transform.position - _previous).magnitude) / Time.deltaTime; _previous = transform.position; _anim.SetFloat("multiplicador", velocity); } public override void CollectObservations(VectorSensor sensor1) { //Distancia al target. //Vector 3 posicion. sensor1.AddObservation( Vector3.Distance(_target.transform.position, transform.position)); //Dirección al target. //Vector 3 posiciones. sensor1.AddObservation( (_target.transform.position - transform.position).normalized); //Vector del señor, donde mira. //Vector de 3 posiciones. sensor1.AddObservation( transform.forward); } public override void Heuristic(float[] actionsOut) { float lForward = 0f; float lTurn = 0f; if (Input.GetKey(KeyCode.UpArrow)) { lForward = 1f; } if (Input.GetKey(KeyCode.LeftArrow)) { lTurn = 1f; } else if (Input.GetKey(KeyCode.RightArrow)) { lTurn = 2f; } // Put the actions into an array and return actionsOut[0] = lForward; actionsOut[1] = lTurn; } private void OnTriggerStay(Collider other) { if (true) { if (other.CompareTag("target")) { DaPremio(0.5f); } if (other.CompareTag("borders")) { DaPremio(-0.05f); } } } protected void DaPremio(float premio) { if (_training) { AddReward(premio); } if (_contadorText != null) { _puntos += premio; _contadorText.text = _puntos.ToString(); } } protected void MoverPosicionInicial() { bool posicionEncontrada = false; int intentos = 100; Vector3 posicionPotencial = Vector3.zero; while (!posicionEncontrada || intentos >= 0) { intentos--; posicionPotencial = new Vector3( transform.parent.position.x + UnityEngine.Random.Range(-3f, 3f), 0.555f, transform.parent.position.z + UnityEngine.Random.Range(-3f, 3f)); //en el caso de que tengamos mas cosas en el escenario checker que no choca Collider[] colliders = Physics.OverlapSphere(posicionPotencial, 0.5f); if (colliders.Length == 0) { transform.position = posicionPotencial; posicionEncontrada = true; } } } }