File size: 5,237 Bytes
05c9ac2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
using System;
using UnityEngine;
using UnityEngine.Serialization;
namespace Unity.MLAgents
{
/// <summary>
/// The DecisionRequester component automatically request decisions for an
/// <see cref="Agent"/> instance at regular intervals.
/// </summary>
/// <remarks>
/// Attach a DecisionRequester component to the same [GameObject] as the
/// <see cref="Agent"/> component.
///
/// The DecisionRequester component provides a convenient and flexible way to
/// trigger the agent decision making process. Without a DecisionRequester,
/// your <see cref="Agent"/> implementation must manually call its
/// <seealso cref="Agent.RequestDecision"/> function.
/// </remarks>
[AddComponentMenu("ML Agents/Decision Requester", (int)MenuGroup.Default)]
[RequireComponent(typeof(Agent))]
[DefaultExecutionOrder(-10)]
public class DecisionRequester : MonoBehaviour
{
/// <summary>
/// The frequency with which the agent requests a decision. A DecisionPeriod of 5 means
/// that the Agent will request a decision every 5 Academy steps. /// </summary>
[Range(1, 20)]
[Tooltip("The frequency with which the agent requests a decision. A DecisionPeriod " +
"of 5 means that the Agent will request a decision every 5 Academy steps.")]
public int DecisionPeriod = 5;
/// <summary>
/// Indicates when to requests a decision. By changing this value, the timing of decision
/// can be shifted even among agents with the same decision period. The value can be
/// from 0 to DecisionPeriod - 1.
/// </summary>
[Range(0, 19)]
[Tooltip("Indicates when to requests a decision. By changing this value, the timing " +
"of decision can be shifted even among agents with the same decision period. " +
"The value can be from 0 to DecisionPeriod - 1.")]
public int DecisionStep = 0;
/// <summary>
/// Indicates whether or not the agent will take an action during the Academy steps where
/// it does not request a decision. Has no effect when DecisionPeriod is set to 1.
/// </summary>
[Tooltip("Indicates whether or not the agent will take an action during the Academy " +
"steps where it does not request a decision. Has no effect when DecisionPeriod " +
"is set to 1.")]
[FormerlySerializedAs("RepeatAction")]
public bool TakeActionsBetweenDecisions = true;
[NonSerialized]
Agent m_Agent;
/// <summary>
/// Get the Agent attached to the DecisionRequester.
/// </summary>
public Agent Agent
{
get => m_Agent;
}
internal void Awake()
{
Debug.Assert(DecisionStep < DecisionPeriod, "DecisionStep must be between 0 and DecisionPeriod - 1.");
m_Agent = gameObject.GetComponent<Agent>();
Debug.Assert(m_Agent != null, "Agent component was not found on this gameObject and is required.");
Academy.Instance.AgentPreStep += MakeRequests;
}
void OnDestroy()
{
if (Academy.IsInitialized)
{
Academy.Instance.AgentPreStep -= MakeRequests;
}
}
/// <summary>
/// Information about Academy step used to make decisions about whether to request a decision.
/// </summary>
public struct DecisionRequestContext
{
/// <summary>
/// The current step count of the Academy, equivalent to Academy.StepCount.
/// </summary>
public int AcademyStepCount;
}
/// <summary>
/// Method that hooks into the Academy in order inform the Agent on whether or not it should request a
/// decision, and whether or not it should take actions between decisions.
/// </summary>
/// <param name="academyStepCount">The current step count of the academy.</param>
void MakeRequests(int academyStepCount)
{
var context = new DecisionRequestContext
{
AcademyStepCount = academyStepCount
};
if (ShouldRequestDecision(context))
{
m_Agent?.RequestDecision();
}
if (ShouldRequestAction(context))
{
m_Agent?.RequestAction();
}
}
/// <summary>
/// Whether Agent.RequestDecision should be called on this update step.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected virtual bool ShouldRequestDecision(DecisionRequestContext context)
{
return context.AcademyStepCount % DecisionPeriod == DecisionStep;
}
/// <summary>
/// Whether Agent.RequestAction should be called on this update step.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected virtual bool ShouldRequestAction(DecisionRequestContext context)
{
return TakeActionsBetweenDecisions;
}
}
}
|