Agent: < /p>
Код: Выделить всё
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using UnityEngine;
public class ProjectileAgent : Agent
{
public Transform target; // Stationary target with a 2D collider & "Target" tag
public Transform launchPoint; // Where the projectile is spawned
public GameObject projectilePrefab; // Prefab with Rigidbody2D & ProjectileCollision script
public float fixedForce = 500f; // Constant force applied to the projectile
private bool hasLaunched = false;
public override void OnEpisodeBegin()
{
hasLaunched = false;
RequestDecision(); // Request one decision at start of each episode
}
public override void CollectObservations(VectorSensor sensor)
{
// Observe the relative position from launchPoint to target (x,y)
Vector2 diff = target.position - launchPoint.position;
sensor.AddObservation(diff.x);
sensor.AddObservation(diff.y);
}
public override void OnActionReceived(ActionBuffers actions)
{
if (!hasLaunched)
{
// One continuous action (0..1) mapped to [0..180] degrees
float angle01 = Mathf.Clamp01(actions.ContinuousActions[0]);
float angleDegrees = Mathf.Lerp(0f, 180f, angle01);
LaunchProjectile(angleDegrees);
hasLaunched = true;
}
}
private void LaunchProjectile(float angleDegrees)
{
GameObject projObj = Instantiate(projectilePrefab, launchPoint.position, Quaternion.identity);
ProjectileCollision projScript = projObj.GetComponent
();
projScript.agent = this;
Rigidbody2D rb = projObj.GetComponent();
float rad = angleDegrees * Mathf.Deg2Rad;
Vector2 direction = new Vector2(Mathf.Cos(rad), Mathf.Sin(rad));
rb.AddForce(direction * fixedForce);
}
// Called by projectile on hitting the target
public void OnHitTarget()
{
AddReward(1.0f);
EndEpisode();
}
// Called by projectile on missing the target
public void OnMiss(Vector2 projectilePosition)
{
float distance = Vector2.Distance(projectilePosition, target.position);
float maxDistance = 10f; // Adjust as needed
float proximity = 1f - (distance / maxDistance);
proximity = Mathf.Clamp01(proximity);
// Partial reward for getting close
AddReward(proximity * 0.5f);
// Small penalty for a miss
AddReward(-0.1f);
EndEpisode();
}
// Heuristic for testing in Unity Editor (random angle)
public override void Heuristic(in ActionBuffers actionsOut)
{
actionsOut.ContinuousActions[0] = Random.value;
}
}
< /code>
снаряд: < /p>
using UnityEngine;
public class ProjectileCollision : MonoBehaviour
{
public ProjectileAgent agent;
private void Start()
{
// Destroy after a short time so we can register a miss
Destroy(gameObject, lifetime);
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Target"))
{
agent.OnHitTarget();
}
else
{
agent.OnMiss(transform.position);
}
Destroy(gameObject);
}
}
Формирование вознаграждения:
+1 для достижения цели, частичное вознаграждение на основе расстояний для почти пропусков и небольшой негатив Отсутствует. Я запускаю до 300K+ шаги, используя PPO. > Фиксированная сила и гравитация:
Проверено, что стрелка может достичь цели вручную с помощью углов жесткого кодирования.
Гравитация установлена, поэтому физически можно ударить. < /li>
Нет случайной цели:
Цель в настоящее время фиксируется в одном месте, чтобы сделать его простой. < /Li>
< /ol>
Подробнее здесь: https://stackoverflow.com/questions/793 ... k-in-unity