Game in 2D on the Unity engine. My hierarchy structure is like this - EmptyObject, named TrainingArea, script TrainingArea.cs is connected to it. I have copied my TrainingArea many times, and while training, it seems to me that when other agents eat their food, it disappears from the first agent. I may be wrong and it may not be. But I know for sure that the food disappears by itself from the very first agent. Sometimes a player in the TrainingArea will spawn not 10 food, but 1 or 3. In addition, other players in their TrainingArea cannot eat their own food. But when trying to eat some food, it may be lost from the first player in the first TrainingArea. In general, the problem may be in the food array. I want each TrainingArea and their Player or Food objects to be independent of other TrainingAreas.

here’s my TrainingArea.cs:
using UnityEngine;
using System.Collections.Generic;

public class TrainingArea : MonoBehaviour
{
[SerializeField] private GameObject playerPrefab;
[SerializeField] private GameObject foodPrefab;
[SerializeField] private int numberOfFoods = 10;
[SerializeField] private float spawnRadius = 5.0f;
private PlayerAgent playerAgent;
private List<GameObject> foodInstances = new List<GameObject>();

private void Start()
{
SpawnPlayer();
SpawnFoods();
}

public void ResetArea()
{
ResetPlayer();
ResetFoods();
}

private void ResetPlayer()
{
if (playerAgent != null)
{
playerAgent.transform.localPosition = new Vector3(Random.Range(-spawnRadius, spawnRadius), Random.Range(-spawnRadius, spawnRadius), 0);
}
}

public void ResetFoods()
{
List<GameObject> eatenFoods = new List<GameObject>();

foreach (GameObject food in foodInstances)
{
if (food != null)
{
food.transform.localPosition = GetValidSpawnPosition();
}
else
{
eatenFoods.Add(food);
}
}

foreach (GameObject food in eatenFoods)
{
Vector3 spawnPosition = GetValidSpawnPosition();
GameObject foodInstance = Instantiate(foodPrefab, spawnPosition, Quaternion.identity, transform);
foodInstances.Add(foodInstance);
}

// Remove eaten food references from the list
foodInstances.RemoveAll(food => food == null);
}

private void SpawnPlayer()
{
Vector3 randomPosition = GetValidSpawnPosition();
GameObject playerInstance = Instantiate(playerPrefab, randomPosition + transform.position, Quaternion.identity, transform);
playerAgent = playerInstance.GetComponent<PlayerAgent>();
}

private void SpawnFoods()
{
for (int i = 0; i < numberOfFoods; i++)
{
Vector3 spawnPosition = GetValidSpawnPosition();
GameObject foodInstance = Instantiate(foodPrefab, spawnPosition, Quaternion.identity, transform);
foodInstances.Add(foodInstance);
}
}

private Vector3 GetValidSpawnPosition()
{
Vector3 spawnPosition;
do
{
spawnPosition = new Vector3(Random.Range(-spawnRadius, spawnRadius), Random.Range(-spawnRadius, spawnRadius), 0);
} while (playerAgent != null && Vector3.Distance(playerAgent.transform.localPosition, spawnPosition) <= 5.0f);

return spawnPosition;
}

public bool AllFoodEaten()
{
foreach (GameObject food in foodInstances)
{
if (food != null)
{
return false;
}
}
return true;
}
}


here’s my PlayerAgent.cs:
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;

public class PlayerAgent : Agent
{
[SerializeField] private float moveSpeed = 5.0f;
[SerializeField] private float maxEpisodeTime = 20.0f;
private TrainingArea trainingArea;
private float episodeTime = 0.0f;

public override void Initialize()
{
trainingArea = GetComponentInParent<TrainingArea>();
}

public override void OnEpisodeBegin()
{
trainingArea.ResetArea();
episodeTime = 0.0f;
}

public override void CollectObservations(VectorSensor sensor)
{
sensor.AddObservation(transform.localPosition);
}

public override void OnActionReceived(ActionBuffers actions)
{
float moveX = Mathf.Clamp(actions.ContinuousActions[0], -1, 1);
float moveY = Mathf.Clamp(actions.ContinuousActions[1], -1, 1);

Vector3 move = new Vector3(moveX, moveY, 0) * moveSpeed * Time.fixedDeltaTime;
Vector3 newPosition = transform.localPosition + move;

Collider2D collider = Physics2D.OverlapCircle(newPosition, 0.5f, LayerMask.GetMask(“Wall”));
if (collider == null || !collider.CompareTag(“Wall”))
{
SetReward(-0.1f);
transform.localPosition = newPosition;
}

Collider2D collider2 = Physics2D.OverlapCircle(newPosition, 0.5f, LayerMask.GetMask(“Food”));
if (collider2 != null && collider2.CompareTag(“Food”))
{
Debug.Log(“OnTriggerEnter2D”);
SetReward(1f);
Destroy(collider2.gameObject);
}
}

public override void Heuristic(in ActionBuffers actionsOut)
{
ActionSegment<float> continuousActions = actionsOut.ContinuousActions;
continuousActions[0] = Input.GetAxis(“Horizontal”);
continuousActions[1] = Input.GetAxis(“Vertical”);
}

private void FixedUpdate()
{
episodeTime += Time.fixedDeltaTime;

if (episodeTime >= maxEpisodeTime || trainingArea.AllFoodEaten())
{
EndEpisode();
}
}

}