Unity 机器学习代理工具包 (ML-Agents) 是一个开源项目,它使游戏和模拟能够作为训练智能代理的环境。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

258 行
8.0 KiB

using System.Collections;
using System.Collections.Generic;
using Unity.MLAgents;
using UnityEngine;
public class DungeonEscapeEnvController : MonoBehaviour
{
[System.Serializable]
public class PlayerInfo
{
public PushAgentEscape Agent;
[HideInInspector]
public Vector3 StartingPos;
[HideInInspector]
public Quaternion StartingRot;
[HideInInspector]
public Rigidbody Rb;
[HideInInspector]
public Collider Col;
}
[System.Serializable]
public class DragonInfo
{
public SimpleNPC Agent;
[HideInInspector]
public Vector3 StartingPos;
[HideInInspector]
public Quaternion StartingRot;
[HideInInspector]
public Rigidbody Rb;
[HideInInspector]
public Collider Col;
public Transform T;
public bool IsDead;
}
/// <summary>
/// Max Academy steps before this platform resets
/// </summary>
/// <returns></returns>
[Header("Max Environment Steps")] public int MaxEnvironmentSteps = 25000;
private int m_ResetTimer;
/// <summary>
/// The area bounds.
/// </summary>
[HideInInspector]
public Bounds areaBounds;
/// <summary>
/// The ground. The bounds are used to spawn the elements.
/// </summary>
public GameObject ground;
Material m_GroundMaterial; //cached on Awake()
/// <summary>
/// We will be changing the ground material based on success/failue
/// </summary>
Renderer m_GroundRenderer;
public List<PlayerInfo> AgentsList = new List<PlayerInfo>();
public List<DragonInfo> DragonsList = new List<DragonInfo>();
private Dictionary<PushAgentEscape, PlayerInfo> m_PlayerDict = new Dictionary<PushAgentEscape, PlayerInfo>();
public bool UseRandomAgentRotation = true;
public bool UseRandomAgentPosition = true;
PushBlockSettings m_PushBlockSettings;
private int m_NumberOfRemainingPlayers;
public GameObject Key;
public GameObject Tombstone;
private SimpleMultiAgentGroup m_AgentGroup;
void Start()
{
// Get the ground's bounds
areaBounds = ground.GetComponent<Collider>().bounds;
// Get the ground renderer so we can change the material when a goal is scored
m_GroundRenderer = ground.GetComponent<Renderer>();
// Starting material
m_GroundMaterial = m_GroundRenderer.material;
m_PushBlockSettings = FindObjectOfType<PushBlockSettings>();
//Reset Players Remaining
m_NumberOfRemainingPlayers = AgentsList.Count;
//Hide The Key
Key.SetActive(false);
// Initialize TeamManager
m_AgentGroup = new SimpleMultiAgentGroup();
foreach (var item in AgentsList)
{
item.StartingPos = item.Agent.transform.position;
item.StartingRot = item.Agent.transform.rotation;
item.Rb = item.Agent.GetComponent<Rigidbody>();
item.Col = item.Agent.GetComponent<Collider>();
// Add to team manager
m_AgentGroup.RegisterAgent(item.Agent);
}
foreach (var item in DragonsList)
{
item.StartingPos = item.Agent.transform.position;
item.StartingRot = item.Agent.transform.rotation;
item.T = item.Agent.transform;
item.Col = item.Agent.GetComponent<Collider>();
}
ResetScene();
}
// Update is called once per frame
void FixedUpdate()
{
m_ResetTimer += 1;
if (m_ResetTimer >= MaxEnvironmentSteps && MaxEnvironmentSteps > 0)
{
m_AgentGroup.GroupEpisodeInterrupted();
ResetScene();
}
}
public void TouchedHazard(PushAgentEscape agent)
{
m_NumberOfRemainingPlayers--;
if (m_NumberOfRemainingPlayers == 0 || agent.IHaveAKey)
{
m_AgentGroup.EndGroupEpisode();
ResetScene();
}
else
{
agent.gameObject.SetActive(false);
}
}
public void UnlockDoor()
{
m_AgentGroup.AddGroupReward(1f);
StartCoroutine(GoalScoredSwapGroundMaterial(m_PushBlockSettings.goalScoredMaterial, 0.5f));
print("Unlocked Door");
m_AgentGroup.EndGroupEpisode();
ResetScene();
}
public void KilledByBaddie(PushAgentEscape agent, Collision baddieCol)
{
baddieCol.gameObject.SetActive(false);
m_NumberOfRemainingPlayers--;
agent.gameObject.SetActive(false);
print($"{baddieCol.gameObject.name} ate {agent.transform.name}");
//Spawn Tombstone
Tombstone.transform.SetPositionAndRotation(agent.transform.position, agent.transform.rotation);
Tombstone.SetActive(true);
//Spawn the Key Pickup
Key.transform.SetPositionAndRotation(baddieCol.collider.transform.position, baddieCol.collider.transform.rotation);
Key.SetActive(true);
}
/// <summary>
/// Use the ground's bounds to pick a random spawn position.
/// </summary>
public Vector3 GetRandomSpawnPos()
{
var foundNewSpawnLocation = false;
var randomSpawnPos = Vector3.zero;
while (foundNewSpawnLocation == false)
{
var randomPosX = Random.Range(-areaBounds.extents.x * m_PushBlockSettings.spawnAreaMarginMultiplier,
areaBounds.extents.x * m_PushBlockSettings.spawnAreaMarginMultiplier);
var randomPosZ = Random.Range(-areaBounds.extents.z * m_PushBlockSettings.spawnAreaMarginMultiplier,
areaBounds.extents.z * m_PushBlockSettings.spawnAreaMarginMultiplier);
randomSpawnPos = ground.transform.position + new Vector3(randomPosX, 1f, randomPosZ);
if (Physics.CheckBox(randomSpawnPos, new Vector3(2.5f, 0.01f, 2.5f)) == false)
{
foundNewSpawnLocation = true;
}
}
return randomSpawnPos;
}
/// <summary>
/// Swap ground material, wait time seconds, then swap back to the regular material.
/// </summary>
IEnumerator GoalScoredSwapGroundMaterial(Material mat, float time)
{
m_GroundRenderer.material = mat;
yield return new WaitForSeconds(time); // Wait for 2 sec
m_GroundRenderer.material = m_GroundMaterial;
}
public void BaddieTouchedBlock()
{
m_AgentGroup.EndGroupEpisode();
// Swap ground material for a bit to indicate we scored.
StartCoroutine(GoalScoredSwapGroundMaterial(m_PushBlockSettings.failMaterial, 0.5f));
ResetScene();
}
Quaternion GetRandomRot()
{
return Quaternion.Euler(0, Random.Range(0.0f, 360.0f), 0);
}
void ResetScene()
{
//Reset counter
m_ResetTimer = 0;
//Reset Players Remaining
m_NumberOfRemainingPlayers = AgentsList.Count;
//Random platform rot
var rotation = Random.Range(0, 4);
var rotationAngle = rotation * 90f;
transform.Rotate(new Vector3(0f, rotationAngle, 0f));
//Reset Agents
foreach (var item in AgentsList)
{
var pos = UseRandomAgentPosition ? GetRandomSpawnPos() : item.StartingPos;
var rot = UseRandomAgentRotation ? GetRandomRot() : item.StartingRot;
item.Agent.transform.SetPositionAndRotation(pos, rot);
item.Rb.velocity = Vector3.zero;
item.Rb.angularVelocity = Vector3.zero;
item.Agent.MyKey.SetActive(false);
item.Agent.IHaveAKey = false;
item.Agent.gameObject.SetActive(true);
m_AgentGroup.RegisterAgent(item.Agent);
}
//Reset Key
Key.SetActive(false);
//Reset Tombstone
Tombstone.SetActive(false);
//End Episode
foreach (var item in DragonsList)
{
if (!item.Agent)
{
return;
}
item.Agent.transform.SetPositionAndRotation(item.StartingPos, item.StartingRot);
item.Agent.SetRandomWalkSpeed();
item.Agent.gameObject.SetActive(true);
}
}
}