Files
unity-application/Assets/SpellingBee/Scripts/GameController.cs
Dries Van Schuylenbergh 852a17b0b4 Integrate minigame and courses
2023-03-08 19:07:57 +00:00

339 lines
9.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using static Unity.VisualScripting.Member;
using UnityEditor;
public class GameController : MonoBehaviour
{
// All of the words that can be used in this session
private string[] words;
// 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
private ThemeList themeList;
// The theme we are currently using
private Theme currentTheme;
// The input field for testing purposes
public TMP_InputField input;
// Current value of timer in seconds
private float timerValue;
// "Game over" or "You win!"
public TMP_Text endText;
// First score display
public TMP_Text correctWordsText;
// Second score display
public TMP_Text correctLettersText;
// The game over panel
public GameObject gameEndedPanel;
// Button for restarting the game
public Button replayButton;
// 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 int secondsPerLetter = 1;
// Counter that keeps track of how many words have been spelled correctly
private int spelledLetters;
// Counter that keeps track of how many letters have been spelled correctly
private int spelledWords;
[Header("User")]
// 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 progress of the current user
private Progress progress = null;
[Header("Minigame")]
// Reference to the minigame ScriptableObject
public Minigame minigame;
[Header("Letter prefab")]
// Letter prefab
public GameObject letterPrefab;
[Header("UI References")]
// Reference to letter prefab
public Transform letterContainer;
// The Image component for displaying the appropriate sprite
public Image wordImage;
// Timer display
public TMP_Text timerText;
[Header("Private Variables")]
// The GameObjects representing the letters
private List<GameObject> letters = new List<GameObject>();
// Start is called before the first frame update
public void Start()
{
spelledLetters = 0;
// We use -1 instead of 0 so SetNextWord can simply increment it each time
spelledWords = -1;
gameEnded = false;
wordIndex = 0;
input.text = "";
timerValue = 0.0f;
gameEndedPanel.SetActive(false);
replayButton.onClick.AddListener(Start);
// Create entry in current user for keeping track of progress
user = userList.users[userList.currentUserIndex];
progress = user.minigames.Find((p) => p != null && p.Get<MinigameIndex>("minigameIndex") == minigame.index);
if (progress == null)
{
progress = new Progress();
progress.AddOrUpdate<MinigameIndex>("minigameIndex", MinigameIndex.SPELLING_BEE);
// TODO: add progress we want to keep track off
// (for example 'highscore')
progress.AddOrUpdate<int>("highscore", 0);
user.minigames.Add(progress);
}
EditorUtility.SetDirty(user);
// TODO: change to ScriptableObject
themeList = ThemeLoader.LoadJson();
currentTheme = FindThemeByName(PlayerPrefs.GetString("themeName"));
words = currentTheme.words;
ShuffleWords();
SetNextWord();
}
// Update is called once per frame
public void Update()
{
if (!gameEnded)
{
if (input.text.Length > 0)
{
CheckChar(input.text[0]);
}
timerValue -= 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
private void ShuffleWords()
{
for (int i = words.Length - 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]);
}
}
// Displays the game over panel and score values
private void ActivateGameOver()
{
DeleteWord();
endText.text = "GAME OVER";
correctLettersText.text = "Correctly spelled letters: " + spelledLetters.ToString();
correctWordsText.text = "Correctly spelled words: " + spelledWords.ToString();
gameEndedPanel.SetActive(true);
gameEndedPanel.transform.SetAsLastSibling();
gameEnded = true;
}
// Display win screen
private void ActivateWin()
{
int score = words.Length;
// Update progress
// TODO: update all tracked progress
int highscore = progress.Get<int>("highscore");
if (score < highscore)
{
progress.AddOrUpdate<int>("highsscore", score);
EditorUtility.SetDirty(user);
}
// @lukas stuff
DeleteWord();
endText.text = "YOU WIN!";
correctLettersText.text = "Your time: " + spelledLetters.ToString();
int totalWordsDuration = 0;
foreach (string word in words)
{
totalWordsDuration += word.Length * secondsPerLetter + 1;
}
// How much time was spent by the player
int spentTime = totalWordsDuration - (int)timerValue;
int seconds = spentTime % 60;
int minutes = spentTime / 60;
if (minutes == 0)
{
correctLettersText.text = "Your time: " + seconds + " seconds";
}
else
{
correctLettersText.text = "Your time: " + minutes + " minutes and " + seconds + " seconds";
}
correctWordsText.text = "";
gameEndedPanel.SetActive(true);
gameEndedPanel.transform.SetAsLastSibling();
gameEnded = true;
}
// Check if the correct char has been given as input
private void CheckChar(char letter)
{
if (Char.ToUpper(letter) == Char.ToUpper(currentWord[letterIndex]) && input.text.Length == 1)
{
letters[letterIndex].GetComponent<Image>().color = Color.green;
input.text = "";
spelledLetters++;
letterIndex++;
if (letterIndex >= currentWord.Length)
{
DeleteWord();
StartCoroutine(Wait());
SetNextWord();
}
}
}
// Delete all letter objects
private void DeleteWord()
{
for (int i = 0; i < letters.Count; i++)
{
Destroy(letters[i]);
}
letters.Clear();
}
// Adds seconds to timer
private void AddSeconds(int seconds)
{
timerValue += (float)seconds;
}
// Find the chosen theme by its name
private Theme FindThemeByName(string themeName)
{
int themeIndex = 0;
while (themeIndex < themeList.themes.Length)
{
Theme theme = themeList.themes[themeIndex];
if (theme.name == themeName)
{
return theme;
}
themeIndex++;
}
Debug.Log("Requested theme not found");
return null;
}
// Display next word in the series
private void SetNextWord()
{
spelledWords++;
if (wordIndex < words.Length)
{
currentWord = words[wordIndex];
ChangeSprite(currentWord);
DisplayWord(currentWord);
AddSeconds(currentWord.Length * secondsPerLetter + 1);
letterIndex = 0;
wordIndex++;
}
else
{
ActivateWin();
}
}
// Displays the word that needs to be spelled
private 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
Image background = instance.GetComponent<Image>();
background.color = Color.red;
TMP_Text txt = instance.GetComponentInChildren<TMP_Text>();
txt.text = Char.ToString(Char.ToUpper(word[i]));
}
}
// Change the image that is being displayed
private void ChangeSprite(string spriteName)
{
// Load the new sprite from the Resources folder
Sprite sprite = Resources.Load<Sprite>("SpellingBee/images/" + spriteName);
// Set the new sprite as the Image component's source image
wordImage.sprite = sprite;
}
private IEnumerator Wait()
{
yield return new WaitForSecondsRealtime(2);
}
}