using System; using UnityEngine; using MLAgents; using MLAgents.Policies; public class AgentSoccer : Agent { // Note that that the detectable tags are different for the blue and purple teams. The order is // * ball // * own goal // * opposing goal // * wall // * own teammate // * opposing player public enum Team { Blue = 0, Purple = 1 } [HideInInspector] public Team team; float m_KickPower; int m_PlayerIndex; public SoccerFieldArea area; [HideInInspector] public Rigidbody agentRb; SoccerSettings m_SoccerSettings; BehaviorParameters m_BehaviorParameters; Vector3 m_Transform; public override void Initialize() { m_BehaviorParameters = gameObject.GetComponent(); if (m_BehaviorParameters.TeamId == (int)Team.Blue) { team = Team.Blue; m_Transform = new Vector3(transform.position.x - 4f, .5f, transform.position.z); } else { team = Team.Purple; m_Transform = new Vector3(transform.position.x + 4f, .5f, transform.position.z); } m_SoccerSettings = FindObjectOfType(); agentRb = GetComponent(); agentRb.maxAngularVelocity = 500; var playerState = new PlayerState { agentRb = agentRb, startingPos = transform.position, agentScript = this, }; area.playerStates.Add(playerState); m_PlayerIndex = area.playerStates.IndexOf(playerState); playerState.playerIndex = m_PlayerIndex; } public void MoveAgent(float[] act) { var dirToGo = Vector3.zero; var rotateDir = Vector3.zero; m_KickPower = 0f; var forwardAxis = (int)act[0]; var rightAxis = (int)act[1]; var rotateAxis = (int)act[2]; switch (forwardAxis) { case 1: dirToGo = transform.forward * 1f; m_KickPower = 1f; break; case 2: dirToGo = transform.forward * -1f; break; } switch (rightAxis) { case 1: dirToGo = transform.right * 0.3f; break; case 2: dirToGo = transform.right * -0.3f; break; } switch (rotateAxis) { case 1: rotateDir = transform.up * -1f; break; case 2: rotateDir = transform.up * 1f; break; } transform.Rotate(rotateDir, Time.deltaTime * 100f); agentRb.AddForce(dirToGo * m_SoccerSettings.agentRunSpeed, ForceMode.VelocityChange); } public override void OnActionReceived(float[] vectorAction) { // Existential penalty for strikers. AddReward(-1f / 3000f); MoveAgent(vectorAction); } public override float[] Heuristic() { var action = new float[3]; //forward if (Input.GetKey(KeyCode.W)) { action[0] = 1f; } if (Input.GetKey(KeyCode.S)) { action[0] = 2f; } //rotate if (Input.GetKey(KeyCode.A)) { action[2] = 1f; } if (Input.GetKey(KeyCode.D)) { action[2] = 2f; } //right if (Input.GetKey(KeyCode.E)) { action[1] = 1f; } if (Input.GetKey(KeyCode.Q)) { action[1] = 2f; } return action; } /// /// Used to provide a "kick" to the ball. /// void OnCollisionEnter(Collision c) { var force = 2000f * m_KickPower; if (c.gameObject.CompareTag("ball")) { var dir = c.contacts[0].point - transform.position; dir = dir.normalized; c.gameObject.GetComponent().AddForce(dir * force); } } public override void OnEpisodeBegin() { if (team == Team.Purple) { transform.rotation = Quaternion.Euler(0f, -90f, 0f); } else { transform.rotation = Quaternion.Euler(0f, 90f, 0f); } transform.position = m_Transform; agentRb.velocity = Vector3.zero; agentRb.angularVelocity = Vector3.zero; SetResetParameters(); } public void SetResetParameters() { area.ResetBall(); } }