quot;[AgentBrainDirector] skill {skill:0.00} -> {brains[pick].label}"); } void OnValidate() { if (Application.isPlaying && brains != null && brains.Length > 0) Apply(force: false); } } ``` Notes: - `SetModel` requires the new model to match the agent's observation and action spec; checkpoints from the same run always do. - Swapping mid-episode is fine for this agent (it has no memory). For agents with LSTM memory, swap at episode boundaries. - Hook `SetSkill` to whatever your DDA system produces ([[Game Balance and Dynamic Difficulty]]), or expose it as an Easy/Normal/Hard option in a settings menu ([[Accessibility]]). ## 5.3 Wrapping the agent so it reads like a designed enemy A raw policy has no wind-up and no tells. Rogers' enemy rules (Level 11 in [[Level Up! (Review)]]) want both. Put a tiny state machine *around* the agent, like the one in [[Enemy AI State Machine]]: the network drives only the **Chase** state. ```csharp using UnityEngine; using Unity.MLAgents; /// <summary> /// Gates a trained agent: Idle (agent off), Chase (agent decides), Telegraph (stop + wind-up), Cooldown. /// The network never decides when to attack; the designer does. /// </summary> public sealed class AgentStateGate : MonoBehaviour { enum State { Idle, Chase, Telegraph, Cooldown } [SerializeField] Agent agent; [SerializeField] DecisionRequester decisionRequester; [SerializeField] Rigidbody body; [SerializeField] Transform player; [SerializeField] float noticeRange = 12f; [SerializeField] float attackRange = 2f; [SerializeField] float telegraphTime = 0.6f; [SerializeField] float cooldownTime = 1.2f; [SerializeField] Animator animator; // optional: "Telegraph" trigger [SerializeField] AudioSource telegraphSound; // optional State _state = State.Idle; float _timer; void Start() => Enter(State.Idle); void Update() { float d = Vector3.Distance(transform.position, player.position); _timer -= Time.deltaTime; switch (_state) { case State.Idle: if (d < noticeRange) Enter(State.Chase); break; case State.Chase: if (d > noticeRange * 1.5f) Enter(State.Idle); else if (d < attackRange) Enter(State.Telegraph); break; case State.Telegraph: if (_timer <= 0f) { DoAttack(); Enter(State.Cooldown); } break; case State.Cooldown: if (_timer <= 0f) Enter(State.Chase); break; } } void Enter(State s) { _state = s; bool agentDrives = s == State.Chase; // Stop requesting decisions outside Chase so the policy cannot move the body. decisionRequester.enabled = agentDrives; if (!agentDrives) body.linearVelocity = new Vector3(0f, body.linearVelocity.y, 0f); if (s == State.Telegraph) { _timer = telegraphTime; if (animator) animator.SetTrigger("Telegraph"); if (telegraphSound) telegraphSound.Play(); } else if (s == State.Cooldown) _timer = cooldownTime; } void DoAttack() { // Spawn a hitbox / call your combat system here (see Combat Feel and Hit Feedback). Debug.Log(quot;{name} attacks"); } } ``` For this the agent must be trained with the **player** as its target instead of a coin (swap `coin` for the player transform in a copy of the agent, or train it on a moving coin). Disabling `DecisionRequester` means no new decisions; with "Take Actions Between Decisions" the last action could still be repeated, which is why the gate also zeroes velocity. Verify in play mode that the agent truly stops; if not, also set a flag the agent checks at the top of `OnActionReceived`. ## 5.4 Cost - Each decision runs one forward pass. With Decision Period 5 and 20 agents, that's about 200 inferences per second of tiny networks on Burst; usually trivial, but measure in the Profiler ([[Profiling and Optimization]]). - Agents that share a model are batched by ML-Agents per decision step. - On mobile or Quest (VR on Unity 6.3 LTS, see [[5.Quest 2 Performance and Rendering]]), keep Decision Period high and agent counts low, and test on device. ## Sources - `Agent.SetModel`: https://docs.unity3d.com/Packages/[email protected]/api/Unity.MLAgents.Agent.html - `BehaviorParameters`: https://docs.unity3d.com/Packages/[email protected]/api/Unity.MLAgents.Policies.BehaviorParameters.html - `InferenceDevice`: https://docs.unity3d.com/Packages/[email protected]/api/Unity.MLAgents.Policies.InferenceDevice.html - ML-Agents and Sentis: https://docs.unity3d.com/Packages/[email protected]/manual/Inference-Engine.html