2024-11-18 09:16:03 +08:00
using System ;
using System.Collections.Generic ;
using UnityEngine ;
using UnityEngine.UIElements ;
using Random = System . Random ;
/// <summary>
/// gameplay behaviour class
/// </summary>
public class Gameplay
{
2024-11-18 18:02:41 +08:00
/// <summary>
/// singleton instance of the gameplay class
/// </summary>
public const int RoundsPerGame = 5 ;
/// <summary>
/// seconds per round
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
2024-11-19 03:59:29 +08:00
public const double SecondsPerRound = 12d ;
2024-11-18 18:02:41 +08:00
2024-11-18 09:16:03 +08:00
/// <summary>
/// countdown text label for showing the countdown
/// </summary>
private readonly Label _countdownText ;
/// <summary>
/// list of played rounds
/// </summary>
private readonly List < RoundInfo > _playedRounds = new ( 5 ) ;
/// <summary>
/// response colour for the player to match
/// </summary>
private readonly VisualElement _responseColour ;
/// <summary>
/// round text label for showing the current round
/// </summary>
private readonly Label _roundText ;
/// <summary>
/// template colour for the player to match
/// </summary>
private readonly VisualElement _templateColour ;
/// <summary>
/// game countdown timer
/// </summary>
private DateTime _countdownDatetime ;
/// <summary>
/// game round counter
/// </summary>
2024-11-18 10:34:29 +08:00
public int Round = - 1 ;
2024-11-18 09:16:03 +08:00
/// <summary>
/// constructor for the gameplay class
/// </summary>
/// <param name="ui">the visual element object for the ui document with the GameView</param>
2024-11-18 10:34:29 +08:00
public Gameplay ( VisualElement ui )
2024-11-18 09:16:03 +08:00
{
_roundText = ui . Q < Label > ( "RoundText" ) ;
_countdownText = ui . Q < Label > ( "TimeText" ) ;
_templateColour = ui . Q < VisualElement > ( "TemplateColour" ) ;
_responseColour = ui . Q < VisualElement > ( "ResponseColour" ) ;
}
/// <summary>
/// function for starting the game
/// </summary>
2024-11-18 10:34:29 +08:00
public void StartGame ( )
2024-11-18 09:16:03 +08:00
{
2024-11-18 10:34:29 +08:00
Round = 0 ;
2024-11-18 09:16:03 +08:00
AdvanceToNextRound ( ) ;
}
/// <summary>
2024-11-18 10:34:29 +08:00
/// (to be) called once per frame
2024-11-18 09:16:03 +08:00
/// </summary>
2024-11-18 10:34:29 +08:00
public void Update ( )
2024-11-18 09:16:03 +08:00
{
2024-11-18 10:34:29 +08:00
if ( Round < 1 ) return ;
2024-11-18 09:16:03 +08:00
if ( _countdownDatetime < DateTime . Now ) AdvanceToNextRound ( ) ;
Render ( ) ;
}
/// <summary>
/// function for advancing to the next round
/// </summary>
private void AdvanceToNextRound ( )
{
2024-11-18 10:34:29 +08:00
if ( Round > 0 ) StoreRoundInfo ( ) ;
2024-11-18 09:16:03 +08:00
GenerateNewTemplateColour ( ) ;
2024-11-18 10:34:29 +08:00
if ( Round < RoundsPerGame )
2024-11-18 09:16:03 +08:00
{
2024-11-18 10:34:29 +08:00
Debug . Log ( "round advance" ) ;
Round + + ;
2024-11-18 09:16:03 +08:00
_countdownDatetime = DateTime . Now . AddSeconds ( SecondsPerRound ) ;
}
else
{
// end game
2024-11-18 10:34:29 +08:00
Round = - 1 ;
2024-11-18 09:16:03 +08:00
GameManager . Instance . SignalGameEnd ( _playedRounds ) ;
}
}
/// <summary>
/// function for storing the round information
/// </summary>
private void StoreRoundInfo ( )
{
_playedRounds . Add ( new RoundInfo
{
TemplateColour = _templateColour . style . backgroundColor . value ,
ResponseColour = _responseColour . style . backgroundColor . value
} ) ;
2024-11-19 03:59:29 +08:00
Debug . Log ( $"stored round info (Template is {_templateColour.style.backgroundColor.value}, Response is {_responseColour.style.backgroundColor.value})" ) ;
2024-11-18 09:16:03 +08:00
}
/// <summary>
/// function for generating a new template colour
/// (a random colour that isn't hard to visually match)
/// </summary>
private void GenerateNewTemplateColour ( )
{
2024-11-19 03:59:29 +08:00
// - lightness: 30-90
// - chroma: 0.03-0.20
2024-11-18 09:16:03 +08:00
// - hue: all (0-360)
2024-11-18 18:02:41 +08:00
var r = new Random ( ) ;
2024-11-19 03:59:29 +08:00
var l = Math . Clamp ( r . NextDouble ( ) * 60d + 30d , 30d , 90d ) ;
var c = Math . Clamp ( r . NextDouble ( ) * 0.17d + 0.03d , 0.03d , 0.20d ) ;
2024-11-18 18:02:41 +08:00
var h = Math . Clamp ( r . NextDouble ( ) * 360d , 0d , 360d ) ;
var colour = Colorimetry . RawLchToColor ( l , c , h ) ;
Debug . Log ( $"generated new template colour LCh({l:F}, {c:F}, {h:F}) -> {colour}" ) ;
_templateColour . style . backgroundColor = colour ;
2024-11-18 09:16:03 +08:00
}
/// <summary>
/// function for rendering the game state
/// </summary>
private void Render ( )
{
var remaining = ( _countdownDatetime - DateTime . Now ) . TotalSeconds ;
2024-11-18 10:34:29 +08:00
_roundText . text = $"{Round}/{RoundsPerGame}" ;
2024-11-19 03:59:29 +08:00
_countdownText . text = $"{remaining:F2}" ;
2024-11-18 09:16:03 +08:00
}
/// <summary>
/// struct for storing round information
/// </summary>
public struct RoundInfo
{
public Color TemplateColour ;
public Color ResponseColour ;
}
}