This commit is contained in:
2024-06-12 21:03:42 +02:00
parent 4685d9942b
commit aef3b3ab97
1548 changed files with 5615 additions and 72 deletions

View File

@@ -0,0 +1,24 @@
using UnityEngine;
public class HumanPlayerBehaviour : PlayerBehaviour
{
protected override sbyte ChooseDirection()
{
return Input.GetKey(KeyCode.Space) ? (sbyte)1 : (sbyte)-1;
}
protected override bool ChooseIfPlayerIsHuman()
{
return true;
}
protected override Color ChoosePlayerColor()
{
return new Color(255, 255, 255);
}
protected override string ChoosePlayerName()
{
return "Joueur Humain";
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class IteratorBehaviour : PlayerBehaviour
{
SensorsScript sensorsScript;
Rigidbody2D rb;
[SerializeField] private List<float> raycastWeight = new List<float>(){
3f, 5f, 5f, 3f, 12f, 25f, 0f, 25f, 12f, 3f, 5f, 5f, 3f
};
protected override sbyte ChooseDirection()
{
List<SensorData> sensorDataList = sensorsScript.GetObserverRaycast();
float influenceSum = 0f;
// Calculer l'influence totale en parcourant les données de capteurs
for (int i = 0; i < sensorDataList.Count; i++)
{
SensorData data = sensorDataList[i];
float angle = sensorsScript.raycastConfigurations[i].y; // Obtenir l'angle du raycast
//float horizontalDistance = data.distance * Mathf.Cos(Mathf.Deg2Rad * angle); // Composante horizontale de la distance
float DistanceForce = MinFloat(sensorsScript.raycastDistance/data.distance/10,10);
float influence = DistanceForce * raycastWeight[i];
if(data.hitLayer == 7){
influence *= 0.5f;
}
if(i <= 5){
influence *= -1;
}
influenceSum += influence;
//Debug.Log(i +" --- "+DistanceForce);
}
if (influenceSum > 0.25f && rb.velocity.y > 0f)
{
// Si la direction suggérée est la même que la direction actuelle, réduire l'influence
influenceSum -= 1f;
}
// Utiliser l'influence totale pour déterminer la direction
sbyte direction = (sbyte)(influenceSum > 0 ? 1 : -1);
//Debug.Log("influenceSum" + influenceSum);
return direction;
}
float MinFloat(float a,float b){
if(a > b)
return b;
return a;
}
void Start()
{
sensorsScript = GetComponent<SensorsScript>();
rb = GetComponent<Rigidbody2D>();
}
protected override string ChoosePlayerName()
{
return "Itérateur";
}
protected override Color ChoosePlayerColor()
{
return new Color(255, 70, 0);
}
protected override bool ChooseIfPlayerIsHuman()
{
return false;
}
}

View File

@@ -0,0 +1,110 @@
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using System.Collections.Generic;
public class ObserverAI : Agent
{
#region PROPERTIES
public sbyte LastDirectionDecision { get; private set; }
#endregion
#region VARIABLES
private PlayerScript _playerRef;
private Rigidbody2D rb;
private sbyte direction;
SensorsScript sensorsScript;
private bool isReadyToStartEpisode = false;
#endregion
#region EVENTS
public override void OnActionReceived(ActionBuffers actions)
{
LastDirectionDecision = actions.ContinuousActions[0] > 0 ? (sbyte)1 : (sbyte)-1;
}
#endregion
#region METHODS
public sbyte TakeDecision()
{
//if(isReadyToStartEpisode){
RequestDecision();
//}
return LastDirectionDecision == 0 ? (sbyte)-1 : LastDirectionDecision;
}
public override void CollectObservations(VectorSensor sensor)
{
sensor.AddObservation(rb.transform.localPosition.y);
sensor.AddObservation(rb.velocity.y);
sensor.AddObservation(GameHandler.Instance.FrameDistance);
if (sensorsScript != null)
{
List<SensorData> sensorDataList = sensorsScript.GetObserverRaycast();
// Display raycast data
foreach (SensorData data in sensorDataList)
{
sensor.AddObservation(data.hitLayer);
sensor.AddObservation(data.distance);
}
}
else
{
Debug.LogWarning("SensorsScript component is not assigned.");
}
}
public override void Heuristic(in ActionBuffers actionsOut)
{
// Heuristic method
}
#endregion
#region LIFECYCLE
void Awake()
{
rb = GetComponent<Rigidbody2D>();
sensorsScript = GetComponent<SensorsScript>();
isReadyToStartEpisode = true;
Debug.Log("Observer IA enabled !");
}
/*void Update()
{
var verticalPosition = rb.transform.position.y;
var reward = 0.1f / (0.01f + ((verticalPosition + 0.59f) * (verticalPosition + 0.59f)));
AddReward(reward);
}*/
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Laser"))
{
AddReward(-100f);
//EndEpisode();
}
else if (other.CompareTag("GoodCoin"))
{
AddReward(100f);
}
else if (other.CompareTag("BadCoin"))
{
AddReward(50f);
}
else if (other.CompareTag("Missile"))
{
AddReward(-500f);
}
}
#endregion
}

View File

@@ -0,0 +1,60 @@
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using System.Collections.Generic;
using Unity.MLAgents.Policies;
using Unity.VisualScripting;
using Unity.Barracuda;
public class ObserverBehaviour : PlayerBehaviour
{
private ObserverAI _observerAi;
private BehaviorParameters _behaviourParameters;
protected override void Awake()
{
base.Awake();
_observerAi = _playerRef.gameObject.AddComponent<ObserverAI>();
_observerAi.enabled = false;
_behaviourParameters = _playerRef.gameObject.GetComponent<BehaviorParameters>();// ?? _playerRef.gameObject.AddComponent<BehaviorParameters>();
_behaviourParameters.BehaviorName = "Observer";
_behaviourParameters.BrainParameters.VectorObservationSize = 29;
_behaviourParameters.BrainParameters.ActionSpec =
//new ActionSpec(
// numContinuousActions: 1, // Une seule action continue
// discreteBranchSizes: new int[] { 0 } // Une action discrète avec 0 choix possibles
// );
ActionSpec.MakeContinuous(1);
_behaviourParameters.Model = Resources.Load<NNModel>("Observer");
_observerAi.EndEpisode();
_observerAi.enabled = true;
}
protected override sbyte ChooseDirection()
{
var direction = _observerAi.TakeDecision();
return direction;
}
protected override string ChoosePlayerName()
{
return "Bot Observateur";
}
protected override Color ChoosePlayerColor()
{
return new Color(0, 255, 0);
}
protected override bool ChooseIfPlayerIsHuman()
{
return false;
}
}

View File

@@ -0,0 +1,44 @@
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using System.Collections.Generic;
using Unity.MLAgents.Policies;
using Unity.VisualScripting;
using Unity.Barracuda;
using System;
public class OmnicientBehaviour : PlayerBehaviour
{
public int frames = 0;
public bool boolean;
protected override sbyte ChooseDirection()
{
if (frames == 0)
{
boolean = (DateTime.Now.Millisecond) % 2 == 0;
}
frames++;
if (frames >= 5)
{
frames = 0;
}
return boolean ? (sbyte)1 : (sbyte)-1;
}
protected override string ChoosePlayerName()
{
return "Omnicient";
}
protected override Color ChoosePlayerColor()
{
return new Color(0, 0, 255);
}
protected override bool ChooseIfPlayerIsHuman()
{
return false;
}
}

View File

@@ -0,0 +1,47 @@
using UnityEngine;
public abstract class PlayerBehaviour : MonoBehaviour
{
protected PlayerScript _playerRef;
protected string playerName;
protected Color playerColor;
protected virtual void Awake()
{
playerName = ChoosePlayerName();
playerColor = ChoosePlayerColor();
_playerRef = gameObject.GetComponent<PlayerScript>();
SetPlayerName(playerName);
SetPlayerColor(playerColor);
_playerRef.IsHuman = ChooseIfPlayerIsHuman();
}
protected virtual void FixedUpdate()
{
sbyte direction = ChooseDirection();
_playerRef.MoveVertically(direction,Time.deltaTime);
}
/// <summary>
/// This method choose if the player goes up (+1) or down (-1).
/// The way the decision is made is up to you.
/// This method must return either +1 or -1 ONLY.
/// </summary>
/// <returns>Returns only +1 or -1</returns>
/// <remarks>This methof is called every frames</remarks>
protected abstract sbyte ChooseDirection();
protected abstract string ChoosePlayerName();
protected abstract Color ChoosePlayerColor();
protected abstract bool ChooseIfPlayerIsHuman();
private void SetPlayerName(string name)
{
_playerRef.SetName(name);
}
private void SetPlayerColor(Color color)
{
_playerRef.SetColor(color);
}
}

View File

@@ -0,0 +1,103 @@
using UnityEngine;
using System.Collections.Generic;
public class SensorsScript : MonoBehaviour
{
// Layer à ignorer
public int ObserverlayerToIgnore = 9;
public int IteratorlayerToIgnore = 7;
// Liste des angles et des offsets pour les raycasts
public List<Vector2> raycastConfigurations = new List<Vector2>()
{
new Vector2(1.18f, 75f),
new Vector2(1.18f, 55f),
new Vector2(1.18f, 35f),
new Vector2(1.18f, 15f),
new Vector2(1.18f, 5f),
new Vector2(0.59f, 4f),
new Vector2(0.59f, 0),
new Vector2(0.59f, -4f),
new Vector2(0f, -5f),
new Vector2(0f, -15f) ,
new Vector2(0f, -35f) ,
new Vector2(0f, -55f) ,
new Vector2(0f, -75f)
};
// Longueur des raycasts
public float raycastDistance = 20f;
// Fonction pour obtenir les données de raycasts d'observation
public List<SensorData> GetObserverRaycast()
{
List<SensorData> raycastsData = new List<SensorData>();
// Calculer le LayerMask pour ignorer le layer spécifié
int layerMask = ~(1 << ObserverlayerToIgnore);
// Pour chaque configuration de raycast
foreach (var config in raycastConfigurations)
{
// Créer une variable pour stocker la position de départ du raycast
Vector3 raycastStartPoint = transform.position;
// Obtenir l'angle et l'offset à partir de la configuration
float offset = config.x;
float angle = config.y;
// Calculer la direction du raycast en fonction de l'angle
Vector2 raycastDirection = Quaternion.Euler(0, 0, angle) * transform.right;
// Ajuster la position de départ du raycast en fonction de l'offset
if (offset == 0.59f)
{
raycastStartPoint += new Vector3(0.5f, offset, 0f);
}
else
{
raycastStartPoint += new Vector3(0f, offset, 0f);
}
// Effectuer le raycast en ignorant le layer spécifié
RaycastHit2D hit = Physics2D.Raycast(raycastStartPoint, raycastDirection, raycastDistance, layerMask);
// Dessiner une ligne pour visualiser le raycast (pour le débogage)
Debug.DrawRay(raycastStartPoint, raycastDirection * raycastDistance, Color.blue);
// Créer un objet SensorData pour stocker les informations du raycast
SensorData data = new SensorData();
// Enregistrer les informations du raycast
if (hit.collider != null)
{
data.hitLayer = hit.collider.gameObject.layer;
data.distance = hit.distance;
// Dessiner une ligne rouge jusqu'au point de collision (pour le débogage)
Debug.DrawLine(raycastStartPoint, hit.point, Color.red);
}
else
{
// Si aucun objet n'a été touché, utiliser des valeurs par défaut
data.hitLayer = -1;
data.distance = raycastDistance;
// Dessiner une ligne verte jusqu'à la fin du raycast (pour le débogage)
Debug.DrawRay(raycastStartPoint, raycastDirection * raycastDistance, Color.green);
}
// Ajouter les données du raycast à la liste
raycastsData.Add(data);
}
return raycastsData;
}
}
// Classe pour stocker les données du raycast touché
public class SensorData
{
public int hitLayer;
public float distance;
}