builds
This commit is contained in:
264
Scripts/GameHandlers/DataBearer.cs
Normal file
264
Scripts/GameHandlers/DataBearer.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using Newtonsoft.Json;
|
||||
using static GameHandler;
|
||||
using static LevelSpawner;
|
||||
using static PlayerScript;
|
||||
using static PlayersHandler;
|
||||
|
||||
namespace Assets.Scripts
|
||||
{
|
||||
public class DataBearer : SingletonMB<DataBearer>
|
||||
{
|
||||
#region PROPERTIES
|
||||
public bool DataSaved { get; private set; }
|
||||
|
||||
public Attempt CurrentAttempt { get; private set; }
|
||||
|
||||
public SessionData Session
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_session == null)
|
||||
{
|
||||
_session = GetSettings();
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_session = value;
|
||||
}
|
||||
} private SessionData _session = null;
|
||||
|
||||
public GameState GameState { get; set; } = new();
|
||||
|
||||
public Players Players { get { return Session.Players; } }
|
||||
public Rules Rules { get { return Session.Rules; } }
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
private GameHandler _gameHandler;
|
||||
private ScoreHandler _scoreHandler;
|
||||
private PlayersHandler _playerHandler;
|
||||
private LevelSpawner _levelSpawner;
|
||||
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
public void RegisterAttempt_OnAttemptEnded(object sender, AttemptEventArgs eventArgs)
|
||||
{
|
||||
Session.Attempts.Add(CurrentAttempt);
|
||||
CurrentAttempt = null;
|
||||
} //
|
||||
|
||||
public void RegisterPlayer_OnPlayerInstanciated(object sender, PlayerEventArgs args)
|
||||
{
|
||||
var player = args.player;
|
||||
var newPlayer = new RegisteredPlayer()
|
||||
{
|
||||
Name = player.Name,
|
||||
Id = player.Id,
|
||||
Human = player.IsHuman
|
||||
};
|
||||
if(!Session.RegisteredPlayers.Exists(rp => rp.Name == newPlayer.Name))
|
||||
{
|
||||
Session.RegisteredPlayers.Add(newPlayer);
|
||||
}
|
||||
|
||||
player.OnBonusTouched += RecordBonus_OnBonusTouched;
|
||||
player.OnObstacleTouched += RecordObstacle_OnObstacleTouched;
|
||||
} //
|
||||
|
||||
public void CreateAttemptRecord_OnAttemptStarted(object sender, AttemptEventArgs args)
|
||||
{
|
||||
CurrentAttempt = args.attempt;
|
||||
|
||||
foreach(var player in Session.RegisteredPlayers)
|
||||
{
|
||||
PlayerAttempt playerAttempt = new PlayerAttempt()
|
||||
{
|
||||
PlayerName = player.Name
|
||||
};
|
||||
CurrentAttempt.PlayersAttempts.Add(player.Name, playerAttempt);
|
||||
}
|
||||
} //
|
||||
|
||||
public void RecordAttemptObstacle_OnPrefabSpawned(object sender, PrefabSpawnedEventArgs args)
|
||||
{
|
||||
LevelPrefab obstacle = new() {
|
||||
PrefabName = args.pattern.name, //todo : prefab name has "(clone)" at the end
|
||||
PrefabNumber = CurrentAttempt.Level.Count + 1,
|
||||
TickTimeWhenTouched = _gameHandler.TickAttemptDuration
|
||||
};
|
||||
CurrentAttempt.Level.Add(obstacle);
|
||||
} //
|
||||
|
||||
public void RecordObstacle_OnObstacleTouched(object sender, PrefabTouchedEventArgs args)
|
||||
{
|
||||
var prefab = args.objectTouched;
|
||||
TouchedGameObject touchedGameObject = new()
|
||||
{
|
||||
FullObjectName = prefab.name, //todo : prefab name is laser... It should be full pattern name
|
||||
ObjectTypeName = SortingLayer.IDToName(prefab.layer), // todo : <unknown layer>
|
||||
GameSpeed = _gameHandler.MapSpeed,
|
||||
PrefabName = prefab.name,
|
||||
TickTimeWhenTouched = _gameHandler.TickAttemptDuration
|
||||
};
|
||||
CurrentAttempt.PlayersAttempts[args.playerName].ObstaclesTouched.Add(touchedGameObject);
|
||||
|
||||
RecordPlayerScore(args.playerId, args.playerName);
|
||||
} //
|
||||
|
||||
public void RecordBonus_OnBonusTouched(object sender, PrefabTouchedEventArgs args)
|
||||
{
|
||||
var prefab = args.objectTouched;
|
||||
TouchedGameObject touchedGameObject = new()
|
||||
{
|
||||
FullObjectName = prefab.name,
|
||||
ObjectTypeName = SortingLayer.IDToName(prefab.layer),
|
||||
GameSpeed = _gameHandler.MapSpeed,
|
||||
PrefabName = prefab.name,
|
||||
TickTimeWhenTouched = _gameHandler.TickAttemptDuration
|
||||
};
|
||||
CurrentAttempt.PlayersAttempts[args.playerName].BonusTouched.Add(touchedGameObject);
|
||||
RecordPlayerScore(args.playerId, args.playerName);
|
||||
} //
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
|
||||
public void ResetSession()
|
||||
{
|
||||
_session = null;
|
||||
}
|
||||
|
||||
public void SaveData()
|
||||
{
|
||||
string directoryPath = Path.Combine(Application.persistentDataPath, "SessionsData");
|
||||
if (!Directory.Exists(directoryPath))// Crée le répertoire s'il n'existe pas déjà
|
||||
{
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
|
||||
var existingFiles = Directory.GetFiles(directoryPath, "*.json");
|
||||
int sessionNumber = existingFiles.Length + 1;
|
||||
Session.SessionNumber = sessionNumber;
|
||||
|
||||
string jsonData = JsonConvert.SerializeObject(Session);
|
||||
|
||||
string fileName = $"Session_{sessionNumber}.json";
|
||||
string filePath = Path.Combine(directoryPath, fileName);
|
||||
File.WriteAllText(filePath, jsonData);
|
||||
|
||||
|
||||
DataSaved = true;
|
||||
Debug.Log($"Session saved to {filePath}");
|
||||
}
|
||||
|
||||
|
||||
public void RecordSessionTime(float time)
|
||||
{
|
||||
Session.SessionTime = time;
|
||||
}
|
||||
public void RecordSessionDate(DateTime date)
|
||||
{
|
||||
Session.Date = date;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record all players scores
|
||||
/// </summary>
|
||||
public void RecordPlayersScore()
|
||||
{
|
||||
Session.RegisteredPlayers.ForEach(p =>
|
||||
{
|
||||
RecordPlayerScore(p.Id, p.Name);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find and record a player score
|
||||
/// </summary>
|
||||
public void RecordPlayerScore(int playerId, string playerName)
|
||||
{
|
||||
int score = (int) _scoreHandler.GetPlayerScore(playerId);
|
||||
var tickTime = _gameHandler.TickAttemptDuration;
|
||||
|
||||
GenericVector<int, int> ScoreByTime = new() { X = tickTime, Y = score };
|
||||
|
||||
CurrentAttempt.PlayersAttempts[playerName].PlayerScoresOverTicksTime.Add(ScoreByTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record a player final score
|
||||
/// </summary>
|
||||
public void RecordPlayerFinalScore(int score, string playerName)
|
||||
{
|
||||
CurrentAttempt.PlayersAttempts[playerName].FinalScore = score;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record the distance parcoured by the player
|
||||
/// </summary>
|
||||
public void RecordPlayerDistance(string playerName)
|
||||
{
|
||||
CurrentAttempt.PlayersAttempts[playerName].Distance = (int)_gameHandler.TotalDistance;
|
||||
}
|
||||
|
||||
public void RecordPlayerAttemptDuration(string playerName)
|
||||
{
|
||||
CurrentAttempt.PlayersAttempts[playerName].AttemptDurationSeconds = _gameHandler.TimeAttemptDuration;
|
||||
CurrentAttempt.PlayersAttempts[playerName].AttemptDurationTicks = _gameHandler.TickAttemptDuration;
|
||||
}
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
private SessionData GetSettings()
|
||||
{
|
||||
SessionData session = new();
|
||||
session.Players.Human = bool.Parse(PlayerPrefs.GetString(Settings.HumanPlayerSelected));
|
||||
session.Players.OmnicientBot = bool.Parse(PlayerPrefs.GetString(Settings.OmnicientBotSelected));
|
||||
session.Players.ObserverBot = bool.Parse(PlayerPrefs.GetString(Settings.ObserverBotSelected));
|
||||
session.Players.IteratorBot = bool.Parse(PlayerPrefs.GetString(Settings.IteratorBotSelected));
|
||||
session.Rules.ChangeSeedEachTry = bool.Parse(PlayerPrefs.GetString(Settings.ChangeSeedSetting));
|
||||
session.Rules.UsesDefaultSeed = bool.Parse(PlayerPrefs.GetString(Settings.UseDefaultSeedSetting));
|
||||
session.Rules.Lasers = bool.Parse(PlayerPrefs.GetString(Settings.LaserSettingToggle));
|
||||
session.Rules.Missiles = bool.Parse(PlayerPrefs.GetString(Settings.MissileSettingToggle));
|
||||
session.Rules.BonusCoins = bool.Parse(PlayerPrefs.GetString(Settings.CoinSettingToggle));
|
||||
session.Rules.MalusCoins = bool.Parse(PlayerPrefs.GetString(Settings.BadCoinSettingToggle));
|
||||
session.Rules.ScoreOnDistance = bool.Parse(PlayerPrefs.GetString(Settings.SurviveScoreSettingToggle));
|
||||
session.Rules.RushMode = bool.Parse(PlayerPrefs.GetString(Settings.RushModeSettingToggle));
|
||||
session.Rules.MaxDistance = PlayerPrefs.GetFloat(Settings.MaxDistanceSettingValue);
|
||||
session.Rules.MaxAttempts = PlayerPrefs.GetInt(Settings.MaxTrySettingValue);
|
||||
session.Rules.MaxSessionTime = PlayerPrefs.GetInt(Settings.MaxTimeSettingValue);
|
||||
session.Rules.MaxSpeed = PlayerPrefs.GetFloat(Settings.MaxSpeedSettingValue);
|
||||
session.Rules.StartSpeed = PlayerPrefs.GetFloat(Settings.StartSpeedSettingValue);
|
||||
session.Rules.DifficultyMultiplier = PlayerPrefs.GetFloat(Settings.DifficultyMultiplierSettingValue);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
protected override void Awake()
|
||||
{
|
||||
DataSaved = false;
|
||||
Session = GetSettings();
|
||||
base.Awake();
|
||||
|
||||
_gameHandler = GameHandler.Instance;
|
||||
_scoreHandler = ScoreHandler.Instance;
|
||||
_playerHandler = PlayersHandler.Instance;
|
||||
_levelSpawner = LevelSpawner.Instance;
|
||||
|
||||
_gameHandler.OnAttemptEnded += RegisterAttempt_OnAttemptEnded;
|
||||
_gameHandler.OnAttemptStarted += CreateAttemptRecord_OnAttemptStarted;
|
||||
_playerHandler.OnPlayerInstanciated += RegisterPlayer_OnPlayerInstanciated;
|
||||
_levelSpawner.OnPrefabSpawned += RecordAttemptObstacle_OnPrefabSpawned;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
164
Scripts/GameHandlers/GameController.cs
Normal file
164
Scripts/GameHandlers/GameController.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using Assets.Scripts;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using static GameHandler;
|
||||
|
||||
public class GameController : SingletonMB<GameController>
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
public bool IsExiting { get; private set; }
|
||||
public SessionData Session { get; private set; } = new SessionData();
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
private GameHandler _gameHandler;
|
||||
private ScoreHandler _scoreHandler;
|
||||
private LevelSpawner _LevelSpawner;
|
||||
private PlayersHandler _playerHandler;
|
||||
private DataBearer _dataBearer;
|
||||
|
||||
private int maxSessionTime;
|
||||
private float currentSessionTime;
|
||||
private int maxAttempts;
|
||||
private int currentAttempts;
|
||||
#endregion
|
||||
#region EVENTS
|
||||
public event EventHandler<SessionEventArgs> OnSessionEnded;
|
||||
public class SessionEventArgs : EventArgs
|
||||
{
|
||||
public SessionData session;
|
||||
public SessionEventArgs(SessionData session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessNextAttempt_OnAttemptEnded(object sender, AttemptEventArgs args)
|
||||
{
|
||||
if(!IsExiting)
|
||||
{
|
||||
PrepareNextRound();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region METHODS
|
||||
/// <summary>
|
||||
/// Initialize a new round if there are more available attempts
|
||||
/// </summary>
|
||||
public void PrepareNextRound()
|
||||
{
|
||||
currentAttempts+=1;
|
||||
|
||||
|
||||
if(maxAttempts == 0 || _dataBearer.Session.Attempts.Count < maxAttempts)
|
||||
{
|
||||
_gameHandler.InitAttempt();
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitToMenu("Nombre maximum d'essais atteint");
|
||||
}
|
||||
}
|
||||
|
||||
public void ExitToMenu(string message)
|
||||
{
|
||||
IsExiting = true;
|
||||
Debug.Log("Session END");
|
||||
//StartCoroutine(ExitToMenuCoroutine(message));
|
||||
_gameHandler.ResumeGame();
|
||||
//yield return null;
|
||||
if (!_gameHandler.AttemptEnding) _gameHandler.HaltAttempt(message);
|
||||
Clean();
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
_dataBearer.ResetSession();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//private IEnumerator ExitToMenuCoroutine(string message)
|
||||
//{
|
||||
// _gameHandler.ResumeGame();
|
||||
// //yield return null;
|
||||
// if(!_gameHandler.AttemptEnding) _gameHandler.HaltAttempt(message);
|
||||
// _dataBearer.ResetSession();
|
||||
// Clean();
|
||||
// SceneManager.LoadScene("MainMenu");
|
||||
//}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
// Start is called before the first frame update
|
||||
private void Start()
|
||||
{
|
||||
Debug.Log($"Start session for {Session.Rules.MaxAttempts} rounds");
|
||||
_dataBearer.RecordSessionDate(DateTime.Now);
|
||||
|
||||
|
||||
currentSessionTime = 0f;
|
||||
PrepareNextRound();
|
||||
}
|
||||
|
||||
// Awake is called before Start
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_gameHandler = GameHandler.Instance;
|
||||
_scoreHandler = ScoreHandler.Instance;
|
||||
_playerHandler = PlayersHandler.Instance;
|
||||
_dataBearer = DataBearer.Instance;
|
||||
|
||||
_gameHandler.OnAttemptEnded += ProcessNextAttempt_OnAttemptEnded;
|
||||
|
||||
maxAttempts = _dataBearer.Rules.MaxAttempts;
|
||||
maxSessionTime = _dataBearer.Rules.MaxSessionTime;
|
||||
currentAttempts = 0;
|
||||
}
|
||||
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
currentSessionTime += Time.deltaTime;
|
||||
_dataBearer.RecordSessionTime(currentSessionTime);
|
||||
|
||||
|
||||
if (maxSessionTime > 0 && currentSessionTime >= maxSessionTime)
|
||||
{
|
||||
currentSessionTime = maxSessionTime;
|
||||
_dataBearer.RecordSessionTime(currentSessionTime);
|
||||
ExitToMenu("Temps <20>coul<75>");
|
||||
}
|
||||
}
|
||||
|
||||
//Unsubscribe events, save databearer;
|
||||
private void OnDestroy()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
_gameHandler.OnAttemptEnded -= ProcessNextAttempt_OnAttemptEnded;
|
||||
|
||||
if (!_dataBearer.DataSaved)
|
||||
{
|
||||
//datasaving logic
|
||||
_dataBearer.RecordSessionTime(currentSessionTime);
|
||||
|
||||
_dataBearer.SaveData();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
299
Scripts/GameHandlers/GameHandler.cs
Normal file
299
Scripts/GameHandlers/GameHandler.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
using Assets.Scripts;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEditor.Rendering;
|
||||
using UnityEngine;
|
||||
using static PlayersHandler;
|
||||
|
||||
/// <summary>
|
||||
/// GameHandler gère le fonctionnement général d'une partie de jeu. Il se charge de faire apparaître les joueurs
|
||||
/// </summary>
|
||||
public class GameHandler : SingletonMB<GameHandler>
|
||||
{
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
int Seed
|
||||
{
|
||||
get { return _seed; }
|
||||
set
|
||||
{
|
||||
_seed = value;
|
||||
UnityEngine.Random.InitState(value);
|
||||
}
|
||||
} private int _seed;
|
||||
public float FrameDistance { get; private set; }
|
||||
public float TotalDistance { get; private set; }
|
||||
[SerializeField] public float MapSpeed { get; private set; }
|
||||
public Attempt CurrentAttempt { get; private set; }
|
||||
public bool MaxDifficultyReached { get; private set; }
|
||||
public bool IsPaused { get; private set; } = false;
|
||||
public bool HaveHumanPlayer { get; private set; } = false;
|
||||
public bool AttemptEnding { get; private set; }
|
||||
public int TickAttemptDuration { get; private set; }
|
||||
public float TimeAttemptDuration {get; private set;}
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
private const float DIFFICULTY_DAMP = 0.01f;
|
||||
[SerializeField] private GameObject finishLine;
|
||||
private ScoreHandler _scoreHandler;
|
||||
private LevelSpawner _levelSpawner;
|
||||
private PlayersHandler _playerHandler;
|
||||
private DataBearer _dataBearer;
|
||||
private TileSpawner _tileSpawner;
|
||||
|
||||
private Vector3 playerSpawnPosition = new Vector3(-3, 0, 0);
|
||||
|
||||
private float maxSpeed;
|
||||
private float maxDistance;
|
||||
private bool raiseScoreOnDistance;
|
||||
private float difficultyMultiplier;
|
||||
|
||||
private bool finishLineSpawned;
|
||||
|
||||
private short tickCounter;
|
||||
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
public event EventHandler<AttemptEventArgs> OnAttemptStarted;
|
||||
public event EventHandler<AttemptEventArgs> OnAttemptEnding;
|
||||
public event EventHandler<AttemptEventArgs> OnAttemptEnded;
|
||||
public event EventHandler<EventArgs> OnGamePaused;
|
||||
public event EventHandler<EventArgs> OnGameResumed;
|
||||
public event EventHandler<EventArgs> OnInstanciatingPlayers;
|
||||
|
||||
public class AttemptEventArgs : EventArgs
|
||||
{
|
||||
public Attempt attempt;
|
||||
public AttemptEventArgs(Attempt attempt) { this.attempt = attempt; }
|
||||
}
|
||||
|
||||
public void HaltAttempt_OnAllPlayersFinished(object sender, EventArgs agrs)
|
||||
{
|
||||
HaltAttempt("Tous les joueurs sont Out");
|
||||
}
|
||||
|
||||
public void CheckIfHumanPlayer_OnPlayerInstanciated(object sender, PlayerEventArgs args)
|
||||
{
|
||||
if (args.player.IsHuman)
|
||||
{
|
||||
HaveHumanPlayer = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
/// <summary>
|
||||
/// Return a seed which depend on selected settings and attempt number
|
||||
/// </summary>
|
||||
private int SetSeed()
|
||||
{
|
||||
int seed;
|
||||
if (_dataBearer.Session.Rules.ChangeSeedEachTry & CurrentAttempt.AttemptNumber > 1) //Get a random seed each new try
|
||||
{
|
||||
seed = UnityEngine.Random.Range(100000000, 1000000000); //generate a random 9 digits seed
|
||||
}
|
||||
else //Get either default seed or custom seed
|
||||
{
|
||||
seed = _dataBearer.Session.Rules.UsesDefaultSeed
|
||||
? PlayerPrefs.GetInt(Settings.DefaultSeedSettingValue)
|
||||
: PlayerPrefs.GetInt(Settings.CustomSeedSettingValue);
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
private void RaiseScore()
|
||||
{
|
||||
float scoreToAdd = FrameDistance;// * Time.deltaTime;
|
||||
_scoreHandler.AddScoreToAllAlivePlayers(scoreToAdd);
|
||||
}
|
||||
private void RaiseDifficulty()
|
||||
{
|
||||
if(MapSpeed > maxSpeed)
|
||||
{
|
||||
MapSpeed = maxSpeed;
|
||||
MaxDifficultyReached = true;
|
||||
}
|
||||
MapSpeed += MapSpeed * difficultyMultiplier * Time.deltaTime;
|
||||
}
|
||||
|
||||
private void SpawnPlayers()
|
||||
{
|
||||
if (_dataBearer.Session.Players.Human)
|
||||
_playerHandler.InstanciatePlayer<HumanPlayerBehaviour>(playerSpawnPosition);
|
||||
if (_dataBearer.Session.Players.OmnicientBot)
|
||||
_playerHandler.InstanciatePlayer<OmnicientBehaviour>(playerSpawnPosition);
|
||||
if (_dataBearer.Session.Players.ObserverBot)
|
||||
_playerHandler.InstanciatePlayer<ObserverBehaviour>(playerSpawnPosition);
|
||||
if (_dataBearer.Session.Players.IteratorBot)
|
||||
_playerHandler.InstanciatePlayer<IteratorBehaviour>(playerSpawnPosition);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
|
||||
public void PauseGame()
|
||||
{
|
||||
if (!IsPaused)
|
||||
{
|
||||
StartCoroutine(PauseGameCoroutine());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PauseGameCoroutine()
|
||||
{
|
||||
yield return null;
|
||||
Time.timeScale = 0; // Met le jeu en pause
|
||||
IsPaused = true;
|
||||
OnGamePaused.Invoke(this, new EventArgs());
|
||||
}
|
||||
|
||||
public void ResumeGame()
|
||||
{
|
||||
if (IsPaused)
|
||||
{
|
||||
Time.timeScale = _dataBearer.Rules.RushMode ? 15 : 1; // Reprend le jeu
|
||||
IsPaused = false;
|
||||
OnGameResumed.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void InitAttempt()
|
||||
{
|
||||
TimeAttemptDuration = 0;
|
||||
TickAttemptDuration = 0;
|
||||
Debug.LogWarning("Initate Attempt !");
|
||||
AttemptEnding = false;
|
||||
|
||||
CurrentAttempt = new Attempt();
|
||||
CurrentAttempt.AttemptNumber = _dataBearer.Session.Attempts.Count + 1;
|
||||
Seed = SetSeed();
|
||||
CurrentAttempt.Seed = Seed;
|
||||
|
||||
TotalDistance = 0;
|
||||
MapSpeed = _dataBearer.Rules.StartSpeed;
|
||||
raiseScoreOnDistance = _dataBearer.Rules.ScoreOnDistance;
|
||||
maxSpeed = _dataBearer.Rules.MaxSpeed;
|
||||
difficultyMultiplier = _dataBearer.Rules.DifficultyMultiplier * DIFFICULTY_DAMP;
|
||||
if(_dataBearer.Rules.RushMode){
|
||||
Time.timeScale = 15;
|
||||
foreach (var renderer in FindObjectsOfType<Renderer>())
|
||||
{
|
||||
if(renderer.gameObject.GetComponent<ScorePannelScript>()==null)
|
||||
{renderer.enabled = false;}
|
||||
}
|
||||
}
|
||||
else{
|
||||
Time.timeScale = 1;
|
||||
}
|
||||
|
||||
|
||||
MaxDifficultyReached = false;
|
||||
TotalDistance = 0;
|
||||
FrameDistance = 0;
|
||||
|
||||
finishLineSpawned = false;
|
||||
tickCounter = 0;
|
||||
SpawnPlayers();
|
||||
_scoreHandler.AddScoreToAllAlivePlayers(500);
|
||||
OnAttemptStarted?.Invoke(this, new AttemptEventArgs(CurrentAttempt));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Halt the current attempt
|
||||
/// </summary>
|
||||
public void HaltAttempt(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
AttemptEnding = true;
|
||||
OnAttemptEnding?.Invoke(this, new AttemptEventArgs(CurrentAttempt));
|
||||
OnAttemptEnded?.Invoke(this, new AttemptEventArgs(CurrentAttempt));
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_scoreHandler = ScoreHandler.Instance;
|
||||
_levelSpawner = LevelSpawner.Instance;
|
||||
_playerHandler = PlayersHandler.Instance;
|
||||
_dataBearer = DataBearer.Instance;
|
||||
_tileSpawner = TileSpawner.Instance;
|
||||
|
||||
|
||||
_playerHandler.OnAllPlayersFinished += HaltAttempt_OnAllPlayersFinished;
|
||||
_playerHandler.OnPlayerInstanciated += CheckIfHumanPlayer_OnPlayerInstanciated;
|
||||
|
||||
difficultyMultiplier = _dataBearer.Rules.DifficultyMultiplier;
|
||||
raiseScoreOnDistance = _dataBearer.Rules.ScoreOnDistance;
|
||||
maxDistance = _dataBearer.Rules.MaxDistance;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Update()
|
||||
{
|
||||
FrameDistance = MapSpeed * Time.deltaTime;
|
||||
TotalDistance += FrameDistance;
|
||||
TimeAttemptDuration += Time.deltaTime;
|
||||
TickAttemptDuration += 1;
|
||||
tickCounter += 1;
|
||||
|
||||
if (tickCounter > 1000)
|
||||
{
|
||||
//Debug.Log("1000 TICK " + TimeAttemptDuration);
|
||||
tickCounter = 0;
|
||||
_dataBearer.RecordPlayersScore();
|
||||
}
|
||||
|
||||
|
||||
if(maxDistance != 0 && TotalDistance > maxDistance)
|
||||
{
|
||||
HaltAttempt("Ligne d'arrivée atteinte");
|
||||
}
|
||||
|
||||
if (raiseScoreOnDistance) RaiseScore();
|
||||
if (!MaxDifficultyReached) RaiseDifficulty();
|
||||
|
||||
if(maxDistance != 0 && !finishLineSpawned && maxDistance-TotalDistance < 20)
|
||||
{
|
||||
Instantiate(finishLine, new Vector3(maxDistance - TotalDistance - 3, 0, -1), finishLine.transform.rotation);
|
||||
finishLineSpawned = true;
|
||||
}
|
||||
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Escape))
|
||||
(IsPaused ? (Action)ResumeGame : PauseGame)();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
|
||||
private void Clean()
|
||||
{
|
||||
/*StopAllCoroutines();
|
||||
_playerHandler.OnAllPlayersFinished -= HaltAttempt_OnAllPlayersFinished;
|
||||
_playerHandler.OnPlayerInstanciated -= CheckIfHumanPlayer_OnPlayerInstanciated;*/
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
215
Scripts/GameHandlers/PlayersHandler.cs
Normal file
215
Scripts/GameHandlers/PlayersHandler.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using Assets.Scripts;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using static PlayersHandler;
|
||||
|
||||
public class PlayersHandler : SingletonMB<PlayersHandler>
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
[SerializeField] private GameObject playerPrefab;
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
public Dictionary<int, PlayerScript> Players { get; private set; } = new();
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
private ScoreHandler _scoreHandler;
|
||||
private GameHandler _gameHandler;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
/// <summary>
|
||||
/// Fires when a player is instanciated in the game
|
||||
/// </summary>
|
||||
public event EventHandler<PlayerEventArgs> OnPlayerInstanciated;
|
||||
/// <summary>
|
||||
/// Fires when a player have finished their attempt
|
||||
/// </summary>
|
||||
public event EventHandler<PlayerEventArgs> OnPlayerFinished;
|
||||
/// <summary>
|
||||
/// Fires when all players have finished their attempt
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> OnAllPlayersFinished;
|
||||
public class PlayerEventArgs : EventArgs
|
||||
{
|
||||
|
||||
public PlayerScript player;
|
||||
|
||||
public PlayerEventArgs(PlayerScript player)
|
||||
{
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
/// <summary>
|
||||
/// Remove a player from the game and fire a PlayerFinished event. Fire AllPlayerFinished event if needed
|
||||
/// </summary>
|
||||
/// <param name="playerId"></param>
|
||||
public void RemovePlayer(int playerId)
|
||||
{
|
||||
if (Players.TryGetValue(playerId, out PlayerScript player))
|
||||
{
|
||||
Players.Remove(playerId);
|
||||
if(!_gameHandler.AttemptEnding)
|
||||
OnPlayerFinished.Invoke(this, new PlayerEventArgs(player));
|
||||
player.Dispose();
|
||||
}
|
||||
|
||||
if(Players.Count == 0 && !_gameHandler.AttemptEnding)
|
||||
{
|
||||
OnAllPlayersFinished.Invoke(this, new EventArgs());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool InstanciatePlayer<T>(Vector3 position) where T : MonoBehaviour
|
||||
{
|
||||
|
||||
var player = SpawnPlayer(new Vector3(position.x, position.y, -1));
|
||||
|
||||
PlayerScript script = player.GetComponent<PlayerScript>();
|
||||
player.AddComponent<T>();
|
||||
Players.Add(script.Id, script);
|
||||
|
||||
DecoratePlayer(player);
|
||||
CreateScorePanel(script);
|
||||
|
||||
Debug.Log($"# Player \"{script.Name}\" instanciated !");
|
||||
OnPlayerInstanciated?.Invoke(this, new PlayerEventArgs(script));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
private GameObject SpawnPlayer(Vector3 position)
|
||||
{
|
||||
var player = Instantiate(playerPrefab, position, Quaternion.identity);
|
||||
var script = player.GetComponent<PlayerScript>();
|
||||
script.SetId(Players.Count);
|
||||
return player;
|
||||
}
|
||||
|
||||
private void CreateScorePanel(PlayerScript script)
|
||||
{
|
||||
_scoreHandler.AddScorePanel(script.Name, script.Id, script.Color);
|
||||
}
|
||||
|
||||
//private GameObject InstantiatePlayer(string playerName, Vector3 position)
|
||||
//{
|
||||
// incrementialId++;
|
||||
// var player = Instantiate(playerPrefab, position, Quaternion.identity);
|
||||
// var script = player.GetComponent<PlayerScript>();
|
||||
// script.SetName(playerName);
|
||||
// script.SetId(incrementialId);
|
||||
|
||||
// _scoreHandler.AddScorePanel(script.Name, script.Id, script.Color);
|
||||
|
||||
// Players.Add(script);
|
||||
// return player;
|
||||
//}
|
||||
|
||||
private void DecoratePlayer(GameObject player)
|
||||
{
|
||||
Transform child = player.transform.Find("sprite");
|
||||
PlayerScript script = player.GetComponent<PlayerScript>();
|
||||
var components = child.GetComponentsInChildren<SpriteRenderer>();
|
||||
var jetpackFront = child.transform.Find("JetpackFront").GetComponent<SpriteRenderer>();
|
||||
var jetpackBack = child.transform.Find("JetpackBack").GetComponent<SpriteRenderer>();
|
||||
|
||||
float alpha = _gameHandler.HaveHumanPlayer && !script.IsHuman ? 0.4f : 1.0f;
|
||||
|
||||
var scriptColor = script.Color!=null ? script.Color : new Color(255, 255, 255);
|
||||
scriptColor.a = alpha;
|
||||
foreach ( var component in components )
|
||||
{
|
||||
component.color = new Color(255, 255, 255, alpha);
|
||||
}
|
||||
|
||||
jetpackFront.color = scriptColor;
|
||||
jetpackBack.color = scriptColor;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_scoreHandler = ScoreHandler.Instance;
|
||||
_gameHandler = GameHandler.Instance;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//public void InstanciateOmnicient(Vector3 position)
|
||||
//{
|
||||
// var bot = SpawnPlayer(position);
|
||||
|
||||
// PlayerScript script = bot.GetComponent<PlayerScript>();
|
||||
// Players.Add(script.Id, script);
|
||||
// DecoratePlayer(bot);
|
||||
|
||||
// CreateScorePanel(script);
|
||||
|
||||
// OnPlayerInstanciated?.Invoke(this, new PlayerEventArgs(script));
|
||||
//}
|
||||
|
||||
//public void InstanciateObserver(Vector3 position)
|
||||
//{
|
||||
// var bot = SpawnPlayer(position);
|
||||
// PlayerScript script = bot.GetComponent<PlayerScript>();
|
||||
// Players.Add(script.Id, script);
|
||||
// DecoratePlayer(bot);
|
||||
|
||||
// CreateScorePanel(script);
|
||||
|
||||
// OnPlayerInstanciated?.Invoke(this, new PlayerEventArgs(script));
|
||||
//}
|
||||
|
||||
//public void InstanciateIterator(Vector3 position)
|
||||
//{
|
||||
// var bot = SpawnPlayer(position);
|
||||
// PlayerScript script = bot.GetComponent<PlayerScript>();
|
||||
// Players.Add(script.Id, script);
|
||||
// DecoratePlayer(bot);
|
||||
|
||||
// CreateScorePanel(script);
|
||||
|
||||
// OnPlayerInstanciated?.Invoke(this, new PlayerEventArgs(script));
|
||||
//}
|
||||
|
||||
//public void InstanciateHumanPlayer(Vector3 position)
|
||||
//{
|
||||
// Debug.Log("Instanciate Human");
|
||||
|
||||
// var humanPlayer = SpawnPlayer(new Vector3(position.x, position.y, -1));
|
||||
|
||||
// PlayerScript script = humanPlayer.GetComponent<PlayerScript>();
|
||||
// script.IsHuman = true;
|
||||
// humanPlayer.AddComponent<HumanPlayer>();
|
||||
// DecoratePlayer(humanPlayer);
|
||||
|
||||
// CreateScorePanel(script);
|
||||
|
||||
// Players.Add(script.Id, script);
|
||||
// OnPlayerInstanciated?.Invoke(this, new PlayerEventArgs(script));
|
||||
//}
|
201
Scripts/GameHandlers/ScoreHandler.cs
Normal file
201
Scripts/GameHandlers/ScoreHandler.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Assets.Scripts;
|
||||
using System;
|
||||
using static GameController;
|
||||
using static PlayersHandler;
|
||||
using static GameHandler;
|
||||
using System.Linq;
|
||||
|
||||
public class ScoreHandler : SingletonMB<ScoreHandler>
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
private Dictionary<int, PlayerScore> PlayersScores { get; set; }
|
||||
private Dictionary<int, PlayerScore> OuttedPlayers { get; set; }
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
[SerializeField] private GameObject ScorePanelPrefab;
|
||||
[SerializeField] private GameObject UiDocument;
|
||||
private GameController _gameController;
|
||||
private PlayersHandler _playersHandler;
|
||||
private GameHandler _gameHandler;
|
||||
private DataBearer _dataBearer;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
public event EventHandler<ScoreEventArgs> OnScoreReachingZero;
|
||||
|
||||
public class ScoreEventArgs : EventArgs
|
||||
{
|
||||
public int playerId;
|
||||
public ScoreEventArgs(int id)
|
||||
{
|
||||
playerId = id;
|
||||
}
|
||||
}
|
||||
internal void RemovePlayer_OnPlayerFinished(object sender, PlayerEventArgs args)
|
||||
{
|
||||
if (PlayersScores.TryGetValue(args.player.Id, out PlayerScore looser))
|
||||
{
|
||||
_dataBearer.RecordPlayerDistance(looser.PlayerName);
|
||||
_dataBearer.RecordPlayerScore(looser.PlayerId, looser.PlayerName);
|
||||
_dataBearer.RecordPlayerAttemptDuration(looser.PlayerName);
|
||||
|
||||
OuttedPlayers.Add(looser.PlayerId, looser);
|
||||
PlayersScores.Remove(looser.PlayerId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private void RemoveScores_OnAttemptEnded(object sender, AttemptEventArgs args)
|
||||
{
|
||||
List<int> keys;
|
||||
if (PlayersScores.Count > 0)
|
||||
{
|
||||
keys = new List<int>(PlayersScores.Keys);
|
||||
foreach(var key in keys)
|
||||
{
|
||||
_dataBearer.RecordPlayerDistance(PlayersScores[key].PlayerName);
|
||||
_dataBearer.RecordPlayerScore(key, PlayersScores[key].PlayerName);
|
||||
_dataBearer.RecordPlayerAttemptDuration(PlayersScores[key].PlayerName);
|
||||
|
||||
OuttedPlayers.Add(key, PlayersScores[key]);
|
||||
_playersHandler.RemovePlayer(key);
|
||||
}
|
||||
PlayersScores.Clear();
|
||||
}
|
||||
keys = new List<int>(OuttedPlayers.Keys);
|
||||
foreach (var key in keys)
|
||||
{
|
||||
_dataBearer.RecordPlayerFinalScore((int)OuttedPlayers[key].Score, OuttedPlayers[key].PlayerName);
|
||||
|
||||
|
||||
OuttedPlayers[key].ScorePanel.Dispose();
|
||||
}
|
||||
OuttedPlayers = new();
|
||||
PlayersScores = new();
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
|
||||
public void AddScorePanel(string playerName, int playerId)
|
||||
{
|
||||
var newScorePanel = Instantiate(ScorePanelPrefab, UiDocument.transform);
|
||||
var scoreScript = newScorePanel.GetComponent<ScorePannelScript>();
|
||||
scoreScript.SetPlayerName(playerName);
|
||||
PlayerScore newRecord = new PlayerScore(playerName, playerId, scoreScript);
|
||||
PlayersScores.Add(playerId, newRecord);
|
||||
}
|
||||
|
||||
public void AddScorePanel(string playerName, int playerId, Color playerColor)
|
||||
{
|
||||
var newScorePanel = Instantiate(ScorePanelPrefab, UiDocument.transform);
|
||||
var scoreScript = newScorePanel.GetComponent<ScorePannelScript>();
|
||||
scoreScript.SetColor(playerColor);
|
||||
scoreScript.SetPlayerName(playerName);
|
||||
PlayerScore newRecord = new PlayerScore(playerName, playerId, scoreScript);
|
||||
PlayersScores.Add(playerId, newRecord);
|
||||
}
|
||||
|
||||
public void SetScore(float score, int playerId)
|
||||
{
|
||||
if (PlayersScores.TryGetValue(playerId, out PlayerScore updatedScore))
|
||||
{
|
||||
updatedScore.Score = score;
|
||||
updatedScore.ScorePanel.SetScore(score);
|
||||
PlayersScores[playerId] = updatedScore;
|
||||
}
|
||||
|
||||
if ( score <= 0) //false &&
|
||||
{
|
||||
OnScoreReachingZero.Invoke(this, new ScoreEventArgs(playerId));
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToScore(float score, int playerId)
|
||||
{
|
||||
if (PlayersScores.TryGetValue(playerId, out PlayerScore updatedScore))
|
||||
{
|
||||
updatedScore.Score += score;
|
||||
SetScore(updatedScore.Score, playerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddScoreToAllAlivePlayers(float scoreToAdd)
|
||||
{
|
||||
var keys = new List<int>(PlayersScores.Keys);
|
||||
foreach (var key in keys)
|
||||
{
|
||||
AddToScore(scoreToAdd, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public float GetPlayerScore(int playerId)
|
||||
{
|
||||
return PlayersScores.TryGetValue(playerId, out PlayerScore pscore)
|
||||
? pscore.Score
|
||||
: OuttedPlayers.TryGetValue(playerId, out PlayerScore oscore)
|
||||
? oscore.Score
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_gameController = GameController.Instance;
|
||||
_playersHandler = PlayersHandler.Instance;
|
||||
_gameHandler = GameHandler.Instance;
|
||||
_dataBearer = DataBearer.Instance;
|
||||
|
||||
_playersHandler.OnPlayerFinished += RemovePlayer_OnPlayerFinished;
|
||||
_gameHandler.OnAttemptEnding += RemoveScores_OnAttemptEnded;
|
||||
|
||||
PlayersScores = new();
|
||||
OuttedPlayers = new();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
struct PlayerScore
|
||||
{
|
||||
|
||||
internal string PlayerName { get; set; }
|
||||
internal int PlayerId { get; set; }
|
||||
internal float Score { get; set; }
|
||||
internal ScorePannelScript ScorePanel { get; set; }
|
||||
public PlayerScore(string playerName, int playerId, ScorePannelScript scorePannel)
|
||||
{
|
||||
PlayerName = playerName;
|
||||
PlayerId = playerId;
|
||||
Score = 0f;
|
||||
ScorePanel = scorePannel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
#endregion
|
||||
#region EVENTS
|
||||
#endregion
|
||||
#region METHODS
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
#endregion
|
21
Scripts/GameObjectsScripts/BadCoinScript.cs
Normal file
21
Scripts/GameObjectsScripts/BadCoinScript.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Assets.Scripts;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class BadCoinScript : MonoBehaviour
|
||||
{
|
||||
[SerializeField] float SpawnChance = 1f;
|
||||
|
||||
private bool objectEnabled;
|
||||
private void Awake()
|
||||
{
|
||||
objectEnabled = DataBearer.Instance.Rules.MalusCoins && Random.value < SpawnChance;
|
||||
|
||||
if (!objectEnabled)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
31
Scripts/GameObjectsScripts/FinishLineScript.cs
Normal file
31
Scripts/GameObjectsScripts/FinishLineScript.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class FinishLineScript : MonoBehaviour
|
||||
{
|
||||
private GameHandler _gameHandler;
|
||||
// Start is called before the first frame update
|
||||
void Awake()
|
||||
{
|
||||
_gameHandler = GameHandler.Instance;
|
||||
_gameHandler.OnAttemptEnding += Destroy_OnAttemptEnding;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
gameObject.transform.position += new Vector3(-_gameHandler.FrameDistance, 0, 0);
|
||||
}
|
||||
|
||||
public void Destroy_OnAttemptEnding(object sender, EventArgs args)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
GameHandler.Instance.OnAttemptEnding -= Destroy_OnAttemptEnding;
|
||||
}
|
||||
}
|
22
Scripts/GameObjectsScripts/GoodCoinScript.cs
Normal file
22
Scripts/GameObjectsScripts/GoodCoinScript.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Assets.Scripts;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GoodCoinScript : MonoBehaviour
|
||||
{
|
||||
[SerializeField] float SpawningChance = 1f;
|
||||
|
||||
private bool objectEnabled;
|
||||
private void Awake()
|
||||
{
|
||||
objectEnabled = DataBearer.Instance.Rules.BonusCoins && Random.value < SpawningChance;
|
||||
|
||||
if (!objectEnabled)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
47
Scripts/GameObjectsScripts/LaserScript.cs
Normal file
47
Scripts/GameObjectsScripts/LaserScript.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Assets.Scripts;
|
||||
using UnityEngine;
|
||||
|
||||
public class CapsulePlacer : MonoBehaviour
|
||||
{
|
||||
public Transform objectA;
|
||||
public Transform objectB;
|
||||
private bool laserEnabled;
|
||||
private void Awake()
|
||||
{
|
||||
if(objectA == null || objectB == null)
|
||||
{
|
||||
laserEnabled = false;
|
||||
Debug.LogError("Les boules du laser ne sont pas définis.");
|
||||
}
|
||||
|
||||
laserEnabled = DataBearer.Instance.Rules.Lasers;
|
||||
if (!laserEnabled)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Vector2 positionA = objectA.position;
|
||||
Vector2 positionB = objectB.position;
|
||||
|
||||
// Calcul de la distance et mise à jour de l'échelle
|
||||
float distance = Vector2.Distance(positionA, positionB);
|
||||
Vector3 localScale = transform.localScale;
|
||||
localScale.y = distance / 2f;
|
||||
transform.localScale = localScale;
|
||||
|
||||
// Mise à jour de la position
|
||||
transform.position = (positionA + positionB) / 2f;
|
||||
|
||||
// Calcul de la direction et de l'angle
|
||||
Vector2 direction = positionB - positionA;
|
||||
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg + 90f;
|
||||
|
||||
// Mise à jour de la rotation
|
||||
transform.rotation = Quaternion.Euler(0f, 0f, angle);
|
||||
}
|
||||
}
|
77
Scripts/GameObjectsScripts/MissileAlertScript.cs
Normal file
77
Scripts/GameObjectsScripts/MissileAlertScript.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MissileAlertScript : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
private float blinkInterval = 0.2f;
|
||||
private bool isBlinking = false;
|
||||
private SpriteRenderer spriteRenderer;
|
||||
|
||||
private Vector3 position;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
private IEnumerator Blink()
|
||||
{
|
||||
isBlinking = true;
|
||||
while (isBlinking)
|
||||
{
|
||||
SetSpriteVisible(true);
|
||||
yield return new WaitForSeconds(blinkInterval);
|
||||
SetSpriteVisible(false);
|
||||
yield return new WaitForSeconds(blinkInterval);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSpriteVisible(bool isVisible)
|
||||
{
|
||||
spriteRenderer.enabled = isVisible;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
position = transform.position;
|
||||
spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
|
||||
var mainCamera = Camera.main;
|
||||
position.x = mainCamera.transform.position.x + mainCamera.orthographicSize * mainCamera.aspect - 1f;
|
||||
transform.position = position;
|
||||
|
||||
SetSpriteVisible(false);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (!isBlinking)
|
||||
{
|
||||
StartCoroutine(Blink());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (isBlinking)
|
||||
{
|
||||
StopCoroutine(Blink());
|
||||
SetSpriteVisible(false); // Assure que le sprite est invisible quand on arr<72>te le clignotement
|
||||
isBlinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
82
Scripts/GameObjectsScripts/MissileScript.cs
Normal file
82
Scripts/GameObjectsScripts/MissileScript.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class MissileScript : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
public int TargetId { get; set; }
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
[SerializeField] private float speed = 15.0f;
|
||||
[SerializeField] private GameObject explosion;
|
||||
private bool renderSprite;
|
||||
private GameHandler _gameHandler;
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
public void Explode()
|
||||
{
|
||||
StopParticles();
|
||||
if (renderSprite)
|
||||
{
|
||||
var rotation = transform.rotation;
|
||||
rotation.z = 180;
|
||||
Instantiate(explosion, transform.position, rotation);
|
||||
}
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
public void SetRenderSprite(bool render)
|
||||
{
|
||||
renderSprite = render;
|
||||
}
|
||||
|
||||
public void SetTarget(int id)
|
||||
{
|
||||
TargetId = id;
|
||||
}
|
||||
public void StopParticles()
|
||||
{
|
||||
if (transform.childCount == 0) return;
|
||||
var emit = transform?.GetChild(0);
|
||||
emit.parent = null;
|
||||
|
||||
emit.GetComponent<ParticleSystem>().Stop(true, ParticleSystemStopBehavior.StopEmitting);
|
||||
|
||||
// This finds the particleAnimator associated with the emitter and then
|
||||
// sets it to automatically delete itself when it runs out of particles
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
void Start()
|
||||
{
|
||||
_gameHandler = GameHandler.Instance;
|
||||
}
|
||||
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if(transform.position.x < -20)
|
||||
{
|
||||
StopParticles();
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
|
||||
}
|
||||
//Go up because up is the direction of the head of the missile, even if he goes left the player's POV
|
||||
transform.Translate(Vector3.up * (speed+_gameHandler.MapSpeed) * Time.deltaTime);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
106
Scripts/GameObjectsScripts/ObstaclePatternBehaviour.cs
Normal file
106
Scripts/GameObjectsScripts/ObstaclePatternBehaviour.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.MLAgents;
|
||||
using UnityEngine;
|
||||
|
||||
public class ObstaclePatternBehaviour : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameHandler gameHandler;
|
||||
private float gameObjectLength;
|
||||
private float gameSpeed;
|
||||
|
||||
|
||||
private GameHandler _gameHandler;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Awake()
|
||||
{
|
||||
_gameHandler = GameHandler.Instance;
|
||||
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
gameObjectLength = ComputeLengthRecursive(0.0f, gameObject.transform) - gameObject.transform.position.x;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
// move the obstacle depending on GameHandler's offset value
|
||||
gameObject.transform.position += new Vector3(-_gameHandler.FrameDistance, 0, 0);
|
||||
|
||||
//kill the obstacle if it reach the GameHandler's dead end value
|
||||
var position = gameObject.transform.position.x;
|
||||
var spawnerPosition = LevelSpawner.Instance.transform.position.x;
|
||||
|
||||
//Debug.Log("position : " + position+"\n"+"scale : " + gameObjectLength);
|
||||
|
||||
if(position < -gameObjectLength - spawnerPosition)
|
||||
{
|
||||
//Debug.Log("DESTROY");
|
||||
MonoBehaviour.Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private float ComputeLengthRecursive(float max, Transform @object)
|
||||
{
|
||||
foreach (Transform child in @object)
|
||||
{
|
||||
if(child.position.x > max)
|
||||
{
|
||||
max = child.position.x;
|
||||
}
|
||||
max = ComputeLengthRecursive(max, child);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
//private float ComputeLength()
|
||||
//{
|
||||
// Debug.Log("ComputeLength");
|
||||
// CenterAndChildCount centerAndChildCount = new();
|
||||
// centerAndChildCount = ComputeCenterRecursive(centerAndChildCount, gameObject.transform);
|
||||
|
||||
// Vector3 center = centerAndChildCount.center;
|
||||
// int childCount = centerAndChildCount.childCount;
|
||||
// center /= childCount; //center is average center of children
|
||||
|
||||
|
||||
// Bounds bounds = new Bounds(center, Vector3.zero);
|
||||
// bounds = ComputeBoundsRecursive(bounds, gameObject.transform);
|
||||
|
||||
// return bounds.size.x;
|
||||
|
||||
//}
|
||||
|
||||
//private CenterAndChildCount ComputeCenterRecursive(CenterAndChildCount centerAndChildCount, Transform @object)
|
||||
//{
|
||||
// foreach (Transform child in @object)
|
||||
// {
|
||||
// centerAndChildCount.center += child.gameObject.GetComponent<Renderer>().bounds.center;
|
||||
// centerAndChildCount.childCount++;
|
||||
// centerAndChildCount = ComputeCenterRecursive(centerAndChildCount, child);
|
||||
// }
|
||||
// return centerAndChildCount;
|
||||
//}
|
||||
|
||||
//private Bounds ComputeBoundsRecursive(Bounds bounds, Transform @object)
|
||||
//{
|
||||
// foreach (Transform child in @object)
|
||||
// {
|
||||
// ComputeBoundsRecursive(bounds, child);
|
||||
// bounds.Encapsulate(child.gameObject.GetComponent<Renderer>().bounds);
|
||||
// }
|
||||
// return bounds;
|
||||
//}
|
||||
|
||||
//private class CenterAndChildCount
|
||||
//{
|
||||
// public Vector3 center = Vector3.zero;
|
||||
// public int childCount = 0;
|
||||
//}
|
||||
|
||||
}
|
166
Scripts/GameObjectsScripts/PlayerScript.cs
Normal file
166
Scripts/GameObjectsScripts/PlayerScript.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using static ScoreHandler;
|
||||
|
||||
public class PlayerScript : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
public bool IsHuman { get; set; } = false;
|
||||
public string Name { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public Color Color { get; private set; } = new Color(255, 255, 255);
|
||||
|
||||
|
||||
public bool IsGrounded { get; private set; } = false;
|
||||
public bool IsFlying { get; private set; } = false;
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
private ScoreHandler _scoreHandler;
|
||||
private PlayersHandler _playersHandler;
|
||||
|
||||
public float jumpForce = 8f;
|
||||
private Rigidbody2D rb;
|
||||
public float maxVelocity = 8f;
|
||||
public float minVelocity = -8f;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
public event EventHandler<PrefabTouchedEventArgs> OnObstacleTouched;
|
||||
public event EventHandler<PrefabTouchedEventArgs> OnBonusTouched;
|
||||
|
||||
public class PrefabTouchedEventArgs : EventArgs
|
||||
{
|
||||
public GameObject objectTouched;
|
||||
public int playerId;
|
||||
public string playerName;
|
||||
|
||||
public PrefabTouchedEventArgs(GameObject objectTouched, int playerId, string playerName)
|
||||
{
|
||||
this.objectTouched = objectTouched;
|
||||
this.playerId = playerId;
|
||||
this.playerName = playerName;
|
||||
}
|
||||
}
|
||||
|
||||
private void Lose_OnScoreReachingZero(object sender, ScoreEventArgs args)
|
||||
{
|
||||
if(args.playerId == Id)
|
||||
_playersHandler.RemovePlayer(Id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
public void MoveVertically(sbyte direction,float custom_DeltaTime)
|
||||
{
|
||||
IsFlying=(direction>0);
|
||||
rb.AddForce(Vector2.up * (direction*jumpForce) * custom_DeltaTime);
|
||||
}
|
||||
|
||||
public void SetName(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
void Awake()
|
||||
{
|
||||
rb = GetComponent<Rigidbody2D>();
|
||||
rb.freezeRotation = true;
|
||||
_scoreHandler = ScoreHandler.Instance;
|
||||
_playersHandler = PlayersHandler.Instance;
|
||||
|
||||
_scoreHandler.OnScoreReachingZero += Lose_OnScoreReachingZero;
|
||||
}
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
// Vérifier si la collision concerne l'objet que vous souhaitez détecter
|
||||
|
||||
switch (other.tag)
|
||||
{
|
||||
case "Floor":
|
||||
IsGrounded = true;
|
||||
break;
|
||||
|
||||
case "Laser":
|
||||
OnObstacleTouched.Invoke(this, new PrefabTouchedEventArgs(other.gameObject, Id, Name));
|
||||
_scoreHandler.AddToScore(-200, Id);
|
||||
break;
|
||||
|
||||
case "GoodCoin":
|
||||
if (IsHuman)
|
||||
other.gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
OnBonusTouched.Invoke(this, new PrefabTouchedEventArgs(other.gameObject, Id, Name));
|
||||
_scoreHandler.AddToScore(50, Id);
|
||||
break;
|
||||
|
||||
case "BadCoin":
|
||||
if (IsHuman)
|
||||
other.gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
OnObstacleTouched.Invoke(this, new PrefabTouchedEventArgs(other.gameObject, Id, Name));
|
||||
_scoreHandler.AddToScore(-50, Id);
|
||||
break;
|
||||
|
||||
case "Missile":
|
||||
MissileScript missileScript = other.transform.GetComponent<MissileScript>();
|
||||
if (missileScript.TargetId == Id)
|
||||
{
|
||||
OnObstacleTouched.Invoke(this, new PrefabTouchedEventArgs(other.gameObject, Id, Name));
|
||||
other.GetComponent<MissileScript>().Explode();
|
||||
_scoreHandler.AddToScore(-500, Id);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerExit2D(Collider2D other)
|
||||
{
|
||||
if (other.CompareTag("Floor"))
|
||||
{
|
||||
IsGrounded = false;
|
||||
}
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
// Récupérer la vélocité actuelle du Rigidbody2D
|
||||
Vector2 currentVelocity = rb.velocity;
|
||||
|
||||
// Limiter la vélocité verticale
|
||||
float clampedVelocityY = Mathf.Clamp(currentVelocity.y, minVelocity, maxVelocity);
|
||||
rb.velocity = new Vector2(currentVelocity.x, clampedVelocityY);
|
||||
|
||||
// Appliquer une force constante vers le haut ou le bas en fonction de la touche enfoncée
|
||||
//float verticalForce = Input.GetButton("Jump") ? jumpForce : -jumpForce;
|
||||
//rb.AddForce(Vector2.up * verticalForce * Time.deltaTime);
|
||||
|
||||
// Effectuer le raycast pour vérifier si le joueur est au sol
|
||||
//RaycastHit2D hit = Physics2D.Raycast(rb.position, Vector2.down, 0.25f);
|
||||
//IsGrounded = hit.collider != null && hit.transform.CompareTag("Floor");
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
80
Scripts/GameObjectsScripts/ScorePannelScript.cs
Normal file
80
Scripts/GameObjectsScripts/ScorePannelScript.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
/// <summary>
|
||||
/// Instanciate a ScorePannel view on the UI. This class only serves as view and does not contain any game data and does not affect the game's work
|
||||
/// </summary>
|
||||
public class ScorePannelScript : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
[SerializeField] private VisualTreeAsset scorePannelTemplate; // R<>f<EFBFBD>rence au template UXML du ScorePannel
|
||||
private VisualElement scoreContainer; // Le VisualElement parent o<> ajouter le ScorePannel
|
||||
|
||||
private VisualElement root;
|
||||
private Label scoreLabel;
|
||||
private Label playerNameLabel;
|
||||
private VisualElement scorePanel;
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
public void SetPlayerName(string playerName)
|
||||
{
|
||||
playerNameLabel.text = playerName;
|
||||
}
|
||||
public void SetScore(float score)
|
||||
{
|
||||
scoreLabel.text = score.ToString("0");
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
scorePanel.style.backgroundColor = new StyleColor(new Color(color.r, color.g, color.b, 0.43f));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
scoreContainer.Remove(root);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
void OnEnable()
|
||||
{
|
||||
Debug.Log("SCORE Instanciatied");
|
||||
var uiDocument = GetComponentInParent<UIDocument>(); // Obtenir le composant UIDocument attach<63> <20> l'objet
|
||||
// V<>rifiez que les r<>f<EFBFBD>rences sont assign<67>es
|
||||
if (uiDocument == null || scorePannelTemplate == null)
|
||||
{
|
||||
Debug.LogError("UiDocument ou scorePannelTemplate n'est pas assign<67>.");
|
||||
return;
|
||||
}
|
||||
|
||||
var rootVisualElement = uiDocument.rootVisualElement;
|
||||
|
||||
// V<>rifiez que ScoresContainer existe dans l'arborescence de l'UI
|
||||
scoreContainer = rootVisualElement.Q<VisualElement>("ScoresContainer");
|
||||
if (scoreContainer == null)
|
||||
{
|
||||
Debug.LogError("ScoresContainer n'a pas <20>t<EFBFBD> trouv<75> dans le UXML.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Charger et instancier le ScorePannel
|
||||
root = scorePannelTemplate.CloneTree();
|
||||
scorePanel = root.Q<VisualElement>("panel");
|
||||
scoreLabel = root.Q<Label>("ScoreValue");
|
||||
playerNameLabel = root.Q<Label>("PlayerName");
|
||||
|
||||
scoreContainer.Add(root);
|
||||
root.AddToClassList("scorePanel");
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
104
Scripts/Helpers/AspectRatioPanel.cs
Normal file
104
Scripts/Helpers/AspectRatioPanel.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public class AspectRatioPanel : VisualElement
|
||||
{
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public new class UxmlFactory : UxmlFactory<AspectRatioPanel, UxmlTraits> { }
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public new class UxmlTraits : VisualElement.UxmlTraits
|
||||
{
|
||||
readonly UxmlIntAttributeDescription aspectRatioX = new() { name = "aspect-ratio-x", defaultValue = 16, restriction = new UxmlValueBounds { min = "1" } };
|
||||
readonly UxmlIntAttributeDescription aspectRatioY = new() { name = "aspect-ratio-y", defaultValue = 9, restriction = new UxmlValueBounds { min = "1" } };
|
||||
readonly UxmlIntAttributeDescription balanceX = new() { name = "balance-x", defaultValue = 50, restriction = new UxmlValueBounds { min = "0", max = "100" } };
|
||||
readonly UxmlIntAttributeDescription balanceY = new() { name = "balance-y", defaultValue = 50, restriction = new UxmlValueBounds { min = "0", max = "100" } };
|
||||
|
||||
|
||||
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
|
||||
{
|
||||
get { yield break; }
|
||||
}
|
||||
|
||||
|
||||
public override void Init(VisualElement visualElement, IUxmlAttributes attributes, CreationContext creationContext)
|
||||
{
|
||||
base.Init(visualElement, attributes, creationContext);
|
||||
var element = visualElement as AspectRatioPanel;
|
||||
if (element != null)
|
||||
{
|
||||
element.AspectRatioX = Mathf.Max(1, aspectRatioX.GetValueFromBag(attributes, creationContext));
|
||||
element.AspectRatioY = Mathf.Max(1, aspectRatioY.GetValueFromBag(attributes, creationContext));
|
||||
element.BalanceX = Mathf.Clamp(balanceX.GetValueFromBag(attributes, creationContext), 0, 100);
|
||||
element.BalanceY = Mathf.Clamp(balanceY.GetValueFromBag(attributes, creationContext), 0, 100);
|
||||
element.FitToParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int AspectRatioX { get; private set; } = 16;
|
||||
public int AspectRatioY { get; private set; } = 9;
|
||||
public int BalanceX { get; private set; } = 50;
|
||||
public int BalanceY { get; private set; } = 50;
|
||||
|
||||
|
||||
public AspectRatioPanel()
|
||||
{
|
||||
style.position = Position.Absolute;
|
||||
style.left = 0;
|
||||
style.top = 0;
|
||||
style.right = StyleKeyword.Undefined;
|
||||
style.bottom = StyleKeyword.Undefined;
|
||||
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelEvent);
|
||||
}
|
||||
|
||||
|
||||
void OnAttachToPanelEvent(AttachToPanelEvent e)
|
||||
{
|
||||
parent?.RegisterCallback<GeometryChangedEvent>(OnGeometryChangedEvent);
|
||||
FitToParent();
|
||||
}
|
||||
|
||||
|
||||
void OnGeometryChangedEvent(GeometryChangedEvent e)
|
||||
{
|
||||
FitToParent();
|
||||
}
|
||||
|
||||
|
||||
void FitToParent()
|
||||
{
|
||||
if (parent == null) return;
|
||||
var parentW = parent.resolvedStyle.width;
|
||||
var parentH = parent.resolvedStyle.height;
|
||||
if (float.IsNaN(parentW) || float.IsNaN(parentH)) return;
|
||||
|
||||
style.position = Position.Absolute;
|
||||
style.left = 0;
|
||||
style.top = 0;
|
||||
style.right = StyleKeyword.Undefined;
|
||||
style.bottom = StyleKeyword.Undefined;
|
||||
|
||||
if (AspectRatioX <= 0.0f || AspectRatioY <= 0.0f)
|
||||
{
|
||||
style.width = parentW;
|
||||
style.height = parentH;
|
||||
return;
|
||||
}
|
||||
|
||||
var ratio = Mathf.Min(parentW / AspectRatioX, parentH / AspectRatioY);
|
||||
var targetW = Mathf.Floor(AspectRatioX * ratio);
|
||||
var targetH = Mathf.Floor(AspectRatioY * ratio);
|
||||
style.width = targetW;
|
||||
style.height = targetH;
|
||||
|
||||
var marginX = parentW - targetW;
|
||||
var marginY = parentH - targetH;
|
||||
style.left = Mathf.Floor(marginX * BalanceX / 100.0f);
|
||||
style.top = Mathf.Floor(marginY * BalanceY / 100.0f);
|
||||
}
|
||||
}
|
84
Scripts/Helpers/LabelAutoFit.cs
Normal file
84
Scripts/Helpers/LabelAutoFit.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class LabelAutoFit : Label
|
||||
{
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public new class UxmlFactory : UxmlFactory<LabelAutoFit, UxmlTraits> { }
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public new class UxmlTraits : Label.UxmlTraits
|
||||
{
|
||||
readonly UxmlIntAttributeDescription minFontSize = new UxmlIntAttributeDescription
|
||||
{
|
||||
name = "min-font-size",
|
||||
defaultValue = 10,
|
||||
restriction = new UxmlValueBounds { min = "1" }
|
||||
};
|
||||
|
||||
readonly UxmlIntAttributeDescription maxFontSize = new UxmlIntAttributeDescription
|
||||
{
|
||||
name = "max-font-size",
|
||||
defaultValue = 200,
|
||||
restriction = new UxmlValueBounds { min = "1" }
|
||||
};
|
||||
|
||||
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription { get { yield break; } }
|
||||
|
||||
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
base.Init(ve, bag, cc);
|
||||
|
||||
LabelAutoFit instance = ve as LabelAutoFit;
|
||||
instance.minFontSize = Mathf.Max(minFontSize.GetValueFromBag(bag, cc), 1);
|
||||
instance.maxFontSize = Mathf.Max(maxFontSize.GetValueFromBag(bag, cc), 1);
|
||||
instance.RegisterCallback<GeometryChangedEvent>(instance.OnGeometryChanged);
|
||||
instance.style.fontSize = 1; // Triggers OnGeometryChanged callback
|
||||
}
|
||||
}
|
||||
|
||||
// Setting a limit of max text font refreshes from a single OnGeometryChanged to avoid repeating cycles in some extreme cases
|
||||
private const int MAX_FONT_REFRESHES = 2;
|
||||
|
||||
private int m_textRefreshes = 0;
|
||||
|
||||
public int minFontSize { get; set; }
|
||||
public int maxFontSize { get; set; }
|
||||
|
||||
// Call this if the font size does not update by just setting the text
|
||||
// Should probably wait till the end of frame to get the real font size, instead of using this method
|
||||
// Works well in OnRenderObject() too
|
||||
public void SetText(string text)
|
||||
{
|
||||
this.text = text;
|
||||
UpdateFontSize();
|
||||
}
|
||||
|
||||
private void OnGeometryChanged(GeometryChangedEvent evt)
|
||||
{
|
||||
UpdateFontSize();
|
||||
}
|
||||
|
||||
private void UpdateFontSize()
|
||||
{
|
||||
if (m_textRefreshes < MAX_FONT_REFRESHES)
|
||||
{
|
||||
Vector2 textSize = MeasureTextSize(text, float.MaxValue, MeasureMode.AtMost, float.MaxValue, MeasureMode.AtMost);
|
||||
float fontSize = Mathf.Max(style.fontSize.value.value, 1); // Unity can return a font size of 0 which would break the auto fit // Should probably wait till the end of frame to get the real font size
|
||||
float heightDictatedFontSize = Mathf.Abs(contentRect.height);
|
||||
float widthDictatedFontSize = Mathf.Abs(contentRect.width / textSize.x) * fontSize;
|
||||
float newFontSize = Mathf.FloorToInt(Mathf.Min(heightDictatedFontSize, widthDictatedFontSize));
|
||||
newFontSize = Mathf.Clamp(newFontSize, minFontSize, maxFontSize);
|
||||
if (Mathf.Abs(newFontSize - fontSize) > 1)
|
||||
{
|
||||
m_textRefreshes++;
|
||||
style.fontSize = new StyleLength(new Length(newFontSize));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_textRefreshes = 0;
|
||||
}
|
||||
}
|
||||
}
|
81
Scripts/MainMenuUI/GameUI.cs
Normal file
81
Scripts/MainMenuUI/GameUI.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class GameUI : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
private UIDocument _document;
|
||||
private Button _pauseButton;
|
||||
private Button _playButton;
|
||||
private Button _exitButton;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
private void OnPauseButton(ClickEvent e)
|
||||
{
|
||||
GameHandler.Instance.PauseGame();
|
||||
}
|
||||
private void OnPlayButton(ClickEvent e)
|
||||
{
|
||||
GameHandler.Instance.ResumeGame();
|
||||
}
|
||||
private void OnExitButton(ClickEvent e)
|
||||
{
|
||||
GameController.Instance.ExitToMenu("Retour au menu principal");
|
||||
}
|
||||
private void React_OnGamePaused(object sender, EventArgs e)
|
||||
{
|
||||
ChangeButtonsVisibility(true);
|
||||
}
|
||||
private void React_OnGameResumed(object sender, EventArgs e)
|
||||
{
|
||||
ChangeButtonsVisibility(false);
|
||||
}
|
||||
#endregion
|
||||
#region METHODS
|
||||
private void ChangeButtonsVisibility(bool isPaused)
|
||||
{
|
||||
if (isPaused)
|
||||
{
|
||||
_pauseButton.style.display = DisplayStyle.None;
|
||||
_playButton.style.display = DisplayStyle.Flex;
|
||||
_exitButton.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
else
|
||||
{
|
||||
_playButton.style.display = DisplayStyle.None;
|
||||
_exitButton.style.display = DisplayStyle.None;
|
||||
_pauseButton.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
private void Awake()
|
||||
{
|
||||
_document=GetComponent<UIDocument>();
|
||||
_pauseButton = _document.rootVisualElement.Q("PauseButton") as Button;
|
||||
_pauseButton.RegisterCallback<ClickEvent>(OnPauseButton);
|
||||
_playButton = _document.rootVisualElement.Q("PlayButton") as Button;
|
||||
_playButton.RegisterCallback<ClickEvent>(OnPlayButton);
|
||||
_exitButton = _document.rootVisualElement.Q("ExitButton") as Button;
|
||||
_exitButton.RegisterCallback<ClickEvent>(OnExitButton);
|
||||
|
||||
ChangeButtonsVisibility(false);
|
||||
|
||||
GameHandler.Instance.OnGamePaused += React_OnGamePaused;
|
||||
GameHandler.Instance.OnGameResumed += React_OnGameResumed;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
41
Scripts/MainMenuUI/HoverDescripionScript.cs
Normal file
41
Scripts/MainMenuUI/HoverDescripionScript.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using TMPro;
|
||||
|
||||
public class HoverDescriptionScript : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
[SerializeField] private string description; // La description à afficher
|
||||
private TextMeshProUGUI descriptionText; // Référence au TextMeshPro pour afficher la description
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Trouver l'objet Infobox dans la scène et obtenir le TextMeshPro
|
||||
GameObject infobox = GameObject.Find("Infobox");
|
||||
if (infobox != null)
|
||||
{
|
||||
descriptionText = infobox.GetComponentInChildren<TextMeshProUGUI>();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Infobox not found in the scene.");
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode appelée quand la souris entre dans le collider de l'objet
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (descriptionText != null)
|
||||
{
|
||||
descriptionText.text = description;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode appelée quand la souris sort du collider de l'objet
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
if (descriptionText != null)
|
||||
{
|
||||
descriptionText.text = "Survolez un element pour en avoir une description !";
|
||||
}
|
||||
}
|
||||
}
|
256
Scripts/MainMenuUI/MenuController.cs
Normal file
256
Scripts/MainMenuUI/MenuController.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
public class MenuController : MonoBehaviour
|
||||
{
|
||||
[Header("Play Button")]
|
||||
[SerializeField] Button playerButton;
|
||||
|
||||
[Header("Player Selection Settings")]
|
||||
[SerializeField] Toggle omnicientBotToggler = null;
|
||||
[SerializeField] Toggle observerBotToggler = null;
|
||||
[SerializeField] Toggle iteratorBotToggler = null;
|
||||
[SerializeField] Toggle humanPlayerToggler = null;
|
||||
|
||||
[Header("Level Settings")]
|
||||
[SerializeField] Toggle laserToggler = null;
|
||||
[SerializeField] Toggle missileToggler = null;
|
||||
[SerializeField] Toggle coinToggler = null;
|
||||
[SerializeField] Toggle badCoinToggler = null;
|
||||
[SerializeField] Toggle surviveScoreToggler = null;
|
||||
|
||||
[Header("Seed Settings")]
|
||||
[SerializeField] Toggle changeSeedToggler = null;
|
||||
[SerializeField] Toggle useDefaultSeedToggler = null;
|
||||
[SerializeField] TMP_InputField defaultSeedInputField = null;
|
||||
[SerializeField] TMP_InputField customSeedInputField = null;
|
||||
|
||||
[Header("Session Settings")]
|
||||
[SerializeField] Slider maxSpeedSlider = null;
|
||||
[SerializeField] Slider startSpeedSlider = null;
|
||||
[SerializeField] Slider difficultyMultiplyerSlider = null;
|
||||
[SerializeField] Toggle rushModeToggler = null;
|
||||
[SerializeField] TMP_InputField maxTryInputField = null;
|
||||
[SerializeField] TMP_InputField maxTimeInputField = null;
|
||||
[SerializeField] TMP_InputField maxDistanceInputField = null;
|
||||
|
||||
[Header("Menu Controller")]
|
||||
public string _statsScene;
|
||||
public string _playScene;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Time.timeScale = 1;
|
||||
SetMaxSpeed();
|
||||
SetStartSpeed();
|
||||
SetDifficultyMultiplyer();
|
||||
SetRushModeToggle();
|
||||
SetMaxTry();
|
||||
SetMaxTime();
|
||||
SetMaxDistance();
|
||||
SetChangeSeed();
|
||||
SetUseDefaultSeed();
|
||||
SetDefaultSeedValue();
|
||||
SetCustomSeedValue();
|
||||
SetLaserToggle();
|
||||
SetMissileToggle();
|
||||
SetCoinToggle();
|
||||
SetBadCoinToggle();
|
||||
SetSurviveScoreToggle();
|
||||
SetOmnicientBotSelected();
|
||||
SetObserverBotSelected();
|
||||
SetIteratorBotSelected();
|
||||
SetHumanPlayerSelected();
|
||||
}
|
||||
|
||||
public void StatsButtonClicked()
|
||||
{
|
||||
Debug.Log("=============================================");
|
||||
SceneManager.LoadScene(_statsScene);
|
||||
}
|
||||
public void PlayButtonClicked()
|
||||
{
|
||||
Debug.Log("=============================================");
|
||||
SceneManager.LoadScene(_playScene);
|
||||
}
|
||||
|
||||
void OnPlayerSelectionChanged()
|
||||
{
|
||||
bool omnicient = omnicientBotToggler.isOn;
|
||||
bool observer = observerBotToggler.isOn;
|
||||
bool iterator = iteratorBotToggler.isOn;
|
||||
bool human = humanPlayerToggler.isOn;
|
||||
|
||||
playerButton.interactable = (omnicient || observer || iterator || human);
|
||||
}
|
||||
|
||||
public void QuitButtonClicked()
|
||||
{
|
||||
Debug.Log("Game quitting");
|
||||
Application.Quit();
|
||||
}
|
||||
|
||||
// Session Rules
|
||||
public void SetMaxSpeed()
|
||||
{
|
||||
float speed = maxSpeedSlider.value;
|
||||
PlayerPrefs.SetFloat(Settings.MaxSpeedSettingValue, speed);
|
||||
Debug.Log($"Game's max speed is set to {speed}");
|
||||
}
|
||||
public void SetStartSpeed()
|
||||
{
|
||||
float speed = startSpeedSlider.value;
|
||||
PlayerPrefs.SetFloat(Settings.StartSpeedSettingValue, speed);
|
||||
Debug.Log($"Game's starting speed is set to {speed}");
|
||||
}
|
||||
public void SetDifficultyMultiplyer()
|
||||
{
|
||||
float value = difficultyMultiplyerSlider.value;
|
||||
PlayerPrefs.SetFloat(Settings.DifficultyMultiplierSettingValue, value);
|
||||
Debug.Log($"Game's difficulty multiplyer is set to {value}");
|
||||
}
|
||||
public void SetRushModeToggle()
|
||||
{
|
||||
bool toggle = rushModeToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.RushModeSettingToggle, toggle.ToString());
|
||||
Debug.Log($"Rush Mode has been toggeled to {toggle}");
|
||||
}
|
||||
public void SetMaxTry()
|
||||
{
|
||||
int value = 0;
|
||||
string text = maxTryInputField.text;
|
||||
if (text != "")
|
||||
{
|
||||
value = int.Parse(text);
|
||||
}
|
||||
PlayerPrefs.SetInt(Settings.MaxTrySettingValue, value);
|
||||
Debug.Log($"Game's maximum try count is set to {value}");
|
||||
}
|
||||
public void SetMaxTime()
|
||||
{
|
||||
int seconds = 0;
|
||||
string text = maxTimeInputField.text;
|
||||
if (text != "")
|
||||
{
|
||||
seconds = int.Parse(text);
|
||||
}
|
||||
PlayerPrefs.SetInt(Settings.MaxTimeSettingValue, seconds);
|
||||
Debug.Log($"Game's session maximum time is set to {seconds} seconds");
|
||||
}
|
||||
public void SetMaxDistance()
|
||||
{
|
||||
int distance = 0;
|
||||
string text = maxDistanceInputField.text;
|
||||
if (text != "")
|
||||
{
|
||||
distance = int.Parse(text);
|
||||
}
|
||||
PlayerPrefs.SetFloat(Settings.MaxDistanceSettingValue, distance);
|
||||
Debug.Log($"Level's max distance is set to {distance} units");
|
||||
}
|
||||
|
||||
// Seed Rules
|
||||
public void SetChangeSeed()
|
||||
{
|
||||
bool toggle = changeSeedToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.ChangeSeedSetting, toggle.ToString());
|
||||
Debug.Log($"Changing seed for each level is set to {toggle}");
|
||||
}
|
||||
public void SetUseDefaultSeed()
|
||||
{
|
||||
bool toggle = useDefaultSeedToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.UseDefaultSeedSetting, toggle.ToString());
|
||||
Debug.Log($"Usign default seed is set to {toggle}");
|
||||
}
|
||||
public void SetDefaultSeedValue()
|
||||
{
|
||||
int value = 0;
|
||||
string text = defaultSeedInputField.text;
|
||||
if(text != "")
|
||||
{
|
||||
value = int.Parse(text);
|
||||
}
|
||||
PlayerPrefs.SetInt(Settings.DefaultSeedSettingValue, value);
|
||||
Debug.Log($"Default seed has been set to {value}");
|
||||
}
|
||||
public void SetCustomSeedValue()
|
||||
{
|
||||
int value = 0;
|
||||
string text = customSeedInputField.text;
|
||||
if (text != "")
|
||||
{
|
||||
value = int.Parse(text);
|
||||
}
|
||||
PlayerPrefs.SetInt(Settings.CustomSeedSettingValue, value);
|
||||
Debug.Log($"Custom seed has been set to {value}");
|
||||
}
|
||||
|
||||
|
||||
// Level Rules
|
||||
public void SetLaserToggle()
|
||||
{
|
||||
bool toggle = laserToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.LaserSettingToggle, toggle.ToString());
|
||||
Debug.Log($"Laser have been toggeled to {toggle}");
|
||||
}
|
||||
public void SetMissileToggle()
|
||||
{
|
||||
bool toggle = missileToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.MissileSettingToggle, toggle.ToString());
|
||||
Debug.Log($"Missiles have been toggeled to {toggle}");
|
||||
}
|
||||
public void SetCoinToggle()
|
||||
{
|
||||
bool toggle = coinToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.CoinSettingToggle, toggle.ToString());
|
||||
Debug.Log($"Coins have been toggeled to {toggle}");
|
||||
}
|
||||
public void SetBadCoinToggle()
|
||||
{
|
||||
bool toggle = badCoinToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.BadCoinSettingToggle, toggle.ToString());
|
||||
Debug.Log($"Bad Coins have been toggeled to {toggle}");
|
||||
}
|
||||
public void SetSurviveScoreToggle()
|
||||
{
|
||||
bool toggle = surviveScoreToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.SurviveScoreSettingToggle, toggle.ToString());
|
||||
Debug.Log($"Increasing score with surviving time has been toggeled to {toggle}");
|
||||
}
|
||||
|
||||
// Player Selection
|
||||
public void SetOmnicientBotSelected()
|
||||
{
|
||||
bool toggle = omnicientBotToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.OmnicientBotSelected, toggle.ToString());
|
||||
OnPlayerSelectionChanged();
|
||||
Debug.Log($"Omnicient bot selected has been set to {toggle}");
|
||||
}
|
||||
public void SetObserverBotSelected()
|
||||
{
|
||||
bool toggle = observerBotToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.ObserverBotSelected, toggle.ToString());
|
||||
OnPlayerSelectionChanged();
|
||||
Debug.Log($"Observer bot selected has been set to {toggle}");
|
||||
}
|
||||
public void SetIteratorBotSelected()
|
||||
{
|
||||
bool toggle = iteratorBotToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.IteratorBotSelected, toggle.ToString());
|
||||
OnPlayerSelectionChanged();
|
||||
Debug.Log($"Iterator bot selected has been set to {toggle}");
|
||||
}
|
||||
public void SetHumanPlayerSelected()
|
||||
{
|
||||
bool toggle = humanPlayerToggler.isOn;
|
||||
PlayerPrefs.SetString(Settings.HumanPlayerSelected, toggle.ToString());
|
||||
OnPlayerSelectionChanged();
|
||||
Debug.Log($"Human player selected has been set to {toggle}");
|
||||
}
|
||||
|
||||
}
|
20
Scripts/MainMenuUI/PlayButtonBehaviour.cs
Normal file
20
Scripts/MainMenuUI/PlayButtonBehaviour.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class PlayButtonBehaviour : MonoBehaviour
|
||||
{
|
||||
[Header("Player Selection Buttons")]
|
||||
[SerializeField] Toggle omnicientBot;
|
||||
[SerializeField] Toggle observerBot;
|
||||
[SerializeField] Toggle iteratorBot;
|
||||
[SerializeField] Toggle humanPlayer;
|
||||
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
43
Scripts/MainMenuUI/ScrollerBehavior.cs
Normal file
43
Scripts/MainMenuUI/ScrollerBehavior.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class ScrollerBehavior : MonoBehaviour
|
||||
{
|
||||
|
||||
[SerializeField] TMP_Text sliderValue = null;
|
||||
[SerializeField] Slider slider = null;
|
||||
[SerializeField] Slider intricatedSlider = null;
|
||||
[SerializeField] bool canBeSuperiorToIntricated = false;
|
||||
[SerializeField] bool canBeInferiorToIntricated = false;
|
||||
|
||||
float intricatedValue = 0.0f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
OnIntricatedValueChanged();
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
public void OnValueChanged()
|
||||
{
|
||||
float value = slider.value;
|
||||
if(intricatedSlider != null)
|
||||
{
|
||||
if ((!canBeSuperiorToIntricated && value >= intricatedValue) || (!canBeInferiorToIntricated && value <= intricatedValue))
|
||||
{
|
||||
slider.value = intricatedValue;
|
||||
}
|
||||
}
|
||||
sliderValue.text = slider.value.ToString("0.0");
|
||||
}
|
||||
|
||||
// Call this method when an intricated slider change its value
|
||||
public void OnIntricatedValueChanged()
|
||||
{
|
||||
if(intricatedSlider != null)
|
||||
intricatedValue = intricatedSlider.value;
|
||||
}
|
||||
}
|
25
Scripts/MainMenuUI/ScrollingTexture.cs
Normal file
25
Scripts/MainMenuUI/ScrollingTexture.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
public class ScrollingTexture : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float scrollSpeedX;
|
||||
[SerializeField] private float scrollSpeedY;
|
||||
private CanvasRenderer canvasRenderer;
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
canvasRenderer = GetComponent<CanvasRenderer>();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
Vector2 textureOffset = new Vector2(Time.realtimeSinceStartup * scrollSpeedX, Time.realtimeSinceStartup * scrollSpeedY);
|
||||
|
||||
if(canvasRenderer.GetMaterial() != null) {
|
||||
canvasRenderer.GetMaterial().mainTextureOffset = textureOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
Scripts/Objects/GameState.cs
Normal file
11
Scripts/Objects/GameState.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public struct GameState
|
||||
{
|
||||
public List<int> AlivePlayers { get; set; }
|
||||
public float CurrentDifficultyMultiplier { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
10
Scripts/Objects/ScoreTime.cs
Normal file
10
Scripts/Objects/ScoreTime.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class GenericVector<TX, TY>
|
||||
{
|
||||
public TX X { get; set; }
|
||||
public TY Y { get; set; }
|
||||
}
|
||||
|
||||
|
92
Scripts/Objects/SessionData.cs
Normal file
92
Scripts/Objects/SessionData.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SessionData
|
||||
{
|
||||
public DateTime Date { get; set; } //
|
||||
public int SessionNumber { get; set; }
|
||||
public double SessionTime { get; set; } //
|
||||
|
||||
public Players Players { get; set; } = new(); //
|
||||
public Rules Rules { get; set; } = new(); //
|
||||
public List<Attempt> Attempts { get;
|
||||
set; }
|
||||
= new();
|
||||
public List<RegisteredPlayer> RegisteredPlayers { get; set; } = new(); //
|
||||
}
|
||||
|
||||
public class Players
|
||||
{
|
||||
public bool OmnicientBot { get; set; }
|
||||
public bool ObserverBot { get; set; }
|
||||
public bool IteratorBot { get; set; }
|
||||
public bool Human { get; set; }
|
||||
} //
|
||||
|
||||
public class RegisteredPlayer
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Id { get; set; }
|
||||
public bool Human { get; set; }
|
||||
} //
|
||||
|
||||
public class Rules
|
||||
{
|
||||
public bool Lasers { get; set; }
|
||||
public bool Missiles { get; set; }
|
||||
public bool BonusCoins { get; set; }
|
||||
public bool MalusCoins { get; set; }
|
||||
public bool ScoreOnDistance { get; set; }
|
||||
public bool ChangeSeedEachTry { get; set; }
|
||||
public bool UsesDefaultSeed { get; set; }
|
||||
public int MaxAttempts { get; set; }
|
||||
public int MaxSessionTime { get; set; }
|
||||
public float MaxDistance { get; set; }
|
||||
public float MaxSpeed { get; set; }
|
||||
public float StartSpeed { get; set; }
|
||||
public float DifficultyMultiplier { get; set; }
|
||||
public bool RushMode { get; set; }
|
||||
} //
|
||||
|
||||
public class Attempt
|
||||
{
|
||||
public int AttemptNumber { get; set; } //
|
||||
public int Seed { get; set; } //
|
||||
public Dictionary<string, PlayerAttempt> PlayersAttempts { get; set; } = new();
|
||||
public List<LevelPrefab> Level { get; set; } = new(); //
|
||||
}
|
||||
|
||||
public class PlayerAttempt
|
||||
{
|
||||
public string PlayerName { get; set; } //
|
||||
public int FinalScore { get; set; } //
|
||||
public int Distance { get; set; } //
|
||||
public int AttemptDurationTicks { get; set; } //
|
||||
public double AttemptDurationSeconds { get; set; } //
|
||||
public int TimeTouchingBorder { get; set; }
|
||||
|
||||
public List<GenericVector<int, int>> PlayerScoresOverTicksTime { get; set; } = new(); //
|
||||
public List<TouchedGameObject> BonusTouched { get; set; } = new(); //
|
||||
public List<TouchedGameObject> ObstaclesTouched { get; set; } = new(); //
|
||||
|
||||
}
|
||||
|
||||
public class TouchedGameObject //
|
||||
{
|
||||
public string ObjectTypeName { get; set; }
|
||||
public string PrefabName { get; set; }
|
||||
public string FullObjectName { get; set; }
|
||||
public float GameSpeed { get; set; }
|
||||
public int TickTimeWhenTouched { get; set; }
|
||||
}
|
||||
|
||||
public class LevelPrefab
|
||||
{
|
||||
public string PrefabName { get; set; }
|
||||
public int PrefabNumber { get; set; }
|
||||
public int TickTimeWhenTouched { get; set; }
|
||||
|
||||
} //
|
||||
|
||||
|
||||
|
33
Scripts/Objects/Settings.cs
Normal file
33
Scripts/Objects/Settings.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public static class Settings
|
||||
{
|
||||
public const string MaxSpeedSettingValue = "MaxSpeedSettingValue";
|
||||
public const string StartSpeedSettingValue = "StartSpeedSettingValue";
|
||||
public const string DifficultyMultiplierSettingValue = "DifficultyMultiplyerSettingValue";
|
||||
|
||||
public const string RushModeSettingToggle = "RushModeSettingToggle";
|
||||
|
||||
public const string MaxTrySettingValue = "MaxTrySettingValue";
|
||||
public const string MaxTimeSettingValue = "MaxTimeSettingValue";
|
||||
public const string MaxDistanceSettingValue = "MaxDistanceSettingValue";
|
||||
|
||||
public const string LaserSettingToggle = "LaserSettingToggle";
|
||||
public const string MissileSettingToggle = "MissileSettingToggle";
|
||||
public const string CoinSettingToggle = "CoinSettingToggle";
|
||||
public const string BadCoinSettingToggle = "BadCoinSettingToggle";
|
||||
public const string SurviveScoreSettingToggle = "SurviveScoreSettingToggle";
|
||||
|
||||
public const string ChangeSeedSetting = "ChangeSeedSetting";
|
||||
public const string UseDefaultSeedSetting = "UseDefaultSeedSetting";
|
||||
public const string DefaultSeedSettingValue = "DefaultSeedSettingValue";
|
||||
public const string CustomSeedSettingValue = "CustomSeedSettingValue";
|
||||
|
||||
public const string OmnicientBotSelected = "OmnicientBotSelected";
|
||||
public const string ObserverBotSelected = "ObserverBotSelected";
|
||||
public const string IteratorBotSelected = "IteratorBotSelected";
|
||||
public const string HumanPlayerSelected = "HumanPlayerSelected";
|
||||
|
||||
}
|
24
Scripts/PlayerBehaviourScripts/HumanPlayerBehaviour.cs
Normal file
24
Scripts/PlayerBehaviourScripts/HumanPlayerBehaviour.cs
Normal 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";
|
||||
}
|
||||
}
|
78
Scripts/PlayerBehaviourScripts/Iterator/IteratorBehaviour.cs
Normal file
78
Scripts/PlayerBehaviourScripts/Iterator/IteratorBehaviour.cs
Normal 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;
|
||||
}
|
||||
}
|
110
Scripts/PlayerBehaviourScripts/Observer/ObserverAi.cs
Normal file
110
Scripts/PlayerBehaviourScripts/Observer/ObserverAi.cs
Normal 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
|
||||
|
||||
}
|
60
Scripts/PlayerBehaviourScripts/Observer/ObserverBehaviour.cs
Normal file
60
Scripts/PlayerBehaviourScripts/Observer/ObserverBehaviour.cs
Normal 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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
47
Scripts/PlayerBehaviourScripts/PlayerBehaviour.cs
Normal file
47
Scripts/PlayerBehaviourScripts/PlayerBehaviour.cs
Normal 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);
|
||||
}
|
||||
}
|
103
Scripts/PlayerBehaviourScripts/SensorsScript.cs
Normal file
103
Scripts/PlayerBehaviourScripts/SensorsScript.cs
Normal 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;
|
||||
}
|
2
Scripts/README.md
Normal file
2
Scripts/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Ce dossier regroupe l'ensemble des scripts du projet.
|
||||
Un diagramme de classe complet sera réalisé avec le rapport.
|
54
Scripts/SingletonMB.cs
Normal file
54
Scripts/SingletonMB.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.Scripts
|
||||
{
|
||||
public class SingletonMB<T> : MonoBehaviour where T : SingletonMB<T>
|
||||
{
|
||||
private static T instance;
|
||||
private static readonly object lockObject = new object();
|
||||
protected static bool Instantiated { get; private set; } = false;
|
||||
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
//lock (lockObject)
|
||||
//{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = FindObjectOfType<T>();
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
GameObject obj = new GameObject();
|
||||
obj.name = typeof(T).Name;
|
||||
instance = obj.AddComponent<T>();
|
||||
Instantiated = true;
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
Debug.Log($"{typeof(T).Name} singleton component Loaded");
|
||||
//lock (lockObject)
|
||||
//{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = this as T;
|
||||
// DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else if (instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instantiated = true;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
162
Scripts/Spawners/LevelSpawner.cs
Normal file
162
Scripts/Spawners/LevelSpawner.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using Assets.Scripts;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using static GameHandler;
|
||||
|
||||
public class LevelSpawner : SingletonMB<LevelSpawner>
|
||||
{
|
||||
|
||||
#region PROPERTIES
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
private GameHandler _gameHandler;
|
||||
|
||||
|
||||
[SerializeField] private GameObject[] patternsPrefabs;
|
||||
[SerializeField] private Transform levelSpawner;
|
||||
[SerializeField] private float patternInterval;
|
||||
[SerializeField] private GameObject PlayersContainer;
|
||||
[SerializeField] private GameObject missilePrefab;
|
||||
[SerializeField] private GameObject missileAlertPrefab;
|
||||
[SerializeField] private float dangerMinX = -25f;
|
||||
|
||||
private List<MissileAlertInfo> missileAlertList = new List<MissileAlertInfo>();
|
||||
private List<Transform> spawnedGameElements = new List<Transform>();
|
||||
private GameObject prefabParent;
|
||||
private float patternLength;
|
||||
private ObstaclePatternBehaviour lastSpawnedPattern;
|
||||
private float rewardValue = 0f;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
public event EventHandler<PrefabSpawnedEventArgs> OnPrefabSpawned;
|
||||
|
||||
|
||||
public class PrefabSpawnedEventArgs : EventArgs
|
||||
{
|
||||
public ObstaclePatternBehaviour pattern;
|
||||
public PrefabSpawnedEventArgs(ObstaclePatternBehaviour pattern)
|
||||
{
|
||||
this.pattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetLevel_OnAttemptEnding(object sender, AttemptEventArgs e)
|
||||
{
|
||||
foreach (Transform gameElement in spawnedGameElements)
|
||||
{
|
||||
if (gameElement != null)
|
||||
{
|
||||
Destroy(gameElement.gameObject);
|
||||
}
|
||||
}
|
||||
if(lastSpawnedPattern)Destroy(lastSpawnedPattern.gameObject);
|
||||
lastSpawnedPattern = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
void PrefabSpawnerBehaviour()
|
||||
{
|
||||
if (lastSpawnedPattern == null)
|
||||
{
|
||||
SpawnObstacle();
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnObstacle()
|
||||
{
|
||||
GameObject obstacleToSpawn = patternsPrefabs[UnityEngine.Random.Range(0, patternsPrefabs.Length)];
|
||||
patternLength = obstacleToSpawn.transform.lossyScale.x;
|
||||
lastSpawnedPattern = Instantiate(obstacleToSpawn, transform.position, Quaternion.identity, prefabParent.transform)
|
||||
.GetComponent<ObstaclePatternBehaviour>();
|
||||
|
||||
OnPrefabSpawned?.Invoke(this, new PrefabSpawnedEventArgs(lastSpawnedPattern));
|
||||
}
|
||||
|
||||
//IEnumerator SpawnMissileAfterDelay(GameObject missileAlert, GameObject player)
|
||||
//{
|
||||
// yield return new WaitForSeconds(3f);
|
||||
// Vector3 missileSpawnPosition = missileAlert.transform.position + new Vector3(2.5f, 0, 0);
|
||||
// Destroy(missileAlert);
|
||||
// GameObject newMissile = Instantiate(missilePrefab, missileSpawnPosition, Quaternion.identity, prefabParent.transform);
|
||||
// MissileScript missileScript = newMissile.GetComponent<MissileScript>();
|
||||
// missileScript.Target = player;
|
||||
// spawnedGameElements.Add(newMissile.transform);
|
||||
//}
|
||||
|
||||
private void RemoveExpiredGameElements()
|
||||
{
|
||||
List<Transform> gameElementToRemove = new List<Transform>();
|
||||
|
||||
foreach (Transform gameElementTransform in spawnedGameElements)
|
||||
{
|
||||
if (gameElementTransform == null)
|
||||
{
|
||||
gameElementToRemove.Add(gameElementTransform);
|
||||
continue;
|
||||
}
|
||||
if (gameElementTransform.position.x < dangerMinX)
|
||||
{
|
||||
gameElementToRemove.Add(gameElementTransform);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Transform gameElement in gameElementToRemove)
|
||||
{
|
||||
if (gameElement != null)
|
||||
{
|
||||
Destroy(gameElement.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private void UpdateMissileAlertPositions()
|
||||
//{
|
||||
// missileAlertList.RemoveAll(item => item.alertTransform == null);
|
||||
// foreach (MissileAlertInfo Element in missileAlertList)
|
||||
// {
|
||||
// Vector3 newPosition = new Vector3(Element.alertTransform.position.x, Element.player.transform.position.y + 0.544f, 0);
|
||||
// Element.alertTransform.position = newPosition;
|
||||
// }
|
||||
//}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
void Start()
|
||||
{
|
||||
prefabParent = GameObject.Find("prefab");
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
_gameHandler = GameHandler.Instance;
|
||||
|
||||
_gameHandler.OnAttemptEnding += ResetLevel_OnAttemptEnding;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameController.Instance.IsExiting)
|
||||
{
|
||||
PrefabSpawnerBehaviour();
|
||||
RemoveExpiredGameElements();
|
||||
|
||||
}
|
||||
//UpdateMissileAlertPositions();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public struct MissileAlertInfo
|
||||
{
|
||||
public Transform alertTransform;
|
||||
public GameObject player;
|
||||
}
|
||||
|
||||
}
|
120
Scripts/Spawners/MissileSpawnerScript.cs
Normal file
120
Scripts/Spawners/MissileSpawnerScript.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using Assets.Scripts;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using static LevelSpawner;
|
||||
|
||||
public class MissileSpawnerScript : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
public float alertDuration = 5f;
|
||||
private int baseCountdown = 2;
|
||||
private int countdown = 0;
|
||||
|
||||
private bool renderSprite;
|
||||
private MissileAlertScript missileAlertScript;
|
||||
private PlayerScript playerScript;
|
||||
|
||||
private GameHandler _gameHandler;
|
||||
private DataBearer _dataBearer;
|
||||
private PlayersHandler _playersHandler;
|
||||
private LevelSpawner _leverSpawner;
|
||||
|
||||
[SerializeField] private GameObject missileAlertRef;
|
||||
[SerializeField] private GameObject missilePrefab;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
public event EventHandler<MissileEventArgs> OnMissileAlert;
|
||||
public event EventHandler<MissileEventArgs> OnMissileLaunched;
|
||||
|
||||
public class MissileEventArgs : EventArgs
|
||||
{
|
||||
//todo : eventContent
|
||||
}
|
||||
|
||||
private void MissileLaunchCountdown_OnPrefab(object sender, PrefabSpawnedEventArgs args)
|
||||
{
|
||||
if (countdown == baseCountdown)
|
||||
{
|
||||
StartCoroutine(MissileLaunchSequence());
|
||||
countdown = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
countdown++;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
private IEnumerator MissileLaunchSequence()
|
||||
{
|
||||
|
||||
if(renderSprite)
|
||||
missileAlertScript.enabled = true;
|
||||
|
||||
yield return new WaitForSeconds(alertDuration);
|
||||
missileAlertScript.enabled = false;
|
||||
SpawnMissile();
|
||||
|
||||
}
|
||||
private void SpawnMissile()
|
||||
{
|
||||
var position = new Vector3(20, transform.position.y, -2);
|
||||
var instance = Instantiate(missilePrefab, position, missilePrefab.transform.rotation);
|
||||
instance.GetComponent<MissileScript>().SetTarget(playerScript.Id);
|
||||
instance.GetComponent<MissileScript>().SetRenderSprite(renderSprite);
|
||||
|
||||
if (!renderSprite)
|
||||
{
|
||||
DestroyImmediate(instance.GetComponent<SpriteRenderer>(), true);
|
||||
instance.GetComponent<MissileScript>().StopParticles();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
protected void Awake()
|
||||
{
|
||||
|
||||
_dataBearer = DataBearer.Instance;
|
||||
_gameHandler = GameHandler.Instance;
|
||||
_playersHandler = PlayersHandler.Instance;
|
||||
_leverSpawner = LevelSpawner.Instance;
|
||||
|
||||
if (!_dataBearer.Rules.Missiles)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
_leverSpawner.OnPrefabSpawned += MissileLaunchCountdown_OnPrefab;
|
||||
|
||||
missileAlertScript = missileAlertRef.GetComponent<MissileAlertScript>();
|
||||
playerScript = GetComponentInParent<PlayerScript>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
renderSprite = !(_gameHandler.HaveHumanPlayer && !playerScript.IsHuman); // false if game has human and script is not human
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
|
||||
private void Clean()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
|
||||
LevelSpawner.Instance.OnPrefabSpawned -= MissileLaunchCountdown_OnPrefab;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
125
Scripts/Spawners/TileSpawner.cs
Normal file
125
Scripts/Spawners/TileSpawner.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using Assets.Scripts;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using static GameHandler;
|
||||
|
||||
public class TileSpawner : SingletonMB<TileSpawner>
|
||||
{
|
||||
#region PROPERTIES
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
private GameHandler _gameHandler;
|
||||
|
||||
[SerializeField] private int maxTile = 6;
|
||||
[SerializeField] private GameObject tilePrefab;
|
||||
[SerializeField] private float tileLength = 15f;
|
||||
[SerializeField] private float tileMinX = 15f;
|
||||
|
||||
private List<Transform> tileList = new List<Transform>();
|
||||
|
||||
private GameObject tilesParent;
|
||||
private bool attemptStarted;
|
||||
private float startPositionX;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
private void StartAttempt_OnAttemptStarted(object sender, AttemptEventArgs args)
|
||||
{
|
||||
attemptStarted = true;
|
||||
}
|
||||
private void EndAttempt_OnAttemptEnded(object sender, AttemptEventArgs args)
|
||||
{
|
||||
attemptStarted = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
private void SpawnAllTiles()
|
||||
{
|
||||
for (int i = 1; i <= maxTile; i++)
|
||||
{
|
||||
SpawnTile(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnTile(int tileNumber)
|
||||
{
|
||||
GameObject newTile = Instantiate(tilePrefab, transform.position-new Vector3((tileNumber*tileLength),0,0), Quaternion.identity, transform);
|
||||
//transform.position += new Vector3(tileLength, 0, 0);
|
||||
tileList.Add(newTile.transform);
|
||||
}
|
||||
|
||||
private void ResetBackgroundPosition()
|
||||
{
|
||||
transform.position += new Vector3(tileLength, transform.position.y, transform.position.z);
|
||||
}
|
||||
private void MoveTilesHorizontally()
|
||||
{
|
||||
transform.position += new Vector3(-GameHandler.Instance.FrameDistance, 0, 0);
|
||||
if(startPositionX- transform.position.x > tileLength)
|
||||
{
|
||||
ResetBackgroundPosition();
|
||||
}
|
||||
|
||||
//List<Transform> tilesToRemove = new List<Transform>();
|
||||
|
||||
//foreach (Transform tileTransform in tileList)
|
||||
//{
|
||||
// tileTransform.position += new Vector3(GameHandler.Instance.TotalDistance,0,0);;
|
||||
// if (tileTransform.position.x < tileMinX)
|
||||
// {
|
||||
// tilesToRemove.Add(tileTransform);
|
||||
// }
|
||||
//}
|
||||
|
||||
//// Remove tiles that have gone off screen
|
||||
//foreach (Transform tileToRemove in tilesToRemove)
|
||||
//{
|
||||
// tileList.Remove(tileToRemove);
|
||||
// Destroy(tileToRemove.gameObject);
|
||||
// SpawnTile();
|
||||
//}
|
||||
}
|
||||
|
||||
private float GetStartPosition()
|
||||
{
|
||||
Camera mainCamera = Camera.main;
|
||||
float screenRight = mainCamera.ScreenToWorldPoint(new Vector3(Screen.width, 0, mainCamera.nearClipPlane)).x;
|
||||
return screenRight+2*tileLength;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
void Start()
|
||||
{
|
||||
attemptStarted = false;
|
||||
|
||||
_gameHandler = GameHandler.Instance;
|
||||
_gameHandler.OnAttemptStarted += StartAttempt_OnAttemptStarted;
|
||||
_gameHandler.OnAttemptEnding += EndAttempt_OnAttemptEnded;
|
||||
|
||||
startPositionX = GetStartPosition();
|
||||
transform.position = new Vector3(startPositionX, transform.position.y, transform.position.z);
|
||||
|
||||
|
||||
SpawnAllTiles();
|
||||
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(attemptStarted)
|
||||
{
|
||||
MoveTilesHorizontally();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
1314
Scripts/Statistics/GraphHandler.cs
Normal file
1314
Scripts/Statistics/GraphHandler.cs
Normal file
File diff suppressed because it is too large
Load Diff
143
Scripts/Statistics/GraphPanelScript.cs
Normal file
143
Scripts/Statistics/GraphPanelScript.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using Assets.Scripts;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UIElements;
|
||||
using XCharts.Runtime;
|
||||
|
||||
public class GraphPanelScript : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
public SessionData Session { get; private set; }
|
||||
public LineChart LineChart {get; set; }
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
//public VisualTreeAsset graphPanelTemplate;
|
||||
//public RenderTexture renderTexture;
|
||||
|
||||
|
||||
public UIDocument _document;
|
||||
private StatsMenuController _statsController;
|
||||
|
||||
|
||||
|
||||
private VisualElement root;
|
||||
private VisualElement graphContainer;
|
||||
private VisualElement graphPanel;
|
||||
|
||||
private VisualElement[,] anchors;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
////void UpdateChartPositionAndSize(RectTransform chartRectTransform, VisualElement chartContainer)
|
||||
////{
|
||||
//// // Obtenir les dimensions et la position du conteneur en pixels
|
||||
//// Rect containerRect = chartContainer.worldBound;
|
||||
|
||||
//// // Convertir la position du VisualElement en coordonn<6E>es du Canvas
|
||||
//// var canvasRectTransform = _statsController.Canvas.GetComponent<RectTransform>();
|
||||
//// Vector2 containerSize = containerRect.size;
|
||||
//// Vector2 containerPosition = containerRect.position - new Vector2(canvasRectTransform.rect.width / 2, canvasRectTransform.rect.height / 2);
|
||||
|
||||
//// // Ajuster la taille et la position du RectTransform pour qu'il corresponde au VisualElement
|
||||
//// chartRectTransform.anchorMin = Vector2.zero;
|
||||
//// chartRectTransform.anchorMax = Vector2.zero;
|
||||
//// chartRectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
//// chartRectTransform.sizeDelta = containerSize;
|
||||
//// chartRectTransform.anchoredPosition = containerPosition;
|
||||
////}
|
||||
|
||||
void UpdateChartPositionAndSize(int anchorRow, int anchorCol)
|
||||
{
|
||||
//if (anchorRow < 0 || anchorRow >= 3 || anchorCol < 0 || anchorCol >= 3)
|
||||
//{
|
||||
// Debug.LogError("Invalid anchor position");
|
||||
// return;
|
||||
//}
|
||||
|
||||
//VisualElement anchor = anchors[anchorRow, anchorCol];
|
||||
|
||||
// Positionner le LineChart
|
||||
//RectTransform lineChartRectTransform = LineChart.GetComponent<RectTransform>();
|
||||
|
||||
//lineChartRectTransform.anchoredPosition = new Vector3(480, -184, -1);
|
||||
}
|
||||
|
||||
//private Vector2 ConvertUIToCanvasPosition(VisualElement uiElement)
|
||||
//{
|
||||
// // Trouver la cam<61>ra
|
||||
// Camera camera = Camera.main;
|
||||
|
||||
// // Trouver la position de l'ancre dans l'espace du monde
|
||||
// Vector3 worldPosition = uiElement.worldBound.center;
|
||||
|
||||
// // Convertir la position du monde en position de l'<27>cran
|
||||
// Vector3 screenPosition = camera.WorldToScreenPoint(worldPosition);
|
||||
|
||||
// // Convertir la position de l'<27>cran en position de la toile (canvas)
|
||||
// RectTransform canvasRectTransform = lineChart.GetComponentInParent<Canvas>().GetComponent<RectTransform>();
|
||||
// Vector2 canvasPosition;
|
||||
// RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, screenPosition, camera, out canvasPosition);
|
||||
|
||||
// return canvasPosition;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
protected void Awake()
|
||||
{
|
||||
_statsController = StatsMenuController.Instance;
|
||||
_document = _statsController.GetComponent<UIDocument>();
|
||||
root = _document.rootVisualElement;
|
||||
|
||||
graphContainer = root.Q<VisualElement>("ChartsParentContainer");
|
||||
|
||||
LineChart = gameObject.GetComponent<LineChart>();
|
||||
|
||||
var serie = LineChart.AddSerie<Line>();
|
||||
serie.AddXYData(0, 10);
|
||||
serie.AddXYData(1, 20);
|
||||
serie.AddXYData(2, 15);
|
||||
|
||||
// Synchroniser la position et les dimensions du LineChart avec le VisualElement
|
||||
RectTransform chartRectTransform = LineChart.GetComponent<RectTransform>();
|
||||
|
||||
|
||||
graphContainer.style.width = new StyleLength(Length.Percent(100));
|
||||
graphContainer.style.height = new StyleLength(Length.Percent(100));
|
||||
|
||||
anchors = new VisualElement[3, 3];
|
||||
int k = 0;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
k++;
|
||||
anchors[i, j] = graphContainer.Q<VisualElement>($"Anchor{k}");
|
||||
}
|
||||
}
|
||||
|
||||
UpdateChartPositionAndSize(1, 1);
|
||||
//graphContainer.RegisterCallback<GeometryChangedEvent>(evt => UpdateChartPositionAndSize(lineChart.GetComponent<RectTransform>(), 1, 1, 300, 200));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
331
Scripts/Statistics/GraphSettings.cs
Normal file
331
Scripts/Statistics/GraphSettings.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace Assets.Scripts
|
||||
{
|
||||
public class GraphSettings : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
[Header("Graph Settings")]
|
||||
[Space]
|
||||
public int updatePeriod = 5;
|
||||
[SerializeField] private Vector2 graphSize = new Vector2(800f, 400f);
|
||||
public Vector2 GraphSize
|
||||
{
|
||||
get { return graphSize; }
|
||||
set { graphSize = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePositionAndScale | UpdateMethod.UpdateContent | UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[SerializeField] private Vector2 graphScale = new Vector2(100f, 100f);
|
||||
public Vector2 GraphScale
|
||||
{
|
||||
get { return graphScale; }
|
||||
set { graphScale = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePositionAndScale | UpdateMethod.UpdateContent | UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[Header("Graph Visuals")]
|
||||
[Space]
|
||||
[SerializeField] private Color backgroundColor = new Color(0, 0, 0, 1f);
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get { return backgroundColor; }
|
||||
set { backgroundColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateOutlines); }
|
||||
}
|
||||
[SerializeField] private float outlineWidth = 5f;
|
||||
public float OutlineWidth
|
||||
{
|
||||
get { return outlineWidth; }
|
||||
set { outlineWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdateOutlines); }
|
||||
}
|
||||
|
||||
[SerializeField] private Color outlineColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color OutlineColor
|
||||
{
|
||||
get { return outlineColor; }
|
||||
set { outlineColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateOutlines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float lineWidth = 8f;
|
||||
public float LineWidth
|
||||
{
|
||||
get { return lineWidth; }
|
||||
set { lineWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdateContent); }
|
||||
}
|
||||
[SerializeField] private Color lineColor = new Color(1f, 0.35f, 0f, 1f);
|
||||
public Color LineColor
|
||||
{
|
||||
get { return lineColor; }
|
||||
set { lineColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateContent); }
|
||||
}
|
||||
[Space]
|
||||
public Sprite PointSprite;
|
||||
[SerializeField] private float pointRadius = 5f;
|
||||
public float PointRadius
|
||||
{
|
||||
get { return pointRadius; }
|
||||
set { pointRadius = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[SerializeField] private Color pointColor = new Color(1f, 0.35f, 0f, 1f);
|
||||
public Color PointColor
|
||||
{
|
||||
get { return pointColor; }
|
||||
set { pointColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float pointHoverRadius = 15f;
|
||||
public float PointHoverRadius
|
||||
{
|
||||
get { return pointHoverRadius; }
|
||||
set { pointHoverRadius = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
public float PointHoverSpeed = 5f;
|
||||
|
||||
[SerializeField] private Color pointHoverColor = new Color(1, 0.6f, 0, 1f);
|
||||
public Color PointHoverColor
|
||||
{
|
||||
get { return pointHoverColor; }
|
||||
set { pointHoverColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float pointLockedRadius = 17f;
|
||||
public float PointLockedRadius
|
||||
{
|
||||
get { return pointLockedRadius; }
|
||||
set { pointLockedRadius = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
public float PointLockedSpeed = 5f;
|
||||
|
||||
[SerializeField] private Color pointLockedColor = new Color(1, 0.8f, 0, 1f);
|
||||
public Color PointLockedColor
|
||||
{
|
||||
get { return pointLockedColor; }
|
||||
set { pointLockedColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float unfixedPointOutlineWidth = 10f;
|
||||
public float UnfixedPointOutlineWidth
|
||||
{
|
||||
get { return unfixedPointOutlineWidth; }
|
||||
set { unfixedPointOutlineWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[SerializeField] private Color unfixedPointOutlineColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color UnfixedPointOutlineColor
|
||||
{
|
||||
get { return unfixedPointOutlineColor; }
|
||||
set { unfixedPointOutlineColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float unfixedPointOutlineHoverWidth = 15f;
|
||||
public float UnfixedPointOutlineHoverWidth
|
||||
{
|
||||
get { return unfixedPointOutlineHoverWidth; }
|
||||
set { unfixedPointOutlineHoverWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
public float UnfixedPointOutlineHoverSpeed = 5f;
|
||||
|
||||
[Space]
|
||||
[SerializeField] private Color unfixedPointOutlineHoverColor = new Color(0, 0.5f, 1f, 1f);
|
||||
public Color UnfixedPointOutlineHoverColor
|
||||
{
|
||||
get { return unfixedPointOutlineHoverColor; }
|
||||
set { unfixedPointOutlineHoverColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float fixedPointOutlineWidth = 17f;
|
||||
public float FixedPointOutlineWidth
|
||||
{
|
||||
get { return fixedPointOutlineWidth; }
|
||||
set { fixedPointOutlineWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
public float FixedPointOutlineSpeed = 5f;
|
||||
[SerializeField] private Color fixedPointOutlineColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color FixedPointOutlineColor
|
||||
{
|
||||
get { return fixedPointOutlineColor; }
|
||||
set { fixedPointOutlineColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdatePointVisuals); }
|
||||
}
|
||||
|
||||
[Space]
|
||||
[Header("Grid Settings")]
|
||||
[Space]
|
||||
|
||||
public TMP_FontAsset GridTextFont;
|
||||
[SerializeField] private Vector2 gridSpacing = new Vector2(1, 1);
|
||||
public Vector2 GridSpacing
|
||||
{
|
||||
get { return gridSpacing; }
|
||||
set { gridSpacing = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float xAxisWidth = 3f;
|
||||
public float XAxisWidth
|
||||
{
|
||||
get { return xAxisWidth; }
|
||||
set { xAxisWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
|
||||
[SerializeField] private Color xAxisColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color XAxisColor
|
||||
{
|
||||
get { return xAxisColor; }
|
||||
set { xAxisColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private Color xAxisTextColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color XAxisTextColor
|
||||
{
|
||||
get { return xAxisTextColor; }
|
||||
set { xAxisTextColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[SerializeField] private float xAxisTextSize = 10f;
|
||||
public float XAxisTextSize
|
||||
{
|
||||
get { return xAxisTextSize; }
|
||||
set { xAxisTextSize = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[SerializeField] private float xAxisTextOffset = 10f;
|
||||
public float XAxisTextOffset
|
||||
{
|
||||
get { return xAxisTextOffset; }
|
||||
set { xAxisTextOffset = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float yAxisWidth = 3f;
|
||||
public float YAxisWidth
|
||||
{
|
||||
get { return yAxisWidth; }
|
||||
set { yAxisWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
|
||||
[SerializeField] private Color yAxisColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color YAxisColor
|
||||
{
|
||||
get { return yAxisColor; }
|
||||
set { yAxisColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private Color yAxisTextColor = new Color(0, 0.8f, 1f, 1f);
|
||||
public Color YAxisTextColor
|
||||
{
|
||||
get { return yAxisTextColor; }
|
||||
set { yAxisTextColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[SerializeField] private float yAxisTextSize = 10f;
|
||||
public float YAxisTextSize
|
||||
{
|
||||
get { return yAxisTextSize; }
|
||||
set { yAxisTextSize = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[SerializeField] private float yAxisTextOffset = 10f;
|
||||
public float YAxisTextOffset
|
||||
{
|
||||
get { return yAxisTextOffset; }
|
||||
set { yAxisTextOffset = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float xGridWidth = 2f;
|
||||
public float XGridWidth
|
||||
{
|
||||
get { return xGridWidth; }
|
||||
set { xGridWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[SerializeField] private Color xGridColor = new Color(0, 0.8f, 1f, 0.6f);
|
||||
public Color XGridColor
|
||||
{
|
||||
get { return xGridColor; }
|
||||
set { xGridColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private float yGridWidth = 2f;
|
||||
public float YGridWidth
|
||||
{
|
||||
get { return yGridWidth; }
|
||||
set { yGridWidth = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
|
||||
[SerializeField] private Color yGridColor = new Color(0, 0.8f, 1f, 0.6f);
|
||||
public Color YGridColor
|
||||
{
|
||||
get { return yGridColor; }
|
||||
set { yGridColor = value; GH.UpdateGraphInternal(UpdateMethod.UpdateGridLines); }
|
||||
}
|
||||
|
||||
[Space]
|
||||
[SerializeField] private Color zoomSelectionColor = new Color(0, 0.8f, 1f, 0.2f);
|
||||
public Color ZoomSelectionColor
|
||||
{
|
||||
get { return zoomSelectionColor; }
|
||||
set { zoomSelectionColor = value; GH.UpdateGraphInternal(UpdateMethod.MouseAction); }
|
||||
}
|
||||
[SerializeField] private float zoomSelectionOutlineWidth = 5f;
|
||||
public float ZoomSelectionOutlineWidth
|
||||
{
|
||||
get { return zoomSelectionOutlineWidth; }
|
||||
set { zoomSelectionOutlineWidth = value; GH.UpdateGraphInternal(UpdateMethod.MouseAction); }
|
||||
}
|
||||
[SerializeField] private Color zoomSelectionOutlineColor = new Color(0, 0.8f, 1f, 0.6f);
|
||||
public Color ZoomSelectionOutlineColor
|
||||
{
|
||||
get { return zoomSelectionOutlineColor; }
|
||||
set { zoomSelectionOutlineColor = value; GH.UpdateGraphInternal(UpdateMethod.MouseAction); }
|
||||
}
|
||||
[Space]
|
||||
[SerializeField] private Color pointSelectionColor = new Color(1, 0.35f, 0f, 0.2f);
|
||||
public Color PointSelectionColor
|
||||
{
|
||||
get { return pointSelectionColor; }
|
||||
set { pointSelectionColor = value; GH.UpdateGraphInternal(UpdateMethod.MouseAction); }
|
||||
}
|
||||
[SerializeField] private float pointSelectionOutlineWidth = 5f;
|
||||
public float PointSelectionOutlineWidth
|
||||
{
|
||||
get { return pointSelectionOutlineWidth; }
|
||||
set { pointSelectionOutlineWidth = value; GH.UpdateGraphInternal(UpdateMethod.MouseAction); }
|
||||
}
|
||||
[SerializeField] private Color pointSelectionOutlineColor = new Color(1, 0.35f, 0f, 0.4f);
|
||||
public Color PointSelectionOutlineColor
|
||||
{
|
||||
get { return pointSelectionOutlineColor; }
|
||||
set { pointSelectionOutlineColor = value; GH.UpdateGraphInternal(UpdateMethod.MouseAction); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
[Space]
|
||||
public float ZoomSpeed = 5f;
|
||||
public float SmoothZoomSpeed = 20f;
|
||||
public float SmoothMoveSpeed = 20f;
|
||||
|
||||
private GraphHandler GH;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
GH = GetComponent<GraphHandler>();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
71
Scripts/Statistics/SessionsListView.cs
Normal file
71
Scripts/Statistics/SessionsListView.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class SessionsListView : MonoBehaviour
|
||||
{
|
||||
#region PROPERTIES
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
[SerializeField] private UIDocument uiDocument;
|
||||
private StatsMenuController _statsController;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
private void OnButtonClick(SessionData sessionData)
|
||||
{
|
||||
_statsController.OnSessionSelected(sessionData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_statsController = StatsMenuController.Instance;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
var sessionDataList = _statsController.Sessions;
|
||||
var root = uiDocument.rootVisualElement;
|
||||
|
||||
var listView = root.Q<ListView>("ListViewSessions");
|
||||
|
||||
listView.itemsSource = sessionDataList;
|
||||
listView.makeItem = () => new Button();
|
||||
listView.bindItem = (element, index) =>
|
||||
{
|
||||
var button = element as Button;
|
||||
var sessionData = sessionDataList[index];
|
||||
button.text = $"Session {sessionData.SessionNumber} | {sessionData.Date.ToString("ddd, dd MMM yyy")}";
|
||||
button.AddToClassList("list-button");
|
||||
button.style.backgroundColor = new Color(0, 0, 0, 0.2f);
|
||||
button.style.height = 50;
|
||||
button.style.marginLeft = 10;
|
||||
button.style.marginRight = 10;
|
||||
button.style.marginBottom = 2;
|
||||
button.style.color = Color.white;
|
||||
// Ajouter un callback pour lorsque le bouton est cliqu<71>
|
||||
button.clicked += () => OnButtonClick(sessionData);
|
||||
};
|
||||
|
||||
listView.fixedItemHeight = 52;
|
||||
listView.selectionType = SelectionType.Single;
|
||||
listView.style.flexGrow = 1.0f;
|
||||
|
||||
listView.Rebuild();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
180
Scripts/Statistics/StatsMenuController.cs
Normal file
180
Scripts/Statistics/StatsMenuController.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using Assets.Scripts;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UIElements;
|
||||
using XCharts.Runtime;
|
||||
|
||||
public class StatsMenuController : SingletonMB<StatsMenuController>
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
public List<SessionData> Sessions { get; private set; }
|
||||
public Canvas Canvas { get { return _canvas; } private set { _canvas = value; } }
|
||||
[SerializeField] private Canvas _canvas;
|
||||
|
||||
#endregion
|
||||
#region VARIABLES
|
||||
|
||||
[SerializeField] private GameObject graphPanelTemplate;
|
||||
private UIDocument _document;
|
||||
private Button _exitButton;
|
||||
private Button _storageButton;
|
||||
private List<LineChart> lineCharts;
|
||||
|
||||
#endregion
|
||||
#region EVENTS
|
||||
|
||||
private void OnExitButton(ClickEvent e)
|
||||
{
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
}
|
||||
private void OnStorageButton(ClickEvent e)
|
||||
{
|
||||
string path = Path.Combine(Application.persistentDataPath, "SessionsData");
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.RevealInFinder(path);
|
||||
#elif UNITY_STANDALONE_WIN
|
||||
path = path.Replace("/", "\\"); // Remplacer les / par \ pour Windows
|
||||
Process.Start("explorer.exe", path);
|
||||
#elif UNITY_STANDALONE_OSX
|
||||
Process.Start("open", path);
|
||||
#elif UNITY_STANDALONE_LINUX
|
||||
Process.Start("xdg-open", path);
|
||||
#else
|
||||
Debug.LogWarning("Opening the file explorer is not supported on this platform.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region ENDPOINTS
|
||||
|
||||
public void OnSessionSelected(SessionData session)
|
||||
{
|
||||
if (lineCharts != null)
|
||||
{
|
||||
for (int i = 0; i < lineCharts.Count; i++)
|
||||
{
|
||||
Destroy(lineCharts[i]);
|
||||
}
|
||||
lineCharts.Clear();
|
||||
}
|
||||
|
||||
UnityEngine.Debug.Log("Session Chart " + session.SessionNumber);
|
||||
|
||||
int n = 0;
|
||||
foreach (var attempt in session.Attempts)
|
||||
{
|
||||
n++;
|
||||
if (n > 4) break;
|
||||
|
||||
var instance = Instantiate(graphPanelTemplate, Canvas.transform).GetComponent<GraphPanelScript>().LineChart;
|
||||
instance.RemoveAllSerie();
|
||||
|
||||
lineCharts.Add(instance);
|
||||
|
||||
|
||||
var position = new Vector3(480, -184, -1);
|
||||
var nextColumnPosition = new Vector3(instance.chartWidth + 2, 0, 0);
|
||||
var nextLinePosition = new Vector3(0, -instance.chartHeight - 2, 0);
|
||||
switch (lineCharts.IndexOf(instance))
|
||||
{
|
||||
case 0:
|
||||
instance.GetComponent<RectTransform>().anchoredPosition = position;
|
||||
break;
|
||||
case 1:
|
||||
instance.GetComponent<RectTransform>().anchoredPosition = position + nextColumnPosition;
|
||||
break;
|
||||
case 2:
|
||||
instance.GetComponent<RectTransform>().anchoredPosition = position + nextLinePosition;
|
||||
break;
|
||||
case 3:
|
||||
instance.GetComponent<RectTransform>().anchoredPosition = position + nextLinePosition + nextColumnPosition;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Definir nom de la chart
|
||||
var chartName = instance.EnsureChartComponent<Title>();
|
||||
chartName.text = $"Scores dans le temps | round {attempt.AttemptNumber}";
|
||||
|
||||
|
||||
// D<>finir les noms des axes
|
||||
var xAxis = instance.EnsureChartComponent<XAxis>();
|
||||
xAxis.type = Axis.AxisType.Value;
|
||||
AxisName xName = new();
|
||||
xName.name = "Temps (ticks)";
|
||||
xAxis.axisName = xName;
|
||||
|
||||
var yAxis = instance.EnsureChartComponent<YAxis>();
|
||||
yAxis.type = Axis.AxisType.Value;
|
||||
AxisName yName = new();
|
||||
yName.name = "Score";
|
||||
yAxis.axisName = yName;
|
||||
|
||||
// Ajouter une l<>gende
|
||||
var legend = instance.EnsureChartComponent<Legend>();
|
||||
legend.show = true;
|
||||
|
||||
foreach (var playerAttempt in attempt.PlayersAttempts)
|
||||
{
|
||||
var scoreOverTime = playerAttempt.Value.PlayerScoresOverTicksTime;
|
||||
|
||||
// Ajouter une nouvelle s<>rie avec une l<>gende
|
||||
var serie = instance.AddSerie<Line>(playerAttempt.Value.PlayerName);
|
||||
serie.serieName = playerAttempt.Value.PlayerName;
|
||||
//serie.legendName = playerAttempt.Value.PlayerName;
|
||||
scoreOverTime.ForEach(score =>
|
||||
{
|
||||
serie.AddXYData(score.X, score.Y);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#region METHODS
|
||||
|
||||
private List<SessionData> LoadSessionData()
|
||||
{
|
||||
string directoryPath = Path.Combine(Application.persistentDataPath, "SessionsData");
|
||||
var sessionDataList = new List<SessionData>();
|
||||
|
||||
var files = Directory.GetFiles(directoryPath, "*.json");
|
||||
foreach (var file in files)
|
||||
{
|
||||
var json = File.ReadAllText(file);
|
||||
var sessionData = JsonConvert.DeserializeObject<SessionData>(json);
|
||||
sessionDataList.Add(sessionData);
|
||||
}
|
||||
|
||||
return sessionDataList.OrderBy<SessionData, int>(s => s.SessionNumber).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region LIFECYCLE
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
Sessions = LoadSessionData();
|
||||
|
||||
_document = GetComponent<UIDocument>();
|
||||
_exitButton = _document.rootVisualElement.Q("ExitButton") as Button;
|
||||
_exitButton.RegisterCallback<ClickEvent>(OnExitButton);
|
||||
_storageButton = _document.rootVisualElement.Q("StorageButton") as Button;
|
||||
_storageButton.RegisterCallback<ClickEvent>(OnStorageButton);
|
||||
|
||||
lineCharts = new();
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
Reference in New Issue
Block a user