diff --git a/Assets/Common/Scenes/Boot.unity b/Assets/Common/Scenes/Boot.unity
index 3b18f14..f0a8103 100644
--- a/Assets/Common/Scenes/Boot.unity
+++ b/Assets/Common/Scenes/Boot.unity
@@ -513,10 +513,10 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
- m_UiScaleMode: 0
+ m_UiScaleMode: 1
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
- m_ReferenceResolution: {x: 800, y: 600}
+ m_ReferenceResolution: {x: 1920, y: 1080}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
diff --git a/Assets/Common/Scripts/CourseActivityScreen.cs b/Assets/Common/Scripts/CourseActivityScreen.cs
index c5fbd81..c589316 100644
--- a/Assets/Common/Scripts/CourseActivityScreen.cs
+++ b/Assets/Common/Scripts/CourseActivityScreen.cs
@@ -39,6 +39,7 @@ public class CourseActivityScreen : MonoBehaviour
///
public Image courseImage;
+
///
/// Progress bar Display
///
diff --git a/Assets/Courses/Scripts/CoursesController.cs b/Assets/Courses/Scripts/CoursesController.cs
index 7661a04..f5af8fe 100644
--- a/Assets/Courses/Scripts/CoursesController.cs
+++ b/Assets/Courses/Scripts/CoursesController.cs
@@ -1,6 +1,7 @@
using DigitalRuby.Tween;
using System;
using System.Collections;
+using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
@@ -170,10 +171,26 @@ public class CoursesController : AbstractFeedback
void Start()
{
StartCourseController();
+ signPredictor.SetSignsList(GetSignsList());
signPredictor.SetModel(course.theme.modelIndex);
AddSelfAsListener();
}
+ ///
+ /// Fetches all the strings of the signs of the course
+ ///
+ /// The signsList that needs to be passed to the signPredictor
+ private List GetSignsList()
+ {
+ List signsList = new List();
+ foreach (Learnable learnable in course.theme.learnables)
+ {
+ signsList.Add(learnable.name);
+ }
+
+ return signsList;
+ }
+
///
/// Holds the course-specific logic to start the controller, it is seperated to allow the course to be reset (if that would become needed)
///
@@ -410,6 +427,7 @@ public class CoursesController : AbstractFeedback
float accPredictSign = signPredictor.learnableProbabilities[predictedSign];
Learnable predSign = course.theme.learnables.Find(l => l.name.ToUpper().Replace(" ", "-") == predictedSign);
+ // If there is a feedback-object, we wil change its appearance
if (feedbackText != null && feedbackProgressImage != null)
{
Color col;
@@ -439,6 +457,7 @@ public class CoursesController : AbstractFeedback
feedbackText.color = col;
feedbackProgressImage.color = col;
+ // Tween the feedback-bar
float oldValue = feedbackProgress.value;
// use an exponential scale
float newValue = Mathf.Exp(4 * (Mathf.Clamp(accCurrentSign / sign.thresholdPercentage, 0.0f, 1.0f) - 1.0f));
@@ -451,6 +470,7 @@ public class CoursesController : AbstractFeedback
});
}
+ // The internal logic for the courses
if (accPredictSign > sign.thresholdPercentage)
{
// Correct sign
diff --git a/Assets/Hangman/Scenes/HangmanGame.unity b/Assets/Hangman/Scenes/HangmanGame.unity
index 1acc316..98c396d 100644
--- a/Assets/Hangman/Scenes/HangmanGame.unity
+++ b/Assets/Hangman/Scenes/HangmanGame.unity
@@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
- m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1}
+ m_IndirectSpecularColor: {r: 0.37311918, g: 0.3807398, b: 0.35872716, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
@@ -2241,7 +2241,9 @@ MonoBehaviour:
m_text: 'Speler 1 geeft een woord in aan de hand van vingerspelling.
Het woord
- moet tussen 3 en 17 letters zijn.'
+ moet tussen 3 en 17 letters zijn.
+
+ Je kan letters verwijderen met backspace.'
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
@@ -3276,7 +3278,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
- m_text:
+ m_text: AZERTY
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
@@ -4540,6 +4542,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3576f66af2a0eea42ae06ac73d9779e6, type: 3}
m_Name:
m_EditorClassIdentifier:
+ scoreboardEntriesContainer: {fileID: 2082181368}
+ scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
endText: {fileID: 1205429732}
lettersRightText: {fileID: 815411823}
lettersWrongText: {fileID: 1606437998}
@@ -4547,19 +4551,7 @@ MonoBehaviour:
accuracyText: {fileID: 1341392955}
wordText: {fileID: 328407984}
scoreText: {fileID: 941310846}
- scoreboardEntriesContainer: {fileID: 2082181368}
- scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
image: {fileID: 1503788513}
- sprites:
- - {fileID: 21300000, guid: 46b9ec93c5782294f93be12a7c7bc3f0, type: 3}
- - {fileID: 21300000, guid: 0a2c6671fa08a1249ba97ddd3432ac60, type: 3}
- - {fileID: 21300000, guid: e5b621bb42e52654d88ad633777004a8, type: 3}
- - {fileID: 21300000, guid: 42b25d40421cfce4684bad733747c2e3, type: 3}
- - {fileID: 21300000, guid: 76120f6b7a0251949a56f73d49985d3a, type: 3}
- - {fileID: 21300000, guid: c9b599bbbe306584a926c415d7e96983, type: 3}
- - {fileID: 21300000, guid: 3fa072f7f8a26cf45b84781ce2dfdc51, type: 3}
- - {fileID: 21300000, guid: 3f6826496e2a1334ab74ec68262b2c11, type: 3}
- - {fileID: 21300000, guid: 98ec939c075818c4e869916da0b33aad, type: 3}
--- !u!1 &987091747
GameObject:
m_ObjectHideFlags: 0
@@ -7675,6 +7667,10 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
signPredictor: {fileID: 1991376311}
+ minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2}
+ feedbackProgress: {fileID: 211555568}
+ webcamScreen: {fileID: 1966441454}
+ gameEndedPanel: {fileID: 974474713}
themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2}
fingerSpelling: {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2}
letterPrefab: {fileID: 4639383499500021565, guid: c3e66e8957864914cb022af914df6a28, type: 3}
@@ -7696,15 +7692,10 @@ MonoBehaviour:
inputPanel: {fileID: 640467091}
scoreDisplay: {fileID: 2026578772}
scoreBonus: {fileID: 1537143412}
- gameEndedPanel: {fileID: 974474713}
- minigame: {fileID: 11400000, guid: 165c1d9867275924d9720d409e935f95, type: 2}
- minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2}
gotoGameButton: {fileID: 482979078}
inputTextField: {fileID: 752351940}
feedbackText: {fileID: 887237819}
- feedbackProgress: {fileID: 211555568}
feedbackProgressImage: {fileID: 1107240765}
- webcamScreen: {fileID: 1966441454}
timerCircle: {fileID: 683997248}
confirmPanel: {fileID: 1002919202}
confirmText: {fileID: 1672600188}
diff --git a/Assets/Hangman/Scripts/HangmanController.cs b/Assets/Hangman/Scripts/HangmanController.cs
index 3862eec..f65b0ca 100644
--- a/Assets/Hangman/Scripts/HangmanController.cs
+++ b/Assets/Hangman/Scripts/HangmanController.cs
@@ -1,15 +1,14 @@
using DigitalRuby.Tween;
using System;
-using System.Collections;
using System.Collections.Generic;
-using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
-public class HangmanController : AbstractFeedback
+public class HangmanController : AbstractMinigameController
{
+ [Header("ConcreteVariables")]
///
/// The scriptable with all the themes, will be used to select a random word for hangman.
/// The spellingthemeList will be used for the words.
@@ -17,7 +16,7 @@ public class HangmanController : AbstractFeedback
public ThemeList themeList;
///
- /// reference to the fingerspelling-theme to reach the letter-thresholds
+ /// reference to the fingerspelling-theme to reach the letter-thresholds and to pass to the signPredictor
///
public Theme fingerSpelling;
@@ -96,11 +95,6 @@ public class HangmanController : AbstractFeedback
///
public TMP_Text scoreBonus;
- /////
- ///// This panel holds the panels for input and playing the game, sharing webcam and feedback
- /////
- //public GameObject inputGamePanel;
-
///
/// This int shows what mode we are in, used in update:
/// 0 : single or multiplayer?
@@ -111,27 +105,6 @@ public class HangmanController : AbstractFeedback
///
private int mode;
- ///
- /// The game over panel
- ///
- public GameObject gameEndedPanel;
-
- ///
- /// 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;
-
- ///
- /// Reference to the current user
- ///
- private User user;
-
///
/// The button to go into the game
///
@@ -152,21 +125,11 @@ public class HangmanController : AbstractFeedback
///
public TMP_Text feedbackText;
- ///
- /// Reference to the progress bar
- ///
- public Slider feedbackProgress;
-
///
/// Reference to the progress bar image, so we can add fancy colors
///
public Image feedbackProgressImage;
- ///
- /// reference to the webcam background
- ///
- public RawImage webcamScreen;
-
///
/// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs
///
@@ -239,48 +202,11 @@ public class HangmanController : AbstractFeedback
private int winScore = 25;
///
- /// Start is called before the first frame update
+ /// Set the AbstractMinigameController variable to inform it of the theme for the signPredictor
///
- void Start()
+ protected override Theme signPredictorTheme
{
- signPredictor.SwapScreen(webcamScreen);
- signPredictor.SetModel(ModelIndex.FINGERSPELLING);
- AddSelfAsListener();
-
- StartController();
- }
-
- ///
- /// Called at the start of the scene AND when the scene is replayed
- ///
- public void StartController()
- {
- // Make sure the mode starts at zero
- mode = 0;
-
-
- // Make sure that only the player-selection panel is the one shown
- gamePanel.SetActive(false);
- inputPanel.SetActive(false);
- playerPanel.SetActive(true);
-
- // Make sure that unneeded panels are inactive
- gameEndedPanel.SetActive(false);
- confirmPanel.SetActive(false);
-
- // Create entry in current user for keeping track of progress
- user = UserList.GetCurrentUser();
- var progress = user.GetMinigameProgress(minigame.index);
- if (progress == null)
- {
- progress = new PersistentDataController.SavedMinigameProgress();
- progress.minigameIndex = minigame.index;
- user.AddMinigameProgress(progress);
- }
- UserList.Save();
-
- // Guesses needs to be created instantly because it is used in the FeedbackLoop
- //guesses = new List();
+ get { return fingerSpelling; }
}
///
@@ -289,7 +215,7 @@ public class HangmanController : AbstractFeedback
public void StartGame()
{
// Change the mode
- mode = 2;
+ SwitchMode(2);
// Activate the right panel
gamePanel.SetActive(true);
@@ -334,11 +260,7 @@ public class HangmanController : AbstractFeedback
public void GoToInput()
{
// Change the mode
- mode = 1;
-
- // Initialise the word to an empty String
- currentWord = "";
- inputTextField.text = currentWord.ToUpper();
+ SwitchMode(1);
// Activate the right panel
gamePanel.SetActive(false);
@@ -346,7 +268,11 @@ public class HangmanController : AbstractFeedback
inputPanel.SetActive(true);
playerPanel.SetActive(false);
+ // Initialise the word to an empty String
+ currentWord = "";
+
PanelMultiplayerInput script = inputPanel.GetComponent();
+ script.inputTextField.text = "";
gotoGameButton = script.gotoGameButton;
inputTextField = script.inputTextField;
@@ -470,7 +396,7 @@ public class HangmanController : AbstractFeedback
{
confirmPanel.SetActive(true);
confirmText.text = $"Letter '{currentSign.ToUpper()}' ?";
- mode = 4;
+ SwitchMode(4);
}
}
break;
@@ -478,7 +404,7 @@ public class HangmanController : AbstractFeedback
case 2: // Sign your letter
if (!guesses.Contains(currentSign))
{
- mode = 3;
+ SwitchMode(3);
ConfirmAccept();
}
break;
@@ -517,24 +443,23 @@ public class HangmanController : AbstractFeedback
usedLettersText.text += letter.ToString().ToUpper();
// The current sign was accepted, return to the game
- mode = 2;
-
- if (corrects == currentWord.Replace(" ", "").Length)
+ SwitchMode(2);
+ if (corrects == currentWord.Length)
{
// Victory, deactivate the model and show the scoreboard
- ActivateWin();
+ ActivateEnd(true);
}
else if (NUMBER_OF_FAILS_BEFORE_GAMEOVER < wrongs)
{
// You lost, deactivate the model and show the scoreboard
- ActivateGameOver();
+ ActivateEnd(false);
}
}
else if (mode == 4)
{
currentWord += letter;
inputTextField.text = currentWord.ToUpper();
- mode = 1;
+ SwitchMode(1);
}
}
@@ -544,9 +469,23 @@ public class HangmanController : AbstractFeedback
// The current sign was rejected, return to the game-mode
if (mode == 3)
- mode = 2;
+ SwitchMode(2);
else if (mode == 4)
- mode = 1;
+ SwitchMode(1);
+ }
+
+ public void SwitchMode(int mode)
+ {
+ this.mode = mode;
+ // In mode 1 and 2, the signPredictor needs to run, otherwise it does not
+ if (mode == 1 || mode == 2)
+ {
+ gameIsActive = true;
+ }
+ else
+ {
+ gameIsActive = false;
+ }
}
///
@@ -599,7 +538,7 @@ public class HangmanController : AbstractFeedback
/// This function returns the score that the user currently has
///
/// The current score of the user
- private int CalculateScore()
+ public override int CalculateScore()
{
int won = corrects == currentWord.Length ? 1 : 0;
return corrects * correctLetterScore + wrongs * incorrectLetterScore + winScore * won;
@@ -640,115 +579,19 @@ public class HangmanController : AbstractFeedback
}
///
- /// Update and save the scores
+ /// The logic to process the signs sent by the signPredictor
///
- private void SaveScores()
+ /// The accuracy of the passed sign
+ /// The name of the passed sign
+ protected override void ProcessMostProbableSign(float accuracy, string predictedSign)
{
- // 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();
+ // Grab the threshold for the most probable letter
+ Learnable letter = fingerSpelling.learnables.Find((l) => l.name == predictedSign);
+ float threshold = letter.thresholdPercentage;
- // Save the new score
- var progress = user.GetMinigameProgress(minigame.index);
-
- // Get the current list of scores
- List latestScores = progress.latestScores;
- List highestScores = progress.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.latestScores = latestScores.Take(10).ToList();
- progress.highestScores = highestScores.Take(10).ToList();
-
- UserList.Save();
- }
-
- ///
- /// Display win screen
- ///
- private void ActivateWin()
- {
- // Deactivate the model
- mode = 0;
-
- // Save the scores and show the scoreboard
- SaveScores();
- gameEndedPanel.GetComponent().GenerateContent(
- guessWord: currentWord.ToLower(),
- correctLetters: corrects,
- incorrectLetters: wrongs,
- sprite: hangmanImage.sprite,
- result: "GEWONNEN",
- score: CalculateScore()
- );
-
- gameEndedPanel.SetActive(true);
-
- // @lukas stuff
- DeleteWord();
- }
-
- ///
- /// Displays the game over panel and score values
- ///
- private void ActivateGameOver()
- {
- // Deactivate the model
- mode = 0;
-
- // Save the scores and show the scoreboard
- SaveScores();
- gameEndedPanel.GetComponent().GenerateContent(
- guessWord: currentWord.ToLower(),
- correctLetters: corrects,
- incorrectLetters: wrongs,
- sprite: hangmanImage.sprite,
- result: "VERLOREN",
- score: CalculateScore()
- );
-
- gameEndedPanel.SetActive(true);
-
- DeleteWord();
- }
-
- ///
- /// The updateFunction that is called when new probabilities become available
- ///
- ///
- protected override IEnumerator UpdateFeedback()
- {
- // Get the sign with the highest prediction
- if ((mode == 1 || mode == 2) &&
- signPredictor != null &&
- signPredictor.learnableProbabilities != null)
+ // If there is a feedback-object, we wil change its appearance
+ if (feedbackText != null && feedbackProgressImage != null)
{
- KeyValuePair highestPrediction = signPredictor.learnableProbabilities.Aggregate((x, y) => x.Value > y.Value ? x : y);
- float accuracy = highestPrediction.Value;
- string predictedSign = highestPrediction.Key;
-
- // vvv TEMPORARY STUFF vvv
- if (predictedSign == "J" && accuracy <= 0.965f)
- {
- highestPrediction = signPredictor.learnableProbabilities.Aggregate((x, y) => x.Value > y.Value && x.Key != "J" ? x : y);
- }
- accuracy = highestPrediction.Value;
- predictedSign = highestPrediction.Key;
- // ^^^ TEMPORARY STUFF ^^^
-
- // Grab the threshold for the most probable letter
- Learnable letter = fingerSpelling.learnables.Find((l) => l.name == predictedSign);
- float threshold = letter.thresholdPercentage;
-
float oldValue = feedbackProgress.value;
// use an exponential scale
float newValue = Mathf.Exp(4 * (Mathf.Clamp(accuracy / threshold, 0.0f, 1.0f) - 1.0f));
@@ -781,37 +624,33 @@ public class HangmanController : AbstractFeedback
feedbackText.color = red;
feedbackProgressImage.color = red;
}
+ }
- if (accuracy > threshold)
+ // The logic for the internal workings of the game
+ if (accuracy > threshold)
+ {
+ // A different sign was predicted compared to the last call of this function
+ if (previousSign != predictedSign)
{
- if (previousSign != predictedSign)
+ // Reset the timer
+ previousSign = predictedSign;
+ currentTime = 0;
+ // If you are entering a word the timer needs to work
+ // If you are playing the game and haven't guessed the letter yet, then the timer needs to work
+ if ((mode == 1) ||
+ (mode == 2 && !guesses.Contains(previousSign.ToUpper())))
{
- // Reset the timer
- previousSign = predictedSign;
- currentTime = 0;
- if ((mode == 1) ||
- (mode == 2 && !guesses.Contains(previousSign.ToUpper())))
- {
- runTime = true;
- }
- timerCircle.fillAmount = currentTime;
+ runTime = true;
}
- else if (currentTime == maxTime)
- {
- // Set the predictedSign as your guess and update the Hangman
- currentSign = predictedSign;
- UpdateSign();
- // reset the timer and look for a new prediction
- previousSign = null;
- currentTime = 0;
- runTime = false;
- timerCircle.fillAmount = currentTime;
- }
-
+ timerCircle.fillAmount = currentTime;
}
- else
+ // The same sign was predicted as last time and said sign has been held for a sufficiently long time
+ else if (currentTime == maxTime)
{
- // The sign was dropped, reset the timer
+ // Set the predictedSign as your guess and update the Hangman
+ currentSign = predictedSign;
+ UpdateSign();
+ // reset the timer and look for a new prediction
previousSign = null;
currentTime = 0;
runTime = false;
@@ -819,11 +658,69 @@ public class HangmanController : AbstractFeedback
}
}
- else if (feedbackProgress != null)
+ else
{
-
- feedbackProgress.value = 0.0f;
+ // The sign was dropped, reset the timer
+ previousSign = null;
+ currentTime = 0;
+ runTime = false;
+ timerCircle.fillAmount = currentTime;
}
- yield return null;
+ }
+
+ ///
+ /// The logic to set the scoreboard of hangman
+ ///
+ /// SHows whether or not the player won
+ protected override void SetScoreBoard(bool victory)
+ {
+ string resultTxt;
+ if (victory)
+ {
+ resultTxt = "GEWONNEN";
+ }
+ else
+ {
+ resultTxt = "VERLOREN";
+ }
+ gameEndedPanel.GetComponent().GenerateContent(
+ guessWord: currentWord.ToLower(),
+ correctLetters: corrects,
+ incorrectLetters: wrongs,
+ sprite: hangmanImage.sprite,
+ result: resultTxt,
+ score: CalculateScore()
+ );
+ }
+
+ ///
+ /// The hangman-specific logic that needs to be called at the start of the game
+ ///
+ protected override void StartGameLogic()
+ {
+ // Make sure the mode starts at zero
+ SwitchMode(0);
+
+
+ // Make sure that only the player-selection panel is the one shown
+ gamePanel.SetActive(false);
+ inputPanel.SetActive(false);
+ playerPanel.SetActive(true);
+
+ // Make sure that unneeded panels are inactive
+ gameEndedPanel.SetActive(false);
+ confirmPanel.SetActive(false);
+ }
+
+ ///
+ /// The Hangman-specific logic that needs to be called at the end of a game
+ ///
+ ///
+ protected override void EndGameLogic(bool victory)
+ {
+ // Deactivate the model
+ SwitchMode(0);
+
+ DeleteWord();
}
}
diff --git a/Assets/Hangman/Scripts/HangmanGameEndedPanel.cs b/Assets/Hangman/Scripts/HangmanGameEndedPanel.cs
index aca391c..4e6eb8f 100644
--- a/Assets/Hangman/Scripts/HangmanGameEndedPanel.cs
+++ b/Assets/Hangman/Scripts/HangmanGameEndedPanel.cs
@@ -7,8 +7,16 @@ using UnityEngine.UI;
///
/// The hangman-variant of the ScoreBoard
///
-public class HangmanGameEndedPanel : MonoBehaviour
+public class HangmanGameEndedPanel : AbstractGameEndedPanel
{
+ ///
+ /// Tell the scoreboard that the scoreboard is for HangMan
+ ///
+ protected override MinigameIndex minigameIndex
+ {
+ get { return MinigameIndex.HANGMAN; }
+ }
+
///
/// "VERLOREN" or "GEWONNEN"
///
@@ -40,28 +48,11 @@ public class HangmanGameEndedPanel : MonoBehaviour
///
public TMP_Text scoreText;
- ///
- /// Reference to the scoreboard entries container
- ///
- public Transform scoreboardEntriesContainer;
-
- ///
- /// The GameObjects representing the letters
- ///
- private List scoreboardEntries = new List();
-
- ///
- /// Reference to the ScoreboardEntry prefab
- ///
- public GameObject scoreboardEntry;
-
///
/// Reference to the end result image
///
public Image image;
- public List sprites;
-
///
/// Generate the content of the GameEnded panel
///
@@ -99,105 +90,4 @@ public class HangmanGameEndedPanel : MonoBehaviour
scoreText.text = $"Score: {score}";
SetScoreBoard();
}
-
-
- ///
- /// Sets the scoreboard
- ///
- private void SetScoreBoard()
- {
- // Clean the previous scoreboard entries
- for (int i = 0; i < scoreboardEntries.Count; i++)
- {
- Destroy(scoreboardEntries[i]);
- }
- scoreboardEntries.Clear();
-
- // Instantiate new entries
- // Get all scores from all users
- List> allScores = new List>();
- foreach (User user in UserList.GetUsers())
- {
- // Get user's progress for this minigame
- var progress = user.GetMinigameProgress(MinigameIndex.HANGMAN);
- if (progress != null)
- {
- // Add scores to dictionary
- List scores = progress.highestScores;
- foreach (Score score in scores)
- {
- allScores.Add(new Tuple(user.GetUsername(), score));
- }
- }
- }
-
- // Sort allScores based on Score.scoreValue
- allScores.Sort((a, b) => b.Item2.scoreValue.CompareTo(a.Item2.scoreValue));
-
- // Instantiate scoreboard entries
- int rank = 1;
- foreach (Tuple tup in allScores.Take(10))
- {
- string username = tup.Item1;
- Score score = tup.Item2;
-
- GameObject entry = Instantiate(scoreboardEntry, scoreboardEntriesContainer);
- scoreboardEntries.Add(entry);
-
- // Set the player icon
- entry.transform.Find("Image").GetComponent().sprite = UserList.GetUserByUsername(username).GetAvatar();
-
- // Set the player name
- entry.transform.Find("PlayerName").GetComponent().text = username;
-
- // Set the score
- entry.transform.Find("Score").GetComponent().text = score.scoreValue.ToString();
-
- // Set the rank
- entry.transform.Find("Rank").GetComponent().text = rank.ToString();
-
- // Set the ago
- // Convert the score.time to Datetime
- DateTime time = DateTime.Parse(score.time);
- DateTime currentTime = DateTime.Now;
- TimeSpan diff = currentTime.Subtract(time);
-
- string formatted;
- if (diff.Days > 0)
- {
- formatted = $"{diff.Days}d ";
- }
- else if (diff.Hours > 0)
- {
- formatted = $"{diff.Hours}h ";
- }
- else if (diff.Minutes > 0)
- {
- formatted = $"{diff.Minutes}m ";
- }
- else
- {
- formatted = "now";
- }
-
- entry.transform.Find("Ago").GetComponent().text = formatted;
-
-
- // Alternating colors looks nice
- if (rank % 2 == 0)
- {
- Image image = entry.transform.GetComponent();
- image.color = new Color(image.color.r, image.color.g, image.color.b, 0f);
- }
-
- // Make new score stand out
- if (diff.TotalSeconds < 1)
- {
- Image image = entry.transform.GetComponent();
- image.color = new Color(0, 229, 255, 233);
- }
-
- rank++;
- }
- }
}
diff --git a/Assets/Hangman/Scripts/HangmanScripts.asmdef b/Assets/Hangman/Scripts/HangmanScripts.asmdef
index ec792c4..161066e 100644
--- a/Assets/Hangman/Scripts/HangmanScripts.asmdef
+++ b/Assets/Hangman/Scripts/HangmanScripts.asmdef
@@ -5,9 +5,10 @@
"GUID:e83ddf9a537a96b4a804a16bb7872ec1",
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:1631ed2680c61245b8211d943c1639a8",
- "GUID:d0b6b39a21908f94fbbd9f2c196a9725",
"GUID:58e104b97fb3752438ada2902a36dcbf",
- "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
+ "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
+ "GUID:403dd94a93598934eb522dc36df43d7b",
+ "GUID:d0b6b39a21908f94fbbd9f2c196a9725"
],
"includePlatforms": [],
"excludePlatforms": [],
diff --git a/Assets/JustSign/Scenes/JustSignGame.unity b/Assets/JustSign/Scenes/JustSignGame.unity
index a80a109..21b1120 100644
--- a/Assets/JustSign/Scenes/JustSignGame.unity
+++ b/Assets/JustSign/Scenes/JustSignGame.unity
@@ -1557,20 +1557,19 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
signPredictor: {fileID: 1150323775}
+ minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2}
+ feedbackProgress: {fileID: 1753834854}
+ webcamScreen: {fileID: 496523654}
+ gameEndedPanel: {fileID: 2498222378566216023}
answerField: {fileID: 0}
timingFeedback: {fileID: 128049076}
scoreDisplay: {fileID: 1627575593}
- minigame: {fileID: 11400000, guid: e726e0b93ea88465db7ee27605deb83f, type: 2}
- minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2}
songList: {fileID: 11400000, guid: 4f0ce70309bb901feb28199a82a7d195, type: 2}
hitZonePerfect: {fileID: 2012531008}
hitZoneGood: {fileID: 369868393}
hitZoneMeh: {fileID: 141066497}
- webcamScreen: {fileID: 496523654}
symbolPrefab: {fileID: 4639383499500021565, guid: f3117b0203a1342a48a95904347b03c8, type: 3}
symbolContainer: {fileID: 2093721209}
- scoreboardEntriesContainer: {fileID: 2498222377153197597}
- scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
lpmText: {fileID: 2498222377094258231}
perfectSignsText: {fileID: 2498222378642934129}
goodSignsText: {fileID: 524776817}
@@ -1578,9 +1577,7 @@ MonoBehaviour:
terribleSignsText: {fileID: 1343527143}
notFoundSignsText: {fileID: 850357042}
scoreText: {fileID: 2498222378754007924}
- gameEndedPanel: {fileID: 2498222378566216023}
feedbackText: {fileID: 1753834853}
- feedbackProgressBar: {fileID: 1753834854}
feedbackProgressImage: {fileID: 1753834852}
perfectSprite: {fileID: 21300000, guid: 43b0de2d8fcec1540bb9989e45db4581, type: 3}
goodSprite: {fileID: 21300000, guid: 168acd43cf46d1c419991a2620485bf6, type: 3}
@@ -1857,7 +1854,7 @@ MonoBehaviour:
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
modelInfoFileEmbedding: {fileID: 4900000, guid: 4e303164823194bc4be87f4c9550cfd0, type: 3}
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
- screen: {fileID: 0}
+ screen: {fileID: 496523654}
--- !u!4 &1150323776
Transform:
m_ObjectHideFlags: 0
@@ -3524,7 +3521,7 @@ GameObject:
- component: {fileID: 2498222377094258230}
- component: {fileID: 2498222377094258231}
m_Layer: 5
- m_Name: LPM
+ m_Name: GPM
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -3578,7 +3575,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
- m_text: XXX LPM
+ m_text: XXX GPM
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
@@ -4700,29 +4697,6 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2498222378566216023}
m_CullTransparentMesh: 1
---- !u!114 &2498222378566215979
-MonoBehaviour:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 2498222378566216023}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: 5aa929dce1f59b340b4a0cca1bb68edc, type: 3}
- m_Name:
- m_EditorClassIdentifier:
- endText: {fileID: 2498222377166680336}
- lpmText: {fileID: 2498222377094258231}
- lettersRightText: {fileID: 0}
- lettersWrongText: {fileID: 0}
- lettersTotalText: {fileID: 0}
- accuracyText: {fileID: 2498222378642934129}
- wordsText: {fileID: 0}
- timeText: {fileID: 0}
- scoreText: {fileID: 2498222378754007924}
- scoreboardEntriesContainer: {fileID: 2498222377153197597}
- scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
--- !u!224 &2498222378566216020
RectTransform:
m_ObjectHideFlags: 0
@@ -4788,7 +4762,7 @@ GameObject:
- component: {fileID: 2498222378566216020}
- component: {fileID: 2498222378566215978}
- component: {fileID: 2498222378566216021}
- - component: {fileID: 2498222378566215979}
+ - component: {fileID: 2498222378566216024}
m_Layer: 5
m_Name: GameEnded Panel
m_TagString: Untagged
@@ -4796,6 +4770,27 @@ GameObject:
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
+--- !u!114 &2498222378566216024
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2498222378566216023}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 9a86c239be1aa1543ba8a4ace5f658b1, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ scoreboardEntriesContainer: {fileID: 2498222377153197597}
+ scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
+ perfectSignsText: {fileID: 2498222378642934129}
+ goodSignsText: {fileID: 524776817}
+ mehSignsText: {fileID: 6218584}
+ terribleSignsText: {fileID: 1343527143}
+ notFoundSignsText: {fileID: 850357042}
+ gpmText: {fileID: 2498222377094258231}
+ scoreText: {fileID: 2498222378754007924}
--- !u!1 &2498222378611643141
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/JustSign/Scripts/JustSignController.cs b/Assets/JustSign/Scripts/JustSignController.cs
index 032986d..b0ea321 100644
--- a/Assets/JustSign/Scripts/JustSignController.cs
+++ b/Assets/JustSign/Scripts/JustSignController.cs
@@ -1,8 +1,6 @@
using DigitalRuby.Tween;
-using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
@@ -11,7 +9,7 @@ using Random = UnityEngine.Random;
///
/// Contains all game logic for the JustSign game
///
-public class JustSignController : AbstractFeedback
+public class JustSignController : AbstractMinigameController
{
///
/// All of the words that can be used in this session
@@ -33,17 +31,6 @@ public class JustSignController : AbstractFeedback
///
public TMP_Text scoreDisplay;
- ///
- /// 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;
-
///
/// Reference to the list of available songs
///
@@ -69,11 +56,6 @@ public class JustSignController : AbstractFeedback
///
public RectTransform hitZoneMeh;
- ///
- /// Reference to the webcam
- ///
- public RawImage webcamScreen;
-
///
/// Score obtained when getting a perfect hit
///
@@ -124,11 +106,6 @@ public class JustSignController : AbstractFeedback
///
private List activeSymbols = new List();
- ///
- /// Have the symbols started spawning or not
- ///
- private bool gameIsActive = false;
-
///
/// Controls movement speed of symbols (higher -> faster)
///
@@ -184,26 +161,6 @@ public class JustSignController : AbstractFeedback
///
private int incorrectSigns;
- ///
- /// Reference to the scoreboard entries container
- ///
- public Transform scoreboardEntriesContainer;
-
- ///
- /// The GameObjects representing the letters
- ///
- private List scoreboardEntries = new List();
-
- ///
- /// Reference to the ScoreboardEntry prefab
- ///
- public GameObject scoreboardEntry;
-
- ///
- /// Reference to the current user
- ///
- private User user;
-
///
/// LPM
///
@@ -239,21 +196,11 @@ public class JustSignController : AbstractFeedback
///
public TMP_Text scoreText;
- ///
- /// Reference to the gameEnded panel, so we can update its display
- ///
- public GameObject gameEndedPanel;
-
///
/// Reference to the feedback field
///
public TMP_Text feedbackText;
- ///
- /// Reference to the progress bar
- ///
- public Slider feedbackProgressBar;
-
///
/// Reference to the progress bar image, so we can add fancy colors
///
@@ -299,53 +246,9 @@ public class JustSignController : AbstractFeedback
///
public GameObject userFeedback;
- ///
- /// Start is called before the first frame update
- ///
- public void Start()
+ protected override Theme signPredictorTheme
{
- currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
- signPredictor.SetModel(currentTheme.modelIndex);
- signPredictor.SwapScreen(webcamScreen);
- AddSelfAsListener();
-
- StartController();
- }
-
- ///
- /// Holds the game-specific logic to start the controller
- ///
- public void StartController()
- {
- userFeedback.SetActive(currentTheme.modelIndex != ModelIndex.NONE);
- previewMessage.SetActive(currentTheme.modelIndex == ModelIndex.NONE);
- perfectSigns = 0;
- goodSigns = 0;
- mehSigns = 0;
- terribleSigns = 0;
- incorrectSigns = 0;
- timingFeedback.text = "";
- imageFeedback.sprite = minigame.thumbnail;
- gameEndedPanel.SetActive(false);
- // Create entry in current user for keeping track of progress
- user = UserList.GetCurrentUser();
- var progress = user.GetMinigameProgress(minigame.index);
- if (progress == null)
- {
- progress = new PersistentDataController.SavedMinigameProgress();
- progress.minigameIndex = minigame.index;
- user.AddMinigameProgress(progress);
- }
- UserList.Save();
-
- scoreDisplay.text = $"Score: {CalculateScore()}";
- words.AddRange(currentTheme.learnables);
- currentSong = songList.songs[songList.currentSongIndex];
- AudioSource.PlayClipAtPoint(currentSong.song, Vector3.zero, 1.0f);
- beginTime = Time.time;
- lastSymbolTime = beginTime + currentSong.duration - 1920.0f / moveSpeed;
-
- StartCoroutine(WaitThenStart(currentSong.firstSymbolTime));
+ get { return currentTheme; }
}
///
@@ -388,7 +291,8 @@ public class JustSignController : AbstractFeedback
// Check if the song has ended and activate scorescreen if it has
if (currentTime - beginTime > currentSong.duration)
{
- ActivateEnd();
+ // The boolean that is passed is irrelevant for this game
+ ActivateEnd(true);
}
// Move all active symbols to the right
@@ -406,28 +310,11 @@ public class JustSignController : AbstractFeedback
/// Calculate the score
///
/// The calculated score
- public int CalculateScore()
+ public override int CalculateScore()
{
return goodSigns * goodScore + perfectSigns * perfectScore + mehScore * mehSigns + terribleScore * terribleSigns + incorrectSigns * offscreenScore;
}
- ///
- /// Display Scoreboard + Metrics
- ///
- public void ActivateEnd()
- {
- gameIsActive = false;
- while (activeSymbols.Count > 0)
- {
- DestroySymbolAt(0);
- }
- // TODO: Scoreboard
- SaveScores();
- SetScoreMetrics();
- SetScoreBoard();
- gameEndedPanel.SetActive(true);
- }
-
///
/// Destroy the symbol at the given index
///
@@ -474,282 +361,160 @@ public class JustSignController : AbstractFeedback
}
///
- /// Update and save the scores
+ /// The logic to process the signs sent by the signPredictor
///
- public void SaveScores()
+ /// The accuracy of the passed sign
+ /// The name of the passed sign
+ protected override void ProcessMostProbableSign(float accuracy, string predictedSign)
{
- // Calculate new score
- int newScore = CalculateScore();
+ Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper() == predictedSign);
- // 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
- var progress = user.GetMinigameProgress(minigame.index);
-
- // Get the current list of scores
- List latestScores = progress.latestScores;
- List highestScores = progress.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.latestScores = latestScores.Take(10).ToList();
- progress.highestScores = highestScores.Take(10).ToList();
-
- PersistentDataController.GetInstance().Save();
- }
-
- ///
- /// Set score metrics
- ///
- private void SetScoreMetrics()
- {
- // In de zone
- perfectSignsText.text = perfectSigns.ToString();
-
- // Aanvaardbaar
- goodSignsText.text = goodSigns.ToString();
-
- // Nipt
- mehSignsText.text = mehSigns.ToString();
-
- // Slechte timing
- terribleSignsText.text = terribleSigns.ToString();
-
- // Niet Geraden
- notFoundSignsText.text = incorrectSigns.ToString();
-
- // LPM
- int duration = songList.songs[songList.currentSongIndex].duration;
- int correctSigns = goodSigns + perfectSigns + mehSigns + terribleSigns;
- lpmText.text = (60f * correctSigns / duration).ToString("#") + " GPM";
-
- // Score
- scoreText.text = $"Score: {CalculateScore()}";
- }
-
- ///
- /// Sets the scoreboard
- ///
- private void SetScoreBoard()
- {
- // Clean the previous scoreboard entries
- for (int i = 0; i < scoreboardEntries.Count; i++)
+ // If there is a feedback-object, we wil change its appearance
+ if (feedbackText != null && feedbackProgressImage != null)
{
- Destroy(scoreboardEntries[i]);
- }
- scoreboardEntries.Clear();
-
- // Instantiate new entries
- // Get all scores from all users
- List> allScores = new List>();
- foreach (User user in UserList.GetUsers())
- {
- // Get user's progress for this minigame
- var progress = user.GetMinigameProgress(minigame.index);
- if (progress != null)
+ Color col;
+ if (accuracy > predSign.thresholdPercentage)
{
- // Add scores to dictionary
- List scores = progress.highestScores;
- foreach (Score score in scores)
- {
- allScores.Add(new Tuple(user.GetUsername(), score));
- }
+ feedbackText.text = $"Herkent '{predictedSign}'";
+ col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
}
- }
-
- // Sort allScores based on Score.scoreValue
- allScores.Sort((a, b) => b.Item2.scoreValue.CompareTo(a.Item2.scoreValue));
-
- // Instantiate scoreboard entries
- int rank = 1;
- foreach (Tuple tup in allScores.Take(10))
- {
- string username = tup.Item1;
- Score score = tup.Item2;
-
- GameObject entry = Instantiate(scoreboardEntry, scoreboardEntriesContainer);
- scoreboardEntries.Add(entry);
-
- // Set the player icon
- entry.transform.Find("Image").GetComponent().sprite = UserList.GetUserByUsername(username).GetAvatar();
-
- // Set the player name
- entry.transform.Find("PlayerName").GetComponent().text = username;
-
- // Set the score
- entry.transform.Find("Score").GetComponent().text = score.scoreValue.ToString();
-
- // Set the rank
- entry.transform.Find("Rank").GetComponent().text = rank.ToString();
-
- // Set the ago
- // Convert the score.time to Datetime
- DateTime time = DateTime.Parse(score.time);
- DateTime currentTime = DateTime.Now;
- TimeSpan diff = currentTime.Subtract(time);
-
- string formatted;
- if (diff.Days > 0)
+ else if (accuracy > 0.9 * predSign.thresholdPercentage)
{
- formatted = $"{diff.Days}d ";
- }
- else if (diff.Hours > 0)
- {
- formatted = $"{diff.Hours}h ";
- }
- else if (diff.Minutes > 0)
- {
- formatted = $"{diff.Minutes}m ";
+ feedbackText.text = $"Lijkt op '{predictedSign}'";
+ col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f);
}
else
{
- formatted = "now";
+ feedbackText.text = "Detecteren...";
+ col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
}
- entry.transform.Find("Ago").GetComponent().text = formatted;
+ feedbackText.color = col;
+ feedbackProgressImage.color = col;
-
- // Alternating colors looks nice
- if (rank % 2 == 0)
+ float oldValue = feedbackProgress.value;
+ // use an exponential scale
+ float newValue = Mathf.Exp(4 * (Mathf.Clamp(accuracy / predSign.thresholdPercentage, 0.0f, 1.0f) - 1.0f));
+ feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
{
- Image image = entry.transform.GetComponent();
- image.color = new Color(image.color.r, image.color.g, image.color.b, 0f);
- }
+ if (feedbackProgress != null)
+ {
+ feedbackProgress.value = t.CurrentValue;
+ }
+ });
+ }
- // Make new score stand out
- if (diff.TotalSeconds < 1)
+ // The logic for the internal workings of the game
+ if (accuracy > predSign.thresholdPercentage)
+ {
+ int matchedSymbolIndex = activeWords.IndexOf(predictedSign.ToUpper());
+
+ // Destroy the oldest symbol if the current input matches it
+ if (0 <= matchedSymbolIndex)
{
- Image image = entry.transform.GetComponent();
- image.color = new Color(0, 229, 255, 233);
- }
+ float x = activeSymbols[matchedSymbolIndex].transform.localPosition.x;
- rank++;
+ // parameters to define the Perfect hit zone
+ float perfectRange = hitZonePerfect.sizeDelta.x;
+ float perfectCenter = hitZonePerfect.localPosition.x;
+ // parameters to define the Good hit zone
+ float goodRange = hitZoneGood.sizeDelta.x;
+ float goodCenter = hitZoneGood.localPosition.x;
+ // parameters to define the Meh hit zone
+ float mehRange = hitZoneMeh.sizeDelta.x;
+ float mehCenter = hitZoneMeh.localPosition.x;
+
+ if (perfectCenter - perfectRange / 2 <= x && x <= perfectCenter + perfectRange / 2)
+ {
+ timingFeedback.text = $"Perfect! \n +{perfectScore}";
+ imageFeedback.sprite = perfectSprite;
+ perfectSigns++;
+ timingFeedback.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
+ }
+ else if (goodCenter - goodRange / 2 <= x && x <= goodCenter + goodRange / 2)
+ {
+ timingFeedback.text = $"Goed \n +{goodScore}";
+ imageFeedback.sprite = goodSprite;
+ goodSigns++;
+ timingFeedback.color = new Color(0xf7 / 255.0f, 0xad / 255.0f, 0x19 / 255.0f);
+ }
+ else if (mehCenter - mehRange / 2 <= x && x <= mehCenter + mehRange / 2)
+ {
+ timingFeedback.text = $"Bijna... \n +{mehScore}";
+ imageFeedback.sprite = mehSprite;
+ mehSigns++;
+ timingFeedback.color = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f);
+ }
+ else
+ {
+ timingFeedback.text = $"Te vroeg! \n {terribleScore}";
+ imageFeedback.sprite = terribleSprite;
+ terribleSigns++;
+ timingFeedback.color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
+ }
+
+ DestroySymbolAt(matchedSymbolIndex);
+ }
}
}
///
- /// The updateFunction that is called when new probabilities become available
+ /// The logic to set the scoreboard of justsign
///
- ///
- protected override IEnumerator UpdateFeedback()
+ /// Shows whether or not the player won, is not relevant for JustSIgn
+ protected override void SetScoreBoard(bool victory)
{
- // Get the predicted sign
- if (signPredictor != null && signPredictor.learnableProbabilities != null && gameIsActive)
+ gameEndedPanel.GetComponent().GenerateContent(
+ perfectSigns: perfectSigns,
+ goodSigns: goodSigns,
+ mehSigns: mehSigns,
+ terribleSigns: terribleSigns,
+ incorrectSigns: incorrectSigns,
+ duration: currentSong.duration,
+ score: CalculateScore()
+ );
+ }
+
+ ///
+ /// The justsign-specific logic that needs to be called at the start of the game
+ ///
+ protected override void StartGameLogic()
+ {
+ // Set the current theme so that it can be passed along
+
+ currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
+
+ userFeedback.SetActive(currentTheme.modelIndex != ModelIndex.NONE);
+ previewMessage.SetActive(currentTheme.modelIndex == ModelIndex.NONE);
+ perfectSigns = 0;
+ goodSigns = 0;
+ mehSigns = 0;
+ terribleSigns = 0;
+ incorrectSigns = 0;
+ timingFeedback.text = "";
+ imageFeedback.sprite = minigame.thumbnail;
+ gameEndedPanel.SetActive(false);
+
+ scoreDisplay.text = $"Score: {CalculateScore()}";
+ words.AddRange(currentTheme.learnables);
+ currentSong = songList.songs[songList.currentSongIndex];
+ AudioSource.PlayClipAtPoint(currentSong.song, Vector3.zero, 1.0f);
+ beginTime = Time.time;
+ lastSymbolTime = beginTime + currentSong.duration - 1920.0f / moveSpeed;
+
+ StartCoroutine(WaitThenStart(currentSong.firstSymbolTime));
+ }
+
+ ///
+ /// The justsign-specific logic that needs to be called at the end of a game
+ ///
+ ///
+ protected override void EndGameLogic(bool victory)
+ {
+ gameIsActive = false;
+ while (activeSymbols.Count > 0)
{
- // Get highest predicted sign
- string predictedSign = signPredictor.learnableProbabilities.Aggregate((a, b) => a.Value > b.Value ? a : b).Key;
- float accuracy = signPredictor.learnableProbabilities[predictedSign];
-
- // vvv TEMPORARY STUFF vvv
- if (predictedSign == "J" && accuracy <= 0.97f)
- {
- predictedSign = signPredictor.learnableProbabilities.Aggregate((x, y) => x.Value > y.Value && x.Key != "J" ? x : y).Key;
- }
- accuracy = signPredictor.learnableProbabilities[predictedSign];
- // ^^^ TEMPORARY STUFF ^^^
-
- Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper().Replace(" ", "-") == predictedSign);
-
- if (feedbackText != null && feedbackProgressImage != null)
- {
- Color col;
- if (accuracy > predSign.thresholdPercentage)
- {
- feedbackText.text = $"Herkent '{predictedSign}'";
- col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
- }
- else if (accuracy > 0.9 * predSign.thresholdPercentage)
- {
- feedbackText.text = $"Lijkt op '{predictedSign}'";
- col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f);
- }
- else
- {
- feedbackText.text = "Detecteren...";
- col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
- }
-
- feedbackText.color = col;
- feedbackProgressImage.color = col;
-
- float oldValue = feedbackProgressBar.value;
- // use an exponential scale
- float newValue = Mathf.Exp(4 * (Mathf.Clamp(accuracy / predSign.thresholdPercentage, 0.0f, 1.0f) - 1.0f));
- feedbackProgressBar.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
- {
- if (feedbackProgressBar != null)
- {
- feedbackProgressBar.value = t.CurrentValue;
- }
- });
- }
-
- if (accuracy > predSign.thresholdPercentage)
- {
- int matchedSymbolIndex = activeWords.IndexOf(predictedSign.ToUpper());
-
- // Destroy the oldest symbol if the current input matches it
- if (0 <= matchedSymbolIndex)
- {
- float x = activeSymbols[matchedSymbolIndex].transform.localPosition.x;
-
- // parameters to define the Perfect hit zone
- float perfectRange = hitZonePerfect.sizeDelta.x;
- float perfectCenter = hitZonePerfect.localPosition.x;
- // parameters to define the Good hit zone
- float goodRange = hitZoneGood.sizeDelta.x;
- float goodCenter = hitZoneGood.localPosition.x;
- // parameters to define the Meh hit zone
- float mehRange = hitZoneMeh.sizeDelta.x;
- float mehCenter = hitZoneMeh.localPosition.x;
-
- if (perfectCenter - perfectRange / 2 <= x && x <= perfectCenter + perfectRange / 2)
- {
- timingFeedback.text = $"Perfect! \n +{perfectScore}";
- imageFeedback.sprite = perfectSprite;
- perfectSigns++;
- timingFeedback.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
- }
- else if (goodCenter - goodRange / 2 <= x && x <= goodCenter + goodRange / 2)
- {
- timingFeedback.text = $"Goed \n +{goodScore}";
- imageFeedback.sprite = goodSprite;
- goodSigns++;
- timingFeedback.color = new Color(0xf7 / 255.0f, 0xad / 255.0f, 0x19 / 255.0f);
- }
- else if (mehCenter - mehRange / 2 <= x && x <= mehCenter + mehRange / 2)
- {
- timingFeedback.text = $"Bijna... \n +{mehScore}";
- imageFeedback.sprite = mehSprite;
- mehSigns++;
- timingFeedback.color = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f);
- }
- else
- {
- timingFeedback.text = $"Te vroeg! \n {terribleScore}";
- imageFeedback.sprite = terribleSprite;
- terribleSigns++;
- timingFeedback.color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
- }
-
- DestroySymbolAt(matchedSymbolIndex);
- }
- }
+ DestroySymbolAt(0);
}
- else if (feedbackProgressBar != null)
- {
-
- feedbackProgressBar.value = 0.0f;
- }
- yield return null;
}
}
diff --git a/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs
new file mode 100644
index 0000000..f54de98
--- /dev/null
+++ b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TMPro;
+using UnityEngine;
+using UnityEngine.UI;
+///
+/// The JustSign-variant of the ScoreBoard
+///
+public class JustSignGameEndedPanel : AbstractGameEndedPanel
+{
+ ///
+ /// Tell the scoreboard that the scoreboard is for JustSign
+ ///
+ protected override MinigameIndex minigameIndex
+ {
+ get { return MinigameIndex.JUST_SIGN; }
+ }
+
+ ///
+ /// The field that will display the amount of perfect signs
+ ///
+ public TMP_Text perfectSignsText;
+
+ ///
+ /// The field that will display the amount of good signs
+ ///
+ public TMP_Text goodSignsText;
+
+ ///
+ /// The field that will display the amount of meh signs
+ ///
+ public TMP_Text mehSignsText;
+
+ ///
+ /// The field that will display the amount of terrible signs
+ ///
+ public TMP_Text terribleSignsText;
+
+ ///
+ /// The field that will display the amount of not found signs
+ ///
+ public TMP_Text notFoundSignsText;
+
+ ///
+ /// The field that will display the signs per minute
+ ///
+ public TMP_Text gpmText;
+
+ ///
+ /// Score
+ ///
+ public TMP_Text scoreText;
+
+ ///
+ /// Generate the content of the gameEnded panel
+ ///
+ /// The amount of perfect signs
+ /// The amount of good signs
+ /// The amount of meh signs
+ /// The emount of terrible signs
+ /// The amount of incorrect signs
+ /// The duration of the song that was played
+ /// The score obtained by the player
+ public void GenerateContent(int perfectSigns, int goodSigns, int mehSigns, int terribleSigns, int incorrectSigns, int duration, int score)
+ {
+ // In de zone
+ perfectSignsText.text = perfectSigns.ToString();
+
+ // Aanvaardbaar
+ goodSignsText.text = goodSigns.ToString();
+
+ // Nipt
+ mehSignsText.text = mehSigns.ToString();
+
+ // Slechte timing
+ terribleSignsText.text = terribleSigns.ToString();
+
+ // Niet Geraden
+ notFoundSignsText.text = incorrectSigns.ToString();
+
+ // LPM
+ int correctSigns = goodSigns + perfectSigns + mehSigns + terribleSigns;
+ gpmText.text = (60f * correctSigns / duration).ToString("#") + " GPM";
+
+ // Score
+ scoreText.text = $"Score: {score}";
+ SetScoreBoard();
+ }
+}
diff --git a/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs.meta b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs.meta
new file mode 100644
index 0000000..8ceccbe
--- /dev/null
+++ b/Assets/JustSign/Scripts/JustSignGameEndedPanel.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9a86c239be1aa1543ba8a4ace5f658b1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JustSign/Scripts/JustSignScripts.asmdef b/Assets/JustSign/Scripts/JustSignScripts.asmdef
index dba74d9..8db4bcf 100644
--- a/Assets/JustSign/Scripts/JustSignScripts.asmdef
+++ b/Assets/JustSign/Scripts/JustSignScripts.asmdef
@@ -7,7 +7,8 @@
"GUID:1631ed2680c61245b8211d943c1639a8",
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
"GUID:58e104b97fb3752438ada2902a36dcbf",
- "GUID:d0b6b39a21908f94fbbd9f2c196a9725"
+ "GUID:d0b6b39a21908f94fbbd9f2c196a9725",
+ "GUID:403dd94a93598934eb522dc36df43d7b"
],
"includePlatforms": [],
"excludePlatforms": [],
diff --git a/Assets/MediaPipeUnity/Scripts/SignPredictor.cs b/Assets/MediaPipeUnity/Scripts/SignPredictor.cs
index 6e4a5a3..ba4d1ab 100644
--- a/Assets/MediaPipeUnity/Scripts/SignPredictor.cs
+++ b/Assets/MediaPipeUnity/Scripts/SignPredictor.cs
@@ -297,6 +297,7 @@ public class SignPredictor : MonoBehaviour
///
private static bool resourceManagerIsInitialized = false;
+ private List signs;
private EmbeddingDataList embeddingDataList;
private ModelIndex modelID;
@@ -521,15 +522,6 @@ public class SignPredictor : MonoBehaviour
{
learnableProbabilities = new Dictionary();
- // Temporary fix
- List signs = new List()
- {
- "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
- };
-
-
-
for (int j = 0; j < result.Count; j++)
{
learnableProbabilities.Add(signs[j].ToUpper(), result[j]);
@@ -715,4 +707,8 @@ public class SignPredictor : MonoBehaviour
}
}
+ public void SetSignsList(List signs)
+ {
+ this.signs = signs;
+ }
}
diff --git a/Assets/Minigames.meta b/Assets/Minigames.meta
new file mode 100644
index 0000000..c8b700b
--- /dev/null
+++ b/Assets/Minigames.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 353d02d53aeb14341835f87efae01039
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Minigames/Scripts.meta b/Assets/Minigames/Scripts.meta
new file mode 100644
index 0000000..9fd5eb6
--- /dev/null
+++ b/Assets/Minigames/Scripts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d5e1253d871fce14ab568e5c9ad4ced2
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/SpellingBee/Scripts/GameEndedPanel.cs b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs
similarity index 60%
rename from Assets/SpellingBee/Scripts/GameEndedPanel.cs
rename to Assets/Minigames/Scripts/AbstractGameEndedPanel.cs
index 096da0c..905533e 100644
--- a/Assets/SpellingBee/Scripts/GameEndedPanel.cs
+++ b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs
@@ -4,50 +4,19 @@ using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
-
-public class GameEndedPanel : MonoBehaviour
+///
+/// Abstract class for all minigame-gameEndedPanels
+///
+public abstract class AbstractGameEndedPanel : MonoBehaviour
{
///
- /// "VERLOREN" or "GEWONNEN"
+ /// The index of minigame that needs a GameEndedPanel
///
- public TMP_Text endText;
-
- ///
- /// LPM
- ///
- public TMP_Text lpmText;
-
- ///
- /// Letters ( right | wrong )
- ///
- public TMP_Text lettersRightText;
- public TMP_Text lettersWrongText;
-
- ///
- /// Letters
- ///
- public TMP_Text lettersTotalText;
-
- ///
- /// Accuracy
- ///
- public TMP_Text accuracyText;
-
- ///
- /// Words
- ///
- public TMP_Text wordsText;
-
- ///
- /// Time
- ///
- public TMP_Text timeText;
-
- ///
- /// Score
- ///
- public TMP_Text scoreText;
-
+ protected abstract MinigameIndex minigameIndex
+ {
+ get;
+ }
+
///
/// Reference to the scoreboard entries container
///
@@ -63,55 +32,10 @@ public class GameEndedPanel : MonoBehaviour
///
public GameObject scoreboardEntry;
- ///
- /// Generate the content of the GameEnded panel
- ///
- /// Time of starting the minigame
- /// Total number of words
- /// Total number of correctly spelled letters
- /// Total number of incorrectly spelled letters
- /// "VERLOREN" or "GEWONNEN"
- /// Final score
- public void GenerateContent(DateTime startTime, int totalWords, int correctLetters, int incorrectLetters, string result, int score)
- {
- // Final result
- endText.text = result;
-
- // LPM
- TimeSpan duration = DateTime.Now.Subtract(startTime);
- lpmText.text = (60f * correctLetters / duration.TotalSeconds).ToString("#") + " LPM";
-
- // Letters ( right | wrong ) total
- lettersRightText.text = correctLetters.ToString();
- lettersWrongText.text = incorrectLetters.ToString();
- lettersTotalText.text = (correctLetters + incorrectLetters).ToString();
-
- // Accuracy
- if (correctLetters + incorrectLetters > 0)
- {
- accuracyText.text = ((correctLetters) * 100f / (correctLetters + incorrectLetters)).ToString("#.##") + "%";
- }
- else
- {
- accuracyText.text = "-";
- }
-
- // Words
- wordsText.text = $"{totalWords}";
-
- // Time
- timeText.text = duration.ToString(@"mm\:ss");
-
- // Score
- scoreText.text = $"Score: {score}";
- SetScoreBoard();
- }
-
-
///
/// Sets the scoreboard
///
- private void SetScoreBoard()
+ protected void SetScoreBoard()
{
// Clean the previous scoreboard entries
for (int i = 0; i < scoreboardEntries.Count; i++)
@@ -126,7 +50,7 @@ public class GameEndedPanel : MonoBehaviour
foreach (User user in UserList.GetUsers())
{
// Get user's progress for this minigame
- var progress = user.GetMinigameProgress(MinigameIndex.SPELLING_BEE);
+ var progress = user.GetMinigameProgress(minigameIndex);
if (progress != null)
{
// Add scores to dictionary
diff --git a/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs.meta b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs.meta
new file mode 100644
index 0000000..def7668
--- /dev/null
+++ b/Assets/Minigames/Scripts/AbstractGameEndedPanel.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 73d452eb6e118ec4091d6cdd82f3550c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Minigames/Scripts/AbstractMinigameController.cs b/Assets/Minigames/Scripts/AbstractMinigameController.cs
new file mode 100644
index 0000000..c888f8d
--- /dev/null
+++ b/Assets/Minigames/Scripts/AbstractMinigameController.cs
@@ -0,0 +1,221 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.UI;
+///
+/// Shared abstract class for the minigameControllers
+///
+public abstract class AbstractMinigameController : AbstractFeedback
+{
+ [Header("AbstractVariables")]
+ ///
+ /// We keep the minigamelist so that the minigame-index doesn't get reset
+ /// DO NOT REMOVE
+ ///
+ public MinigameList minigamelist;
+
+ ///
+ /// A bool to denote whether or not the game is still being played
+ ///
+ protected bool gameIsActive;
+
+ ///
+ /// Reference to the progress bar
+ ///
+ public Slider feedbackProgress;
+
+ ///
+ /// Reference to the current user
+ ///
+ private User user;
+
+ ///
+ /// Reference to the minigame ScriptableObject
+ ///
+ protected Minigame minigame;
+
+ ///
+ /// Each minigame has a webcamTexture, this will be used in children-methods
+ ///
+ public RawImage webcamScreen;
+
+ ///
+ /// Reference to the gameEnded panel, so we can update its display
+ ///
+ public GameObject gameEndedPanel;
+
+ ///
+ /// The theme that will be used by the signpredictor, this needs to be passed from the concrete class.
+ /// This theme CAN be different from the theme that words are fetched from (Think SpellingBee and Hangman)
+ ///
+ protected abstract Theme signPredictorTheme
+ {
+ get;
+ }
+
+ ///
+ /// Start is called before the first frame update, seal it to prevent minigames from changing it
+ ///
+ protected void Start()
+ {
+ // Get the scriptable of the current minigame
+ minigame = minigamelist.minigames[minigamelist.currentMinigameIndex];
+
+ // Start the game-specific start-logic
+ StartController();
+
+ // Prepare the signPredictor
+ signPredictor.SetModel(signPredictorTheme.modelIndex);
+ signPredictor.SwapScreen(webcamScreen);
+ signPredictor.SetSignsList(GetSignsList());
+ AddSelfAsListener();
+ }
+
+ ///
+ /// All minigames use the same principle, they grab the most probable sign and use said sign to show feedback to the user
+ /// Because we don't want minigames to write their own UpdateFeedbacks this function will be sealed
+ ///
+ ///
+ ///
+ protected override sealed IEnumerator UpdateFeedback()
+ {
+ // Get the predicted sign
+ if (signPredictor != null && signPredictor.learnableProbabilities != null && gameIsActive)
+ {
+ // Get highest predicted sign
+ string predictedSign = signPredictor.learnableProbabilities.Aggregate((a, b) => a.Value > b.Value ? a : b).Key;
+ float accuracy = signPredictor.learnableProbabilities[predictedSign];
+
+ // vvv TEMPORARY STUFF vvv
+ if (predictedSign == "J" && accuracy <= 0.97f)
+ {
+ predictedSign = signPredictor.learnableProbabilities.Aggregate((x, y) => x.Value > y.Value && x.Key != "J" ? x : y).Key;
+ }
+ accuracy = signPredictor.learnableProbabilities[predictedSign];
+ // ^^^ TEMPORARY STUFF ^^^
+
+ ProcessMostProbableSign(accuracy, predictedSign);
+ }
+
+ // This part is the only reason that feedbackProgress is needed in the abstract
+ else if (feedbackProgress != null)
+ {
+
+ feedbackProgress.value = 0.0f;
+ }
+
+ yield return null;
+ }
+
+ ///
+ /// Each game keeps a score, this score needs to be saved at some point
+ ///
+ 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
+ var progress = user.GetMinigameProgress(minigame.index);
+
+ // Get the current list of scores
+ List latestScores = progress.latestScores;
+ List highestScores = progress.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.latestScores = latestScores.Take(10).ToList();
+ progress.highestScores = highestScores.Take(10).ToList();
+
+ PersistentDataController.GetInstance().Save();
+ }
+ ///
+ /// The function that activates when the game ends, handles some endgame logic and displays the EndPanel
+ ///
+ ///
+ public void ActivateEnd(bool victory)
+ {
+ EndGameLogic(victory);
+ SaveScores();
+ SetScoreBoard(victory);
+
+ gameEndedPanel.SetActive(true);
+ }
+
+ ///
+ /// Once the most probable sign has been fetched, they can be processed
+ ///
+ /// The accuracy of the passed sign
+ /// The name of the passed sign
+ protected abstract void ProcessMostProbableSign(float accuracy, string predictedSign);
+
+ ///
+ /// Each minigame has their own way of calculating their score
+ ///
+ /// The score that the user has at that point
+ public abstract int CalculateScore();
+
+ ///
+ /// Each minigame has an AbstractGameEndedPanel at the end, but they each have their own unique concrete instance
+ ///
+ /// 1 if the player won, 0 if they lost. Some games need this
+ protected abstract void SetScoreBoard(bool victory);
+
+ ///
+ /// Each minigame puts their GameLogic to be called at (re)start in a seperate function from Start()
+ ///
+ public void StartController()
+ {
+ StartGameLogic();
+
+ // Create entry in current user for keeping track of progress
+ user = UserList.GetCurrentUser();
+ var progress = user.GetMinigameProgress(minigame.index);
+ if (progress == null)
+ {
+ progress = new PersistentDataController.SavedMinigameProgress();
+ progress.minigameIndex = minigame.index;
+ user.AddMinigameProgress(progress);
+ }
+ UserList.Save();
+ }
+
+ ///
+ /// Logic to be called at the start of the game
+ ///
+ protected abstract void StartGameLogic();
+
+ ///
+ /// Function that contains all the logic to end the game
+ ///
+ /// 1 if the player won, 0 if they lost. Some games need this
+ protected abstract void EndGameLogic(bool victory);
+
+ ///
+ /// All non-fingerspelling-minigames have the same logic for the GetSignsList
+ ///
+ /// The signsList that needs to be passed to the signPredictor
+ private List GetSignsList()
+ {
+ List signsList = new List();
+ foreach (Learnable learnable in signPredictorTheme.learnables)
+ {
+ signsList.Add(learnable.name);
+ }
+
+ return signsList;
+ }
+}
diff --git a/Assets/Minigames/Scripts/AbstractMinigameController.cs.meta b/Assets/Minigames/Scripts/AbstractMinigameController.cs.meta
new file mode 100644
index 0000000..a91101a
--- /dev/null
+++ b/Assets/Minigames/Scripts/AbstractMinigameController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a32c0ecc5507e4542a79c1b96a47b0a7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Minigames/Scripts/MinigameScripts.asmdef b/Assets/Minigames/Scripts/MinigameScripts.asmdef
new file mode 100644
index 0000000..96a7380
--- /dev/null
+++ b/Assets/Minigames/Scripts/MinigameScripts.asmdef
@@ -0,0 +1,20 @@
+{
+ "name": "MinigameScripts",
+ "rootNamespace": "",
+ "references": [
+ "GUID:d0b6b39a21908f94fbbd9f2c196a9725",
+ "GUID:e83ddf9a537a96b4a804a16bb7872ec1",
+ "GUID:1631ed2680c61245b8211d943c1639a8",
+ "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
+ "GUID:6055be8ebefd69e48b49212b09b47b2f"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/Minigames/Scripts/MinigameScripts.asmdef.meta b/Assets/Minigames/Scripts/MinigameScripts.asmdef.meta
new file mode 100644
index 0000000..9b1396f
--- /dev/null
+++ b/Assets/Minigames/Scripts/MinigameScripts.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 403dd94a93598934eb522dc36df43d7b
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs b/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs
index 307413d..df4428a 100644
--- a/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs
+++ b/Assets/SpellingBee/PlayModeTests/GameEndedPanelTests.cs
@@ -5,7 +5,7 @@ using UnityEditor;
using UnityEngine;
using UnityEngine.TestTools;
-public class GameEndedPanelTests
+public class SpellingBeeGameEndedPanelTests
{
[UnitySetUp]
public IEnumerator SetupFunction()
@@ -31,15 +31,15 @@ public class GameEndedPanelTests
yield return new WaitForSeconds(1f);
- spellingBeeController.ActivateWin();
+ spellingBeeController.ActivateEnd(true);
- GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
- Assert.NotNull(gameEndedPanel);
- Assert.AreEqual("Score: 0", gameEndedPanel.scoreText.text);
- Assert.AreEqual("1", gameEndedPanel.lettersRightText.text);
- Assert.AreEqual("2", gameEndedPanel.lettersWrongText.text);
- Assert.AreEqual("3", gameEndedPanel.lettersTotalText.text);
- Assert.AreEqual("00:01", gameEndedPanel.timeText.text);
+ SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
+ Assert.NotNull(SpellingBeeGameEndedPanel);
+ Assert.AreEqual("Score: 0", SpellingBeeGameEndedPanel.scoreText.text);
+ Assert.AreEqual("1", SpellingBeeGameEndedPanel.lettersRightText.text);
+ Assert.AreEqual("2", SpellingBeeGameEndedPanel.lettersWrongText.text);
+ Assert.AreEqual("3", SpellingBeeGameEndedPanel.lettersTotalText.text);
+ Assert.AreEqual("00:01", SpellingBeeGameEndedPanel.timeText.text);
}
}
diff --git a/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs b/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs
index b42d5c0..d8db61d 100644
--- a/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs
+++ b/Assets/SpellingBee/PlayModeTests/SpellingBeeControllerTests.cs
@@ -36,12 +36,12 @@ public class SpellingBeeControllerTests
public IEnumerator ActivateGameOverTest()
{
SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController));
- spellingBeeController.ActivateGameOver();
+ spellingBeeController.ActivateEnd(false);
yield return new WaitForSeconds(0.2f);
- GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
- Assert.NotNull(gameEndedPanel);
- Assert.AreEqual("VERLOREN", gameEndedPanel.endText.text);
+ SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
+ Assert.NotNull(SpellingBeeGameEndedPanel);
+ Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text);
}
@@ -49,12 +49,12 @@ public class SpellingBeeControllerTests
public IEnumerator ActivateWinTests()
{
SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController));
- spellingBeeController.ActivateWin();
+ spellingBeeController.ActivateEnd(true);
yield return new WaitForSeconds(0.2f);
- GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
- Assert.NotNull(gameEndedPanel);
- Assert.AreEqual("GEWONNEN", gameEndedPanel.endText.text);
+ SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
+ Assert.NotNull(SpellingBeeGameEndedPanel);
+ Assert.AreEqual("GEWONNEN", SpellingBeeGameEndedPanel.endText.text);
}
[UnityTest]
@@ -64,8 +64,8 @@ public class SpellingBeeControllerTests
spellingBeeController.AddSeconds(-60);
yield return new WaitForSeconds(0.1f);
- GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
- Assert.NotNull(gameEndedPanel);
- Assert.AreEqual("VERLOREN", gameEndedPanel.endText.text);
+ SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
+ Assert.NotNull(SpellingBeeGameEndedPanel);
+ Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text);
}
}
diff --git a/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef b/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef
index 4c3d59e..7c82f99 100644
--- a/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef
+++ b/Assets/SpellingBee/PlayModeTests/SpellingBeePlayModeTests.asmdef
@@ -9,7 +9,8 @@
"SpellingBeeScripts",
"AccountsScripts",
"SystemArchitecture",
- "SignPredictor"
+ "SignPredictor",
+ "MinigameScripts"
],
"includePlatforms": [],
"excludePlatforms": [],
diff --git a/Assets/SpellingBee/Scenes/SpellingBeeGame.unity b/Assets/SpellingBee/Scenes/SpellingBeeGame.unity
index ec22d51..4d0fafa 100644
--- a/Assets/SpellingBee/Scenes/SpellingBeeGame.unity
+++ b/Assets/SpellingBee/Scenes/SpellingBeeGame.unity
@@ -1432,6 +1432,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 5aa929dce1f59b340b4a0cca1bb68edc, type: 3}
m_Name:
m_EditorClassIdentifier:
+ scoreboardEntriesContainer: {fileID: 1499197559}
+ scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
endText: {fileID: 1502459770}
lpmText: {fileID: 1172084829}
lettersRightText: {fileID: 994850063}
@@ -1441,8 +1443,6 @@ MonoBehaviour:
wordsText: {fileID: 1754130538}
timeText: {fileID: 1052827058}
scoreText: {fileID: 653157662}
- scoreboardEntriesContainer: {fileID: 1499197559}
- scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
--- !u!1 &778704239
GameObject:
m_ObjectHideFlags: 0
@@ -3982,21 +3982,20 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
signPredictor: {fileID: 1592592444}
+ minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2}
+ feedbackProgress: {fileID: 967164046}
+ webcamScreen: {fileID: 1743003084}
+ gameEndedPanel: {fileID: 757133117}
themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2}
fingerspelling: {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2}
- minigame: {fileID: 11400000, guid: 8a087d241d652634eb4f6352267ea7dc, type: 2}
- minigamelist: {fileID: 11400000, guid: 51453f9b41bc72f468ba3e67ab622f8f, type: 2}
letterPrefab: {fileID: 4639383499500021565, guid: c3e66e8957864914cb022af914df6a28, type: 3}
letterContainer: {fileID: 1346005056}
wordImage: {fileID: 1338727891}
timerText: {fileID: 1843239267}
bonusTimeText: {fileID: 1812475780}
Scoreboard: {fileID: 862382568}
- gameEndedPanel: {fileID: 757133117}
feedbackText: {fileID: 967164047}
- feedbackProgress: {fileID: 967164046}
feedbackProgressImage: {fileID: 967164045}
- webcamScreen: {fileID: 1743003084}
scoreDisplay: {fileID: 1985911006}
scoreBonus: {fileID: 1130901870}
--- !u!1 &1499197558
diff --git a/Assets/SpellingBee/Scripts/SpellingBeeController.cs b/Assets/SpellingBee/Scripts/SpellingBeeController.cs
index 2485370..37f41b2 100644
--- a/Assets/SpellingBee/Scripts/SpellingBeeController.cs
+++ b/Assets/SpellingBee/Scripts/SpellingBeeController.cs
@@ -7,7 +7,7 @@ using TMPro;
using UnityEngine;
using UnityEngine.UI;
-public partial class SpellingBeeController : AbstractFeedback
+public partial class SpellingBeeController : AbstractMinigameController
{
///
/// All of the words that can be used in this session
@@ -45,11 +45,6 @@ public partial class SpellingBeeController : AbstractFeedback
///
private float timerValue;
- ///
- /// Indicates if the game is still going
- ///
- private bool gameEnded;
-
///
/// List of learnables to get the threshold for the letters
///
@@ -81,22 +76,6 @@ public partial class SpellingBeeController : AbstractFeedback
///
private DateTime startTime;
- ///
- /// 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
///
@@ -137,21 +116,11 @@ public partial class SpellingBeeController : AbstractFeedback
///
public Transform Scoreboard;
- ///
- /// Reference to the gameEnded panel, so we can update its display
- ///
- public GameObject gameEndedPanel;
-
///
/// Reference to the feedback field
///
public TMP_Text feedbackText;
- ///
- /// Reference to the progress bar
- ///
- public Slider feedbackProgress;
-
///
/// Reference to the progress bar image, so we can add fancy colors
///
@@ -172,11 +141,6 @@ public partial class SpellingBeeController : AbstractFeedback
///
protected string previousIncorrectSign = null;
- ///
- /// Reference used to set the webcam for the SignPredictor
- ///
- public RawImage webcamScreen;
-
///
/// Reference to display the score
///
@@ -198,57 +162,11 @@ public partial class SpellingBeeController : AbstractFeedback
private int incorrectLettersScore = -5;
///
- /// Start is called before the first frame update
+ /// Set the AbstractMinigameController variable to inform it of the theme for the signPredictor
///
- public void Start()
+ protected override Theme signPredictorTheme
{
- signPredictor.SetModel(ModelIndex.FINGERSPELLING);
- signPredictor.SwapScreen(webcamScreen);
- AddSelfAsListener();
-
- StartController();
- }
-
- ///
- /// Is called at the start of the scene AND when the game is replayed
- ///
- public void StartController()
- {
- 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
- user = UserList.GetCurrentUser();
- var progress = user.GetMinigameProgress(minigame.index);
- if (progress == null)
- {
- progress = new PersistentDataController.SavedMinigameProgress();
- progress.minigameIndex = MinigameIndex.SPELLING_BEE;
- user.AddMinigameProgress(progress);
- }
- UserList.Save();
-
- currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
- //feedback.signPredictor.SetModel(currentTheme.modelIndex);
- words.AddRange(currentTheme.learnables);
- ShuffleWords();
- NextWord();
-
- scoreDisplay.text = $"Score: {CalculateScore()}";
- scoreBonus.text = "";
+ get { return fingerspelling; }
}
///
@@ -256,7 +174,7 @@ public partial class SpellingBeeController : AbstractFeedback
///
public void Update()
{
- if (!gameEnded)
+ if (gameIsActive)
{
timerValue -= Time.deltaTime;
if (bonusActiveRemaining <= 0.0 && bonusTimeText.activeSelf)
@@ -272,7 +190,8 @@ public partial class SpellingBeeController : AbstractFeedback
if (timerValue <= 0.0f)
{
timerValue = 0.0f;
- ActivateGameOver();
+ //ActivateGameOver();
+ ActivateEnd(false);
}
int minutes = Mathf.FloorToInt(timerValue / 60.0f);
@@ -302,89 +221,11 @@ public partial class SpellingBeeController : AbstractFeedback
/// Calculate the score
///
/// The calculated score
- public int CalculateScore()
+ public override int CalculateScore()
{
return correctLetters * correctLettersScore + incorrectLetters * incorrectLettersScore;
}
- ///
- /// 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
- var progress = user.GetMinigameProgress(minigame.index);
-
- // Get the current list of scores
- List latestScores = progress.latestScores;
- List highestScores = progress.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.latestScores = latestScores.Take(10).ToList();
- progress.highestScores = highestScores.Take(10).ToList();
-
- UserList.Save();
- }
-
///
/// Delete all letter objects
///
@@ -414,7 +255,7 @@ public partial class SpellingBeeController : AbstractFeedback
/// true if the letter was correctly signed, false otherwise
public void NextLetter(bool successful)
{
- if (gameEnded) { return; }
+ if (!gameIsActive) { return; }
// Change color of current letter (skip spaces)
if (successful)
@@ -469,7 +310,8 @@ public partial class SpellingBeeController : AbstractFeedback
}
else
{
- ActivateWin();
+ //ActivateWin();
+ ActivateEnd(true);
}
}
@@ -514,7 +356,7 @@ public partial class SpellingBeeController : AbstractFeedback
Learnable letter = fingerspelling.learnables.Find(l => l.name == sign);
return letter.thresholdPercentage;
}
-
+ /*
///
/// The updateFunction that is called when new probabilities become available
///
@@ -525,7 +367,7 @@ public partial class SpellingBeeController : AbstractFeedback
string currentSign = GetSign();
// Get the predicted sign
if (signPredictor != null && signPredictor.learnableProbabilities != null &&
- currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign))
+ currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign) && gameIsActive)
{
float accCurrentSign = signPredictor.learnableProbabilities[currentSign];
float thresholdCurrentSign = GetTresholdPercentage(currentSign);
@@ -613,6 +455,7 @@ public partial class SpellingBeeController : AbstractFeedback
}
yield return null;
}
+ */
///
/// Function to get the current letter that needs to be signed
///
@@ -638,4 +481,157 @@ public partial class SpellingBeeController : AbstractFeedback
}
NextLetter(successful);
}
+
+ ///
+ /// The logic to process the signs sent by the signPredictor
+ ///
+ /// The accuracy of the passed sign
+ /// The name of the passed sign
+ protected override void ProcessMostProbableSign(float accuracy, string predictedSign)
+ {
+ string currentSign = GetSign();
+ float accPredictSign = accuracy;
+ float accCurrentSign = signPredictor.learnableProbabilities[currentSign];
+ float thresholdCurrentSign = GetTresholdPercentage(currentSign);
+ float thresholdPredictedSign = GetTresholdPercentage(predictedSign);
+
+ // If there is a feedback-object, we wil change its appearance
+ if (feedbackText != null && feedbackProgressImage != null)
+ {
+ Color col;
+ if (accPredictSign > thresholdCurrentSign)
+ {
+ feedbackText.text = "Goed";
+ col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
+ }
+ else if (accCurrentSign > 0.9 * thresholdCurrentSign)
+ {
+ feedbackText.text = "Bijna...";
+ col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f);
+ }
+ else if (accPredictSign > thresholdPredictedSign)
+ {
+ feedbackText.text = $"Verkeerde gebaar: '{predictedSign}'";
+ col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
+ accCurrentSign = 0.0f;
+ }
+ else
+ {
+ feedbackText.text = "Detecteren...";
+ col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
+ }
+
+ feedbackText.color = col;
+ feedbackProgressImage.color = col;
+
+ float oldValue = feedbackProgress.value;
+ // use an exponential scale
+ float newValue = Mathf.Exp(4 * (Mathf.Clamp(accCurrentSign / thresholdCurrentSign, 0.0f, 1.0f) - 1.0f));
+ feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
+ {
+ if (feedbackProgress != null)
+ {
+ feedbackProgress.value = t.CurrentValue;
+ }
+ });
+ }
+
+ // The logic for the internal workings of the game
+ if (accPredictSign > thresholdPredictedSign)
+ {
+ // Correct sign, instantly pass it along
+ if (predictedSign == currentSign)
+ {
+ PredictSign(predictedSign);
+ timer = DateTime.Now;
+ predictedSign = null;
+ previousIncorrectSign = null;
+ }
+
+ // Incorrect sign, wait a bit before passing it along
+ else
+ {
+ if (previousIncorrectSign != predictedSign)
+ {
+ timer = DateTime.Now;
+ previousIncorrectSign = predictedSign;
+ }
+ else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f))
+ {
+ PredictSign(predictedSign);
+ timer = DateTime.Now;
+ predictedSign = null;
+ previousIncorrectSign = null;
+ }
+ }
+
+ }
+ }
+
+ ///
+ /// The logic to set the scoreboard of spellingbee
+ ///
+ /// SHows whether or not the player won
+ protected override void SetScoreBoard(bool victory)
+ {
+ string resultTxt;
+ if (victory)
+ {
+ resultTxt = "GEWONNEN";
+ }
+ else
+ {
+ resultTxt = "VERLOREN";
+ }
+ // Save the scores and show the scoreboard
+ gameEndedPanel.GetComponent().GenerateContent(
+ startTime: startTime,
+ totalWords: spelledWords,
+ correctLetters: correctLetters,
+ incorrectLetters: incorrectLetters,
+ result: resultTxt,
+ score: CalculateScore()
+ );
+ }
+
+ ///
+ /// The spellinbee-specific logic that needs to be called at the start of the game
+ ///
+ protected override void StartGameLogic()
+ {
+ correctLetters = 0;
+ incorrectLetters = 0;
+
+ words.Clear();
+ // We use -1 instead of 0 so SetNextWord can simply increment it each time
+ spelledWords = -1;
+ wordIndex = 0;
+
+ gameIsActive = true;
+ timerValue = 30.0f;
+ bonusActiveRemaining = 0.0f;
+ startTime = DateTime.Now;
+
+ gameEndedPanel.SetActive(false);
+ bonusTimeText.SetActive(false);
+
+ currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
+ //feedback.signPredictor.SetModel(currentTheme.modelIndex);
+ words.AddRange(currentTheme.learnables);
+ ShuffleWords();
+ NextWord();
+
+ scoreDisplay.text = $"Score: {CalculateScore()}";
+ scoreBonus.text = "";
+ }
+
+ ///
+ /// The spellingbee-specific logic that needs to be called at the end of a game
+ ///
+ ///
+ protected override void EndGameLogic(bool victory)
+ {
+ gameIsActive = false;
+ DeleteWord();
+ }
}
diff --git a/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs b/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs
new file mode 100644
index 0000000..de6c3d5
--- /dev/null
+++ b/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TMPro;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class SpellingBeeGameEndedPanel : AbstractGameEndedPanel
+{
+ ///
+ /// Tell the scoreboard that the scoreboard is for SpellingBee
+ ///
+ protected override MinigameIndex minigameIndex
+ {
+ get { return MinigameIndex.SPELLING_BEE; }
+ }
+
+ ///
+ /// "VERLOREN" or "GEWONNEN"
+ ///
+ public TMP_Text endText;
+
+ ///
+ /// LPM
+ ///
+ public TMP_Text lpmText;
+
+ ///
+ /// Letters ( right | wrong )
+ ///
+ public TMP_Text lettersRightText;
+ public TMP_Text lettersWrongText;
+
+ ///
+ /// Letters
+ ///
+ public TMP_Text lettersTotalText;
+
+ ///
+ /// Accuracy
+ ///
+ public TMP_Text accuracyText;
+
+ ///
+ /// Words
+ ///
+ public TMP_Text wordsText;
+
+ ///
+ /// Time
+ ///
+ public TMP_Text timeText;
+
+ ///
+ /// Score
+ ///
+ public TMP_Text scoreText;
+
+ ///
+ /// Generate the content of the GameEnded panel
+ ///
+ /// Time of starting the minigame
+ /// Total number of words
+ /// Total number of correctly spelled letters
+ /// Total number of incorrectly spelled letters
+ /// "VERLOREN" or "GEWONNEN"
+ /// Final score
+ public void GenerateContent(DateTime startTime, int totalWords, int correctLetters, int incorrectLetters, string result, int score)
+ {
+ // Final result
+ endText.text = result;
+
+ // LPM
+ TimeSpan duration = DateTime.Now.Subtract(startTime);
+ lpmText.text = (60f * correctLetters / duration.TotalSeconds).ToString("#") + " LPM";
+
+ // Letters ( right | wrong ) total
+ lettersRightText.text = correctLetters.ToString();
+ lettersWrongText.text = incorrectLetters.ToString();
+ lettersTotalText.text = (correctLetters + incorrectLetters).ToString();
+
+ // Accuracy
+ if (correctLetters + incorrectLetters > 0)
+ {
+ accuracyText.text = ((correctLetters) * 100f / (correctLetters + incorrectLetters)).ToString("#.##") + "%";
+ }
+ else
+ {
+ accuracyText.text = "-";
+ }
+
+ // Words
+ wordsText.text = $"{totalWords}";
+
+ // Time
+ timeText.text = duration.ToString(@"mm\:ss");
+
+ // Score
+ scoreText.text = $"Score: {score}";
+ SetScoreBoard();
+ }
+}
diff --git a/Assets/SpellingBee/Scripts/GameEndedPanel.cs.meta b/Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs.meta
similarity index 100%
rename from Assets/SpellingBee/Scripts/GameEndedPanel.cs.meta
rename to Assets/SpellingBee/Scripts/SpellingBeeGameEndedPanel.cs.meta
diff --git a/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef b/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef
index 7c87746..bbf25b5 100644
--- a/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef
+++ b/Assets/SpellingBee/Scripts/SpellingBeeScripts.asmdef
@@ -8,7 +8,8 @@
"GUID:d0b6b39a21908f94fbbd9f2c196a9725",
"GUID:58e104b97fb3752438ada2902a36dcbf",
"GUID:e83ddf9a537a96b4a804a16bb7872ec1",
- "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
+ "GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
+ "GUID:403dd94a93598934eb522dc36df43d7b"
],
"includePlatforms": [],
"excludePlatforms": [],
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index 9466c19..8502e64 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -168,7 +168,8 @@ PlayerSettings:
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- - {fileID: 11400000, guid: 57fdfdc7df920454ba35444c783867d8, type: 2}
+ - {fileID: 0}
+ - {fileID: 0}
metroInputSource: 0
wsaTransparentSwapchain: 0
m_HolographicPauseOnTrackingLoss: 1