using System.Collections.Generic; using UnityEngine; namespace MLAgents { /// /// Brain receive data from Agents through calls to SendState. The brain then updates the /// actions of the agents at each FixedUpdate. /// The Brain encapsulates the decision making process. Every Agent must be assigned a Brain, /// but you can use the same Brain with more than one Agent. You can also create several /// Brains, attach each of the Brain to one or more than one Agent. /// Brain assets has several important properties that you can set using the Inspector window. /// These properties must be appropriate for the Agents using the Brain. For example, the /// Vector Observation Space Size property must match the length of the feature /// vector created by an Agent exactly. /// public abstract class Brain : ScriptableObject { [SerializeField] public BrainParameters brainParameters; protected Dictionary m_AgentInfos = new Dictionary(1024); protected Batcher m_BrainBatcher; [System.NonSerialized] private bool m_IsInitialized; /// /// Sets the Batcher of the Brain. The brain will call the batcher at every step and give /// it the agent's data using SendBrainInfo at each DecideAction call. /// /// The Batcher the brain will use for the current session public void SetBatcher(Batcher batcher) { if (batcher == null) { m_BrainBatcher = null; } else { m_BrainBatcher = batcher; m_BrainBatcher.SubscribeBrain(name); } LazyInitialize(); } /// /// Adds the data of an agent to the current batch so it will be processed in DecideAction. /// /// /// public void SendState(Agent agent, AgentInfo info) { LazyInitialize(); m_AgentInfos.Add(agent, info); } /// /// If the Brain is not initialized, it subscribes to the Academy's DecideAction Event and /// calls the Initialize method to be implemented by child classes. /// private void LazyInitialize() { if (!m_IsInitialized) { var academy = FindObjectOfType(); if (academy) { academy.BrainDecideAction += BrainDecideAction; academy.DestroyAction += Shutdown; Initialize(); m_IsInitialized = true; } } } /// /// Called by the Academy when it shuts down. This ensures that the Brain cleans up properly /// after scene changes. /// private void Shutdown() { if (m_IsInitialized) { m_AgentInfos.Clear(); m_IsInitialized = false; } } /// /// Calls the DecideAction method that the concrete brain implements. /// private void BrainDecideAction() { m_BrainBatcher?.SendBrainInfo(name, m_AgentInfos); DecideAction(); } /// /// Is called only once at the begening of the training or inference session. /// protected abstract void Initialize(); /// /// Is called once per Environment Step after the Brain has been initialized. /// protected abstract void DecideAction(); } }