using System.Collections; using System.Collections.Generic; using UnityEngine; /** * Welcome to Unity Machine Learning Agents documentation. */ [System.Serializable] public class ScreenConfiguration { [Tooltip("Width of the environment window in pixels.")] public int width; [Tooltip("Height of the environment window in pixels")] public int height; [Tooltip("Rendering quality of environment. (Higher is better quality)")] [Range(0, 5)] public int qualityLevel; [Tooltip("Speed at which environment is run. (Higher is faster)")] [Range(1f, 100f)] public float timeScale; [Tooltip("FPS engine attempts to maintain.")] public int targetFrameRate; public ScreenConfiguration(int w, int h, int q, float ts, int tf) { width = w; height = h; qualityLevel = q; timeScale = ts; targetFrameRate = tf; } } [HelpURL("https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Agents-Editor-Interface.md#academy")] /** Create a child class to implement InitializeAcademy(), AcademyStep() * and AcademyReset(). The child class script must be attached to an empty game * object in your scene, and there can only be one such object within the scene. */ public abstract class Academy : MonoBehaviour { [SerializeField] [Tooltip("Total number of steps per episode. \n" + "0 corresponds to episodes without a maximum number of steps. \n" + "Once the step counter reaches maximum, " + "the environment will reset.")] private int maxSteps; [SerializeField] [HideInInspector] public bool isInference = true; /**< \brief Do not modify : If true, the Academy will use inference * settings. */ private bool _isCurrentlyInference; [SerializeField] [Tooltip("The engine-level settings which correspond to rendering quality" + " and engine speed during Training.")] private ScreenConfiguration trainingConfiguration = new ScreenConfiguration(80, 80, 1, 100.0f, -1); [SerializeField] [Tooltip("The engine-level settings which correspond to rendering quality" + " and engine speed during Inference.")] private ScreenConfiguration inferenceConfiguration = new ScreenConfiguration(1280, 720, 5, 1.0f, 60); /**< \brief Contains a mapping from parameter names to float values. */ /**< You can specify the Default Reset Parameters in the Inspector of the * Academy. You can modify these parameters when training with an External * brain by passing a config dictionary at reset. Reference resetParameters * in your AcademyReset() or AcademyStep() to modify elements in your * environment at reset time. */ [SerializeField] [Tooltip("List of custom parameters that can be changed in the " + "environment on reset.")] public ResetParameters resetParameters; public event System.Action BrainDecideAction; public event System.Action AgentSetStatus; public event System.Action AgentResetIfDone; public event System.Action AgentSendState; public event System.Action AgentAct; public event System.Action AgentForceReset; /**< \brief The done flag of the Academy. */ /**< When set to true, the Academy will call AcademyReset() instead of * AcademyStep() at step time. * If true, all agents done flags will be set to true.*/ private bool done; /// /// The max step reached. /// private bool maxStepReached; /**< \brief Increments each time the environment is reset. */ [HideInInspector] public int episodeCount; [HideInInspector] public int stepsSinceReset; /**< \brief Do not modify : pointer to the communicator currently in * use by the Academy. */ public Communicator communicator; private bool firstAcademyReset; void Awake() { _InitializeAcademy(); } void _InitializeAcademy() { List brains = GetBrains(gameObject); InitializeAcademy(); communicator = new ExternalCommunicator(this); if (!communicator.CommunicatorHandShake()) { communicator = null; } foreach (Brain brain in brains) { brain.InitializeBrain(this, communicator); } if (communicator != null) { communicator.InitializeCommunicator(); communicator.UpdateCommand(); } isInference = (communicator == null); _isCurrentlyInference = !isInference; BrainDecideAction += () => { }; AgentSetStatus += (m, d, i) => { }; AgentResetIfDone += () => { }; AgentSendState += () => { }; AgentAct += () => { }; AgentForceReset += () => { }; } /// Environment specific initialization. /** * Implemented in environment-specific child class. * This method is called once when the environment is loaded. */ public virtual void InitializeAcademy() { } private void ConfigureEngine() { if ((!isInference)) { Screen.SetResolution( trainingConfiguration.width, trainingConfiguration.height, false); QualitySettings.SetQualityLevel( trainingConfiguration.qualityLevel, true); Time.timeScale = trainingConfiguration.timeScale; Application.targetFrameRate = trainingConfiguration.targetFrameRate; QualitySettings.vSyncCount = 0; Time.captureFramerate = 60; Monitor.SetActive(false); } else { Screen.SetResolution( inferenceConfiguration.width, inferenceConfiguration.height, false); QualitySettings.SetQualityLevel( inferenceConfiguration.qualityLevel, true); Time.timeScale = inferenceConfiguration.timeScale; Application.targetFrameRate = inferenceConfiguration.targetFrameRate; Time.captureFramerate = 60; Monitor.SetActive(true); } } /// Environment specific step logic. /** * Implemented in environment-specific child class. * This method is called at every step. */ public virtual void AcademyStep() { } /// Environment specific reset logic. /** * Implemented in environment-specific child class. * This method is called everytime the Academy resets (when the global done * flag is set to true). */ public virtual void AcademyReset() { } public void Done() { done = true; } public bool IsDone() { return done; } /// /// Forceds the full reset. The done flags are not affected. Is either /// called the first reset at inference and every external reset /// at training. /// private void ForcedFullReset() { _AcademyReset(); AgentForceReset(); firstAcademyReset = true; } internal void _AcademyStep() { if (isInference != _isCurrentlyInference) { ConfigureEngine(); _isCurrentlyInference = isInference; } if (communicator != null) { if (communicator.GetCommand() == ExternalCommand.RESET) { Dictionary NewResetParameters = communicator.GetResetParameters(); foreach (KeyValuePair kv in NewResetParameters) { resetParameters[kv.Key] = kv.Value; } ForcedFullReset(); communicator.SetCommand(ExternalCommand.STEP); } if (communicator.GetCommand() == ExternalCommand.QUIT) { Application.Quit(); } } else if (!firstAcademyReset) { ForcedFullReset(); } if ((stepsSinceReset >= maxSteps) && maxSteps > 0) { maxStepReached = true; Done(); } AgentSetStatus(maxStepReached, done, stepsSinceReset); if (done) _AcademyReset(); AgentResetIfDone(); AgentSendState(); BrainDecideAction(); AcademyStep(); AgentAct(); stepsSinceReset += 1; } internal void _AcademyReset() { stepsSinceReset = 0; episodeCount++; done = false; maxStepReached = false; AcademyReset(); } void FixedUpdate() { _AcademyStep(); } private static List GetBrains(GameObject gameObject) { List brains = new List(); var transform = gameObject.transform; for (var i = 0; i < transform.childCount; i++) { var child = transform.GetChild(i); var brain = child.GetComponent(); if (brain != null && child.gameObject.activeSelf) brains.Add(brain); } return brains; } }