using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public partial class GameController : MonoBehaviour
{
///
/// All of the words that can be used in this session
///
//private string[] words;
private List words = new List();
///
/// Where we currently are in the word
///
private int letterIndex;
///
/// Where we currently are in the word list
///
private int wordIndex;
///
/// The word that is currently being spelled
///
private string currentWord;
///
/// All of the available themes
///
public ThemeList themeList;
///
/// The theme we are currently using
///
private Theme currentTheme;
///
/// Current value of timer in seconds
///
private float timerValue;
///
/// Indicates if the game is still going
///
private bool gameEnded;
///
/// Amount of seconds user gets per letter of the current word
/// Set to 1 for testing; should be increased later
///
private const int secondsPerLetter = 5;
///
/// Counter that keeps track of how many letters have been spelled correctly
///
private int correctLetters;
///
/// Counter that keeps track of how many letters have been spelled incorrectly
///
private int incorrectLetters;
///
/// Counter that keeps track of how many words have been spelled correctly
///
private int spelledWords;
///
/// Timer that keeps track of when the game was started
///
private DateTime startTime;
///
/// Reference to the user list to access the current user
///
public UserList userList;
///
/// Reference to the current user
///
private User user;
///
/// Reference to the minigame ScriptableObject
///
public Minigame minigame;
///
/// We keep the minigamelist as well so that the minigame-index doesn't get reset
/// DO NOT REMOVE
///
public MinigameList minigamelist;
///
/// Letter prefab
///
public GameObject letterPrefab;
///
/// Reference to letter container
///
public Transform letterContainer;
///
/// The Image component for displaying the appropriate sprite
///
public Image wordImage;
///
/// Timer display
///
public TMP_Text timerText;
///
/// Bonus time display
///
public GameObject bonusTimeText;
///
/// Timer to display the bonus time
///
private float bonusActiveRemaining = 0.0f;
///
/// The GameObjects representing the letters
///
private List letters = new List();
///
/// Reference to the scoreboard
///
public Transform Scoreboard;
///
/// Accuracy feeback object
///
public Feedback feedback;
///
/// Reference to the gameEnded panel, so we can update its display
///
public GameObject gameEndedPanel;
///
/// Start is called before the first frame update
///
public void Start()
{
correctLetters = 0;
incorrectLetters = 0;
words.Clear();
// We use -1 instead of 0 so SetNextWord can simply increment it each time
spelledWords = -1;
wordIndex = 0;
gameEnded = false;
timerValue = 30.0f;
bonusActiveRemaining = 0.0f;
startTime = DateTime.Now;
gameEndedPanel.SetActive(false);
bonusTimeText.SetActive(false);
// Create entry in current user for keeping track of progress
userList.Load();
user = userList.GetCurrentUser();
Progress progress = user.GetMinigameProgress(minigame.index);
if (progress == null)
{
progress = new Progress();
progress.AddOrUpdate("minigameIndex", MinigameIndex.SPELLING_BEE);
progress.AddOrUpdate>("highestScores", new List());
progress.AddOrUpdate>("latestScores", new List());
user.minigames.Add(progress);
}
userList.Save();
currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
feedback.signPredictor.model = currentTheme.model;
words.AddRange(currentTheme.learnables);
ShuffleWords();
NextWord();
// Set calllbacks
feedback.getSignCallback = () =>
{
if (letterIndex < currentWord.Length)
{
return currentWord[letterIndex].ToString().ToUpper();
}
return null;
};
feedback.predictSignCallback = (sign) =>
{
bool successful = sign.ToUpper() == currentWord[letterIndex].ToString().ToUpper();
if (successful)
{
AddSeconds(secondsPerLetter);
}
NextLetter(successful);
};
}
///
/// Update is called once per frame
///
public void Update()
{
if (!gameEnded)
{
timerValue -= Time.deltaTime;
if (bonusActiveRemaining <= 0.0 && bonusTimeText.activeSelf)
{
bonusTimeText.SetActive(false);
}
else
{
bonusActiveRemaining -= Time.deltaTime;
}
if (timerValue <= 0.0f)
{
timerValue = 0.0f;
ActivateGameOver();
}
int minutes = Mathf.FloorToInt(timerValue / 60.0f);
int seconds = Mathf.FloorToInt(timerValue % 60.0f);
timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
///
/// Randomly shuffle the list of words
///
public void ShuffleWords()
{
for (int i = words.Count - 1; i > 0; i--)
{
// Generate a random index between 0 and i (inclusive)
int j = UnityEngine.Random.Range(0, i + 1);
// Swap the values at indices i and j
(words[j], words[i]) = (words[i], words[j]);
}
}
///
/// Calculate the score
///
/// The calculated score
public int CalculateScore()
{
return spelledWords * 5 + correctLetters;
}
///
/// Displays the game over panel and score values
///
public void ActivateGameOver()
{
gameEnded = true;
DeleteWord();
// Save the scores and show the scoreboard
SaveScores();
gameEndedPanel.GetComponent().GenerateContent(
startTime: startTime,
totalWords: spelledWords,
correctLetters: correctLetters,
incorrectLetters: incorrectLetters,
result: "VERLOREN",
score: CalculateScore()
);
gameEndedPanel.SetActive(true);
}
///
/// Display win screen
///
public void ActivateWin()
{
gameEnded = true;
DeleteWord();
// Save the scores and show the scoreboard
SaveScores();
gameEndedPanel.GetComponent().GenerateContent(
startTime: startTime,
totalWords: spelledWords,
correctLetters: correctLetters,
incorrectLetters: incorrectLetters,
result: "GEWONNEN",
score: CalculateScore()
);
gameEndedPanel.SetActive(true);
}
///
/// Update and save the scores
///
public void SaveScores()
{
// Calculate new score
int newScore = CalculateScore();
// Save the score as a tuple: < int score, string time ago>
Score score = new Score();
score.scoreValue = newScore;
score.time = DateTime.Now.ToString();
// Save the new score
user = userList.GetCurrentUser();
Progress progress = user.GetMinigameProgress(minigame.index);
// Get the current list of scores
List latestScores = progress.Get>("latestScores");
List highestScores = progress.Get>("highestScores");
// Add the new score
latestScores.Add(score);
highestScores.Add(score);
// Sort the scores
highestScores.Sort((a, b) => b.scoreValue.CompareTo(a.scoreValue));
// Only save the top 10 scores, so this list doesn't keep growing endlessly
progress.AddOrUpdate>("latestScores", latestScores.Take(10).ToList());
progress.AddOrUpdate>("highestScores", highestScores.Take(10).ToList());
userList.Save();
}
///
/// Delete all letter objects
///
public void DeleteWord()
{
for (int i = 0; i < letters.Count; i++)
{
Destroy(letters[i]);
}
letters.Clear();
}
///
/// Adds seconds to timer
///
///
public void AddSeconds(int seconds)
{
timerValue += (float)seconds;
bonusTimeText.SetActive(true);
bonusActiveRemaining = 2.0f;
}
///
/// Display the next letter
///
/// true if the letter was correctly signed, false otherwise
public void NextLetter(bool successful)
{
// Change color of current letter (skip spaces)
if (successful)
{
correctLetters++;
letters[letterIndex].GetComponent().color = Color.green;
}
else
{
incorrectLetters++;
letters[letterIndex].GetComponent().color = new Color(0.5f, 0.0f, 0.0f);
}
do
{
letterIndex++;
} while (letterIndex < currentWord.Length && currentWord[letterIndex] == ' ');
// Change the color of the next letter or change to new word
if (letterIndex < currentWord.Length)
{
letters[letterIndex].GetComponent().color = Color.yellow;
}
else
{
StartCoroutine(Wait());
NextWord();
}
}
///
/// Display next word in the series
///
public void NextWord()
{
DeleteWord();
spelledWords++;
if (wordIndex < words.Count)
{
currentWord = words[wordIndex].name;
letterIndex = 0;
DisplayWord(currentWord);
wordIndex++;
}
else
{
ActivateWin();
}
}
///
/// Displays the word that needs to be spelled
///
/// The word to display
public void DisplayWord(string word)
{
for (int i = 0; i < word.Length; i++)
{
// Create instance of prefab
GameObject instance = GameObject.Instantiate(letterPrefab, letterContainer);
letters.Add(instance);
// Dynamically load appearance
char c = Char.ToUpper(word[i]);
Image background = instance.GetComponent();
background.color = i == 0 ? Color.yellow : c != ' ' ? Color.red : Color.clear;
TMP_Text txt = instance.GetComponentInChildren();
txt.text = Char.ToString(c);
}
wordImage.sprite = words[wordIndex].image;
}
///
/// wait for 2 seconds
///
///
private IEnumerator Wait()
{
yield return new WaitForSecondsRealtime(2);
}
}