Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d70725750a | |||
|
|
76b4bdd596 | ||
|
|
3246e1022c | ||
|
|
52ebd0e67a | ||
|
|
7cac7aa9ca | ||
|
|
92c3101db8 | ||
|
|
5ee7add6b9 | ||
| ec60f7d8e3 | |||
|
|
9422df7083 | ||
|
|
db1a72fadd | ||
| db96a700e8 | |||
|
|
ab6c817667 | ||
|
|
e8de984ba1 | ||
|
|
2ba62e316f | ||
| 5b4a3ec4e7 | |||
|
|
77850bfbe6 | ||
|
|
f9fff14662 | ||
| aed09649e3 | |||
|
|
c8dfa96c8f | ||
|
|
4e9d801e61 | ||
|
|
04d9a4bf2b | ||
|
|
2b71bde592 | ||
|
|
73c4756f19 | ||
|
|
f5615bbef3 | ||
|
|
8670fcc4ce | ||
|
|
e6d10db5ca | ||
|
|
8db7c80dad | ||
|
|
197a6200c1 | ||
|
|
68372d859b | ||
|
|
2a7dd16f5f | ||
|
|
e6b0cbd596 | ||
|
|
c358ac59e4 | ||
|
|
c20cd89c3a | ||
|
|
5f4408063f | ||
| 3499e61bb0 | |||
|
|
aefc75f3c4 | ||
|
|
f95e34c6fe | ||
|
|
edf1805a92 | ||
|
|
a808e73a29 | ||
|
|
b955d2164c | ||
|
|
e96f1ff7ca | ||
|
|
b8cdcd128b | ||
|
|
ea13788199 | ||
|
|
564ec209c7 | ||
| a3735af649 | |||
|
|
692b4318bf | ||
|
|
0015c1453c | ||
|
|
c78ef0e773 | ||
|
|
45f545b13f | ||
|
|
d3af75f676 | ||
|
|
5f7216f24c | ||
|
|
b012e40df8 | ||
|
|
f69e2385fc | ||
|
|
37905a904c | ||
|
|
0019a4d07f | ||
|
|
4402e80d0c | ||
|
|
d95a6590d5 | ||
|
|
7b6eb4db69 | ||
|
|
8696aff135 | ||
|
|
001cf6dedb | ||
|
|
669bcb3793 | ||
|
|
668b769094 | ||
|
|
fee989006c | ||
|
|
b3913c281a | ||
|
|
b0c0cdc095 | ||
|
|
db37a16155 | ||
|
|
9c7366e49c | ||
|
|
5a5a1f1542 | ||
|
|
0e997666e2 | ||
|
|
6ef35cabd4 | ||
|
|
2581cd6137 | ||
|
|
800f0ae77f | ||
|
|
bb11f4d743 | ||
|
|
f835adaa23 | ||
| f9298a055a | |||
|
|
2e3dd2e26d | ||
|
|
f2743408a3 | ||
|
|
e23de9a2d3 | ||
|
|
b5328d0b9d | ||
|
|
44d3398e03 | ||
|
|
c9ee031df3 | ||
|
|
3abc24a39c | ||
|
|
f827c29d3a | ||
|
|
0a4cb9e8c6 | ||
|
|
ac000132a9 | ||
|
|
a19d89db03 | ||
|
|
8ff5c6c4c8 | ||
|
|
746906294b | ||
|
|
1a75791d62 | ||
|
|
9dfadece44 | ||
|
|
5e26970bad | ||
|
|
f6e6afe340 | ||
|
|
96fb3c89c3 | ||
|
|
dfc69ddd76 | ||
|
|
59d69f7412 | ||
|
|
a267301ab6 | ||
|
|
94ec7e0359 | ||
|
|
0c795b09bc | ||
|
|
8501edb03a | ||
|
|
cef72508cc | ||
|
|
17abca46ea |
@@ -1,42 +0,0 @@
|
||||
## Description
|
||||
|
||||
_Please provide a brief summary of the changes in this merge request._
|
||||
|
||||
_If possible, add a short screengrab or some screenshots of the changes._
|
||||
|
||||
## Testing Instructions
|
||||
|
||||
_Please provide instructions on how the code reviewers can test your changes:_
|
||||
|
||||
1. [Step 1]
|
||||
2. [Step 2]
|
||||
3. [Step 3]
|
||||
4. ...
|
||||
|
||||
_Please include any specific information on test data, configurations, or other requirements that are necessary to properly test the changes._
|
||||
|
||||
Once you've tested the changes, please confirm that they work as expected and that there are no regressions or unexpected side effects. If any issues are discovered during testing, please include detailed steps to reproduce the issue in the merge request comments. Thank you!
|
||||
|
||||
## Related Issues
|
||||
|
||||
_Please list any related issues or pull requests that are relevant to this merge request._
|
||||
_E.g. WES-XXX-..._
|
||||
|
||||
## Known bugs or issues
|
||||
|
||||
_Please list any known bugs or issues related to the changes in this merge request._
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have filled in this template.
|
||||
- [ ] I have tested my changes thoroughly (both in the editor + **build and run (ctrl+B)**!).
|
||||
- [ ] I have added appropriate unit tests.
|
||||
- [ ] I have added appropriate playmode tests.
|
||||
- [ ] I have updated the user documentation as necessary.
|
||||
- [ ] Code reviewed by 2 people.
|
||||
|
||||
## Additional Notes
|
||||
|
||||
_Please add any additional notes or comments that may be helpful for reviewers to understand your changes._
|
||||
|
||||
/assign_reviewer @wesign/unityappreviewers
|
||||
@@ -6,7 +6,7 @@
|
||||
"UnityEditor.TestRunner",
|
||||
"AccountsScripts",
|
||||
"InterfacesScripts",
|
||||
"ArchitectureScripts"
|
||||
"SystemArchitecture"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 4.3 KiB |
@@ -10,7 +10,7 @@
|
||||
"Unity.TextMeshPro",
|
||||
"AccountsScripts",
|
||||
"SignPredictor",
|
||||
"ArchitectureScripts"
|
||||
"SystemArchitecture"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -513,10 +513,10 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 1
|
||||
m_UiScaleMode: 0
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 1920, y: 1080}
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
|
||||
@@ -39,7 +39,6 @@ public class CourseActivityScreen : MonoBehaviour
|
||||
/// </summary>
|
||||
public Image courseImage;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Progress bar Display
|
||||
/// </summary>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"CommonScripts",
|
||||
"InterfacesScripts",
|
||||
"SignPredictor",
|
||||
"NatML.ML",
|
||||
"ArchitectureScripts"
|
||||
"SystemArchitecture",
|
||||
"NatML.ML"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"ArchitectureScripts"
|
||||
"SystemArchitecture"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"InterfacesScripts",
|
||||
"SignPredictor",
|
||||
"NatML.ML",
|
||||
"Tween",
|
||||
"ArchitectureScripts"
|
||||
"SystemArchitecture",
|
||||
"Tween"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using DigitalRuby.Tween;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -171,26 +170,10 @@ public class CoursesController : AbstractFeedback
|
||||
void Start()
|
||||
{
|
||||
StartCourseController();
|
||||
signPredictor.SetSignsList(GetSignsList());
|
||||
signPredictor.SetModel(course.theme.modelIndex);
|
||||
AddSelfAsListener();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches all the strings of the signs of the course
|
||||
/// </summary>
|
||||
/// <returns>The signsList that needs to be passed to the signPredictor</returns>
|
||||
private List<string> GetSignsList()
|
||||
{
|
||||
List<string> signsList = new List<string>();
|
||||
foreach (Learnable learnable in course.theme.learnables)
|
||||
{
|
||||
signsList.Add(learnable.name);
|
||||
}
|
||||
|
||||
return signsList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the course-specific logic to start the controller, it is seperated to allow the course to be reset (if that would become needed)
|
||||
/// </summary>
|
||||
@@ -427,7 +410,6 @@ 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;
|
||||
@@ -457,7 +439,6 @@ 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));
|
||||
@@ -470,7 +451,6 @@ public class CoursesController : AbstractFeedback
|
||||
});
|
||||
}
|
||||
|
||||
// The internal logic for the courses
|
||||
if (accPredictSign > sign.thresholdPercentage)
|
||||
{
|
||||
// Correct sign
|
||||
|
||||
@@ -38,7 +38,7 @@ RenderSettings:
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.37311918, g: 0.3807398, b: 0.35872716, a: 1}
|
||||
m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
@@ -2241,9 +2241,7 @@ MonoBehaviour:
|
||||
m_text: 'Speler 1 geeft een woord in aan de hand van vingerspelling.
|
||||
|
||||
Het woord
|
||||
moet tussen 3 en 17 letters zijn.
|
||||
|
||||
Je kan letters verwijderen met backspace.'
|
||||
moet tussen 3 en 17 letters zijn.'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
|
||||
m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
|
||||
@@ -3278,7 +3276,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: AZERTY
|
||||
m_text:
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
|
||||
m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
|
||||
@@ -4542,8 +4540,6 @@ 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}
|
||||
@@ -4551,7 +4547,19 @@ 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
|
||||
@@ -7667,10 +7675,6 @@ 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}
|
||||
@@ -7692,10 +7696,15 @@ 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}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
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 : AbstractMinigameController
|
||||
public class HangmanController : AbstractFeedback
|
||||
{
|
||||
[Header("ConcreteVariables")]
|
||||
/// <summary>
|
||||
/// The scriptable with all the themes, will be used to select a random word for hangman.
|
||||
/// The spellingthemeList will be used for the words.
|
||||
@@ -16,7 +17,7 @@ public class HangmanController : AbstractMinigameController
|
||||
public ThemeList themeList;
|
||||
|
||||
/// <summary>
|
||||
/// reference to the fingerspelling-theme to reach the letter-thresholds and to pass to the signPredictor
|
||||
/// reference to the fingerspelling-theme to reach the letter-thresholds
|
||||
/// </summary>
|
||||
public Theme fingerSpelling;
|
||||
|
||||
@@ -95,6 +96,11 @@ public class HangmanController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public TMP_Text scoreBonus;
|
||||
|
||||
///// <summary>
|
||||
///// This panel holds the panels for input and playing the game, sharing webcam and feedback
|
||||
///// </summary>
|
||||
//public GameObject inputGamePanel;
|
||||
|
||||
/// <summary>
|
||||
/// This int shows what mode we are in, used in update: <br></br>
|
||||
/// 0 : single or multiplayer?<br></br>
|
||||
@@ -105,6 +111,27 @@ public class HangmanController : AbstractMinigameController
|
||||
/// </summary>
|
||||
private int mode;
|
||||
|
||||
/// <summary>
|
||||
/// The game over panel
|
||||
/// </summary>
|
||||
public GameObject gameEndedPanel;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the minigame ScriptableObject
|
||||
/// </summary>
|
||||
public Minigame minigame;
|
||||
|
||||
/// <summary>
|
||||
/// We keep the minigamelist as well so that the minigame-index doesn't get reset
|
||||
/// DO NOT REMOVE
|
||||
/// </summary>
|
||||
public MinigameList minigamelist;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the current user
|
||||
/// </summary>
|
||||
private User user;
|
||||
|
||||
/// <summary>
|
||||
/// The button to go into the game
|
||||
/// </summary>
|
||||
@@ -125,11 +152,21 @@ public class HangmanController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public TMP_Text feedbackText;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar
|
||||
/// </summary>
|
||||
public Slider feedbackProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar image, so we can add fancy colors
|
||||
/// </summary>
|
||||
public Image feedbackProgressImage;
|
||||
|
||||
/// <summary>
|
||||
/// reference to the webcam background
|
||||
/// </summary>
|
||||
public RawImage webcamScreen;
|
||||
|
||||
/// <summary>
|
||||
/// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs
|
||||
/// </summary>
|
||||
@@ -202,11 +239,48 @@ public class HangmanController : AbstractMinigameController
|
||||
private int winScore = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Set the AbstractMinigameController variable to inform it of the theme for the signPredictor
|
||||
/// Start is called before the first frame update
|
||||
/// </summary>
|
||||
protected override Theme signPredictorTheme
|
||||
void Start()
|
||||
{
|
||||
get { return fingerSpelling; }
|
||||
signPredictor.SwapScreen(webcamScreen);
|
||||
signPredictor.SetModel(ModelIndex.FINGERSPELLING);
|
||||
AddSelfAsListener();
|
||||
|
||||
StartController();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called at the start of the scene AND when the scene is replayed
|
||||
/// </summary>
|
||||
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<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,7 +289,7 @@ public class HangmanController : AbstractMinigameController
|
||||
public void StartGame()
|
||||
{
|
||||
// Change the mode
|
||||
SwitchMode(2);
|
||||
mode = 2;
|
||||
|
||||
// Activate the right panel
|
||||
gamePanel.SetActive(true);
|
||||
@@ -260,7 +334,11 @@ public class HangmanController : AbstractMinigameController
|
||||
public void GoToInput()
|
||||
{
|
||||
// Change the mode
|
||||
SwitchMode(1);
|
||||
mode = 1;
|
||||
|
||||
// Initialise the word to an empty String
|
||||
currentWord = "";
|
||||
inputTextField.text = currentWord.ToUpper();
|
||||
|
||||
// Activate the right panel
|
||||
gamePanel.SetActive(false);
|
||||
@@ -268,11 +346,7 @@ public class HangmanController : AbstractMinigameController
|
||||
inputPanel.SetActive(true);
|
||||
playerPanel.SetActive(false);
|
||||
|
||||
// Initialise the word to an empty String
|
||||
currentWord = "";
|
||||
|
||||
PanelMultiplayerInput script = inputPanel.GetComponent<PanelMultiplayerInput>();
|
||||
script.inputTextField.text = "";
|
||||
|
||||
gotoGameButton = script.gotoGameButton;
|
||||
inputTextField = script.inputTextField;
|
||||
@@ -306,6 +380,11 @@ public class HangmanController : AbstractMinigameController
|
||||
/// </summary>
|
||||
private void PickRandomWord()
|
||||
{
|
||||
// vvv DEMO DAY STUFF vvv
|
||||
currentWord = "DEMO DAG";
|
||||
return;
|
||||
// ^^^ DEMO DAY STUFF ^^^
|
||||
|
||||
// Get a random index for the themes
|
||||
// Then get a random index for a word to pull
|
||||
|
||||
@@ -396,7 +475,7 @@ public class HangmanController : AbstractMinigameController
|
||||
{
|
||||
confirmPanel.SetActive(true);
|
||||
confirmText.text = $"Letter '{currentSign.ToUpper()}' ?";
|
||||
SwitchMode(4);
|
||||
mode = 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -404,7 +483,7 @@ public class HangmanController : AbstractMinigameController
|
||||
case 2: // Sign your letter
|
||||
if (!guesses.Contains(currentSign))
|
||||
{
|
||||
SwitchMode(3);
|
||||
mode = 3;
|
||||
ConfirmAccept();
|
||||
}
|
||||
break;
|
||||
@@ -443,23 +522,24 @@ public class HangmanController : AbstractMinigameController
|
||||
usedLettersText.text += letter.ToString().ToUpper();
|
||||
|
||||
// The current sign was accepted, return to the game
|
||||
SwitchMode(2);
|
||||
if (corrects == currentWord.Length)
|
||||
mode = 2;
|
||||
|
||||
if (corrects == currentWord.Replace(" ", "").Length)
|
||||
{
|
||||
// Victory, deactivate the model and show the scoreboard
|
||||
ActivateEnd(true);
|
||||
ActivateWin();
|
||||
}
|
||||
else if (NUMBER_OF_FAILS_BEFORE_GAMEOVER < wrongs)
|
||||
{
|
||||
// You lost, deactivate the model and show the scoreboard
|
||||
ActivateEnd(false);
|
||||
ActivateGameOver();
|
||||
}
|
||||
}
|
||||
else if (mode == 4)
|
||||
{
|
||||
currentWord += letter;
|
||||
inputTextField.text = currentWord.ToUpper();
|
||||
SwitchMode(1);
|
||||
mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,23 +549,9 @@ public class HangmanController : AbstractMinigameController
|
||||
|
||||
// The current sign was rejected, return to the game-mode
|
||||
if (mode == 3)
|
||||
SwitchMode(2);
|
||||
mode = 2;
|
||||
else if (mode == 4)
|
||||
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;
|
||||
}
|
||||
mode = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -538,7 +604,7 @@ public class HangmanController : AbstractMinigameController
|
||||
/// This function returns the score that the user currently has
|
||||
/// </summary>
|
||||
/// <returns>The current score of the user</returns>
|
||||
public override int CalculateScore()
|
||||
private int CalculateScore()
|
||||
{
|
||||
int won = corrects == currentWord.Length ? 1 : 0;
|
||||
return corrects * correctLetterScore + wrongs * incorrectLetterScore + winScore * won;
|
||||
@@ -579,19 +645,115 @@ public class HangmanController : AbstractMinigameController
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logic to process the signs sent by the signPredictor
|
||||
/// Update and save the scores
|
||||
/// </summary>
|
||||
/// <param name="accuracy">The accuracy of the passed sign</param>
|
||||
/// <param name="predictedSign">The name of the passed sign</param>
|
||||
protected override void ProcessMostProbableSign(float accuracy, string predictedSign)
|
||||
private void SaveScores()
|
||||
{
|
||||
// Grab the threshold for the most probable letter
|
||||
Learnable letter = fingerSpelling.learnables.Find((l) => l.name == predictedSign);
|
||||
float threshold = letter.thresholdPercentage;
|
||||
// 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();
|
||||
|
||||
// If there is a feedback-object, we wil change its appearance
|
||||
if (feedbackText != null && feedbackProgressImage != null)
|
||||
// Save the new score
|
||||
var progress = user.GetMinigameProgress(minigame.index);
|
||||
|
||||
// Get the current list of scores
|
||||
List<Score> latestScores = progress.latestScores;
|
||||
List<Score> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display win screen
|
||||
/// </summary>
|
||||
private void ActivateWin()
|
||||
{
|
||||
// Deactivate the model
|
||||
mode = 0;
|
||||
|
||||
// Save the scores and show the scoreboard
|
||||
SaveScores();
|
||||
gameEndedPanel.GetComponent<HangmanGameEndedPanel>().GenerateContent(
|
||||
guessWord: currentWord.ToLower(),
|
||||
correctLetters: corrects,
|
||||
incorrectLetters: wrongs,
|
||||
sprite: hangmanImage.sprite,
|
||||
result: "GEWONNEN",
|
||||
score: CalculateScore()
|
||||
);
|
||||
|
||||
gameEndedPanel.SetActive(true);
|
||||
|
||||
// @lukas stuff
|
||||
DeleteWord();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays the game over panel and score values
|
||||
/// </summary>
|
||||
private void ActivateGameOver()
|
||||
{
|
||||
// Deactivate the model
|
||||
mode = 0;
|
||||
|
||||
// Save the scores and show the scoreboard
|
||||
SaveScores();
|
||||
gameEndedPanel.GetComponent<HangmanGameEndedPanel>().GenerateContent(
|
||||
guessWord: currentWord.ToLower(),
|
||||
correctLetters: corrects,
|
||||
incorrectLetters: wrongs,
|
||||
sprite: hangmanImage.sprite,
|
||||
result: "VERLOREN",
|
||||
score: CalculateScore()
|
||||
);
|
||||
|
||||
gameEndedPanel.SetActive(true);
|
||||
|
||||
DeleteWord();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The updateFunction that is called when new probabilities become available
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override IEnumerator UpdateFeedback()
|
||||
{
|
||||
// Get the sign with the highest prediction
|
||||
if ((mode == 1 || mode == 2) &&
|
||||
signPredictor != null &&
|
||||
signPredictor.learnableProbabilities != null)
|
||||
{
|
||||
KeyValuePair<string, float> 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));
|
||||
@@ -624,33 +786,37 @@ public class HangmanController : AbstractMinigameController
|
||||
feedbackText.color = red;
|
||||
feedbackProgressImage.color = red;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (accuracy > threshold)
|
||||
{
|
||||
// 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())))
|
||||
if (previousSign != predictedSign)
|
||||
{
|
||||
runTime = true;
|
||||
// Reset the timer
|
||||
previousSign = predictedSign;
|
||||
currentTime = 0;
|
||||
if ((mode == 1) ||
|
||||
(mode == 2 && !guesses.Contains(previousSign.ToUpper())))
|
||||
{
|
||||
runTime = true;
|
||||
}
|
||||
timerCircle.fillAmount = currentTime;
|
||||
}
|
||||
timerCircle.fillAmount = currentTime;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
// The same sign was predicted as last time and said sign has been held for a sufficiently long time
|
||||
else if (currentTime == maxTime)
|
||||
else
|
||||
{
|
||||
// Set the predictedSign as your guess and update the Hangman
|
||||
currentSign = predictedSign;
|
||||
UpdateSign();
|
||||
// reset the timer and look for a new prediction
|
||||
// The sign was dropped, reset the timer
|
||||
previousSign = null;
|
||||
currentTime = 0;
|
||||
runTime = false;
|
||||
@@ -658,69 +824,11 @@ public class HangmanController : AbstractMinigameController
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
else if (feedbackProgress != null)
|
||||
{
|
||||
// The sign was dropped, reset the timer
|
||||
previousSign = null;
|
||||
currentTime = 0;
|
||||
runTime = false;
|
||||
timerCircle.fillAmount = currentTime;
|
||||
|
||||
feedbackProgress.value = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logic to set the scoreboard of hangman
|
||||
/// </summary>
|
||||
/// <param name="victory">SHows whether or not the player won</param>
|
||||
protected override void SetScoreBoard(bool victory)
|
||||
{
|
||||
string resultTxt;
|
||||
if (victory)
|
||||
{
|
||||
resultTxt = "GEWONNEN";
|
||||
}
|
||||
else
|
||||
{
|
||||
resultTxt = "VERLOREN";
|
||||
}
|
||||
gameEndedPanel.GetComponent<HangmanGameEndedPanel>().GenerateContent(
|
||||
guessWord: currentWord.ToLower(),
|
||||
correctLetters: corrects,
|
||||
incorrectLetters: wrongs,
|
||||
sprite: hangmanImage.sprite,
|
||||
result: resultTxt,
|
||||
score: CalculateScore()
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The hangman-specific logic that needs to be called at the start of the game
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Hangman-specific logic that needs to be called at the end of a game
|
||||
/// </summary>
|
||||
/// <param name="victory"></param>
|
||||
protected override void EndGameLogic(bool victory)
|
||||
{
|
||||
// Deactivate the model
|
||||
SwitchMode(0);
|
||||
|
||||
DeleteWord();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,8 @@ using UnityEngine.UI;
|
||||
/// <summary>
|
||||
/// The hangman-variant of the ScoreBoard
|
||||
/// </summary>
|
||||
public class HangmanGameEndedPanel : AbstractGameEndedPanel
|
||||
public class HangmanGameEndedPanel : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Tell the scoreboard that the scoreboard is for HangMan
|
||||
/// </summary>
|
||||
protected override MinigameIndex minigameIndex
|
||||
{
|
||||
get { return MinigameIndex.HANGMAN; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "VERLOREN" or "GEWONNEN"
|
||||
/// </summary>
|
||||
@@ -48,11 +40,28 @@ public class HangmanGameEndedPanel : AbstractGameEndedPanel
|
||||
/// </summary>
|
||||
public TMP_Text scoreText;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the scoreboard entries container
|
||||
/// </summary>
|
||||
public Transform scoreboardEntriesContainer;
|
||||
|
||||
/// <summary>
|
||||
/// The GameObjects representing the letters
|
||||
/// </summary>
|
||||
private List<GameObject> scoreboardEntries = new List<GameObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the ScoreboardEntry prefab
|
||||
/// </summary>
|
||||
public GameObject scoreboardEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the end result image
|
||||
/// </summary>
|
||||
public Image image;
|
||||
|
||||
public List<Sprite> sprites;
|
||||
|
||||
/// <summary>
|
||||
/// Generate the content of the GameEnded panel
|
||||
/// </summary>
|
||||
@@ -90,4 +99,105 @@ public class HangmanGameEndedPanel : AbstractGameEndedPanel
|
||||
scoreText.text = $"Score: {score}";
|
||||
SetScoreBoard();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the scoreboard
|
||||
/// </summary>
|
||||
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<Tuple<string, Score>> allScores = new List<Tuple<string, Score>>();
|
||||
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<Score> scores = progress.highestScores;
|
||||
foreach (Score score in scores)
|
||||
{
|
||||
allScores.Add(new Tuple<string, Score>(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<string, Score> 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<Image>().sprite = UserList.GetUserByUsername(username).GetAvatar();
|
||||
|
||||
// Set the player name
|
||||
entry.transform.Find("PlayerName").GetComponent<TMP_Text>().text = username;
|
||||
|
||||
// Set the score
|
||||
entry.transform.Find("Score").GetComponent<TMP_Text>().text = score.scoreValue.ToString();
|
||||
|
||||
// Set the rank
|
||||
entry.transform.Find("Rank").GetComponent<TMP_Text>().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<TMP_Text>().text = formatted;
|
||||
|
||||
|
||||
// Alternating colors looks nice
|
||||
if (rank % 2 == 0)
|
||||
{
|
||||
Image image = entry.transform.GetComponent<Image>();
|
||||
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>();
|
||||
image.color = new Color(0, 229, 255, 233);
|
||||
}
|
||||
|
||||
rank++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
"GUID:e83ddf9a537a96b4a804a16bb7872ec1",
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:1631ed2680c61245b8211d943c1639a8",
|
||||
"GUID:d0b6b39a21908f94fbbd9f2c196a9725",
|
||||
"GUID:58e104b97fb3752438ada2902a36dcbf",
|
||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
|
||||
"GUID:403dd94a93598934eb522dc36df43d7b",
|
||||
"GUID:d0b6b39a21908f94fbbd9f2c196a9725"
|
||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -1557,19 +1557,20 @@ 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}
|
||||
@@ -1577,7 +1578,9 @@ 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}
|
||||
@@ -1854,7 +1857,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: 496523654}
|
||||
screen: {fileID: 0}
|
||||
--- !u!4 &1150323776
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -3521,7 +3524,7 @@ GameObject:
|
||||
- component: {fileID: 2498222377094258230}
|
||||
- component: {fileID: 2498222377094258231}
|
||||
m_Layer: 5
|
||||
m_Name: GPM
|
||||
m_Name: LPM
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@@ -3575,7 +3578,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: XXX GPM
|
||||
m_text: XXX LPM
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
|
||||
m_sharedMaterial: {fileID: -2577534979213189211, guid: 1baf2eae62f542f4585aaf3c9c3e229a, type: 2}
|
||||
@@ -4697,6 +4700,29 @@ 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
|
||||
@@ -4762,7 +4788,7 @@ GameObject:
|
||||
- component: {fileID: 2498222378566216020}
|
||||
- component: {fileID: 2498222378566215978}
|
||||
- component: {fileID: 2498222378566216021}
|
||||
- component: {fileID: 2498222378566216024}
|
||||
- component: {fileID: 2498222378566215979}
|
||||
m_Layer: 5
|
||||
m_Name: GameEnded Panel
|
||||
m_TagString: Untagged
|
||||
@@ -4770,27 +4796,6 @@ 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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using DigitalRuby.Tween;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -9,7 +11,7 @@ using Random = UnityEngine.Random;
|
||||
/// <summary>
|
||||
/// Contains all game logic for the JustSign game
|
||||
/// </summary>
|
||||
public class JustSignController : AbstractMinigameController
|
||||
public class JustSignController : AbstractFeedback
|
||||
{
|
||||
/// <summary>
|
||||
/// All of the words that can be used in this session
|
||||
@@ -31,6 +33,17 @@ public class JustSignController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public TMP_Text scoreDisplay;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the minigame ScriptableObject
|
||||
/// </summary>
|
||||
public Minigame minigame;
|
||||
|
||||
/// <summary>
|
||||
/// We keep the minigamelist as well so that the minigame-index doesn't get reset
|
||||
/// DO NOT REMOVE
|
||||
/// </summary>
|
||||
public MinigameList minigamelist;
|
||||
|
||||
/// </summary>
|
||||
/// Reference to the list of available songs
|
||||
/// </summary>
|
||||
@@ -56,6 +69,11 @@ public class JustSignController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public RectTransform hitZoneMeh;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the webcam
|
||||
/// </summary>
|
||||
public RawImage webcamScreen;
|
||||
|
||||
/// <summary>
|
||||
/// Score obtained when getting a perfect hit
|
||||
/// </summary>
|
||||
@@ -106,6 +124,11 @@ public class JustSignController : AbstractMinigameController
|
||||
/// </summary>
|
||||
private List<GameObject> activeSymbols = new List<GameObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Have the symbols started spawning or not
|
||||
/// </summary>
|
||||
private bool gameIsActive = false;
|
||||
|
||||
/// <summary>
|
||||
/// Controls movement speed of symbols (higher -> faster)
|
||||
/// </summary>
|
||||
@@ -161,6 +184,26 @@ public class JustSignController : AbstractMinigameController
|
||||
/// </summary>
|
||||
private int incorrectSigns;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the scoreboard entries container
|
||||
/// </summary>
|
||||
public Transform scoreboardEntriesContainer;
|
||||
|
||||
/// <summary>
|
||||
/// The GameObjects representing the letters
|
||||
/// </summary>
|
||||
private List<GameObject> scoreboardEntries = new List<GameObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the ScoreboardEntry prefab
|
||||
/// </summary>
|
||||
public GameObject scoreboardEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the current user
|
||||
/// </summary>
|
||||
private User user;
|
||||
|
||||
/// <summary>
|
||||
/// LPM
|
||||
/// </summary>
|
||||
@@ -196,11 +239,21 @@ public class JustSignController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public TMP_Text scoreText;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the gameEnded panel, so we can update its display
|
||||
/// </summary>
|
||||
public GameObject gameEndedPanel;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the feedback field
|
||||
/// </summary>
|
||||
public TMP_Text feedbackText;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar
|
||||
/// </summary>
|
||||
public Slider feedbackProgressBar;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar image, so we can add fancy colors
|
||||
/// </summary>
|
||||
@@ -246,9 +299,53 @@ public class JustSignController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public GameObject userFeedback;
|
||||
|
||||
protected override Theme signPredictorTheme
|
||||
/// <summary>
|
||||
/// Start is called before the first frame update
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
get { return currentTheme; }
|
||||
currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
|
||||
signPredictor.SetModel(currentTheme.modelIndex);
|
||||
signPredictor.SwapScreen(webcamScreen);
|
||||
AddSelfAsListener();
|
||||
|
||||
StartController();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the game-specific logic to start the controller
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -291,8 +388,7 @@ public class JustSignController : AbstractMinigameController
|
||||
// Check if the song has ended and activate scorescreen if it has
|
||||
if (currentTime - beginTime > currentSong.duration)
|
||||
{
|
||||
// The boolean that is passed is irrelevant for this game
|
||||
ActivateEnd(true);
|
||||
ActivateEnd();
|
||||
}
|
||||
|
||||
// Move all active symbols to the right
|
||||
@@ -310,11 +406,28 @@ public class JustSignController : AbstractMinigameController
|
||||
/// Calculate the score
|
||||
/// </summary>
|
||||
/// <returns>The calculated score</returns>
|
||||
public override int CalculateScore()
|
||||
public int CalculateScore()
|
||||
{
|
||||
return goodSigns * goodScore + perfectSigns * perfectScore + mehScore * mehSigns + terribleScore * terribleSigns + incorrectSigns * offscreenScore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display Scoreboard + Metrics
|
||||
/// </summary>
|
||||
public void ActivateEnd()
|
||||
{
|
||||
gameIsActive = false;
|
||||
while (activeSymbols.Count > 0)
|
||||
{
|
||||
DestroySymbolAt(0);
|
||||
}
|
||||
// TODO: Scoreboard
|
||||
SaveScores();
|
||||
SetScoreMetrics();
|
||||
SetScoreBoard();
|
||||
gameEndedPanel.SetActive(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroy the symbol at the given index
|
||||
/// </summary>
|
||||
@@ -361,160 +474,282 @@ public class JustSignController : AbstractMinigameController
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logic to process the signs sent by the signPredictor
|
||||
/// Update and save the scores
|
||||
/// </summary>
|
||||
/// <param name="accuracy">The accuracy of the passed sign</param>
|
||||
/// <param name="predictedSign">The name of the passed sign</param>
|
||||
protected override void ProcessMostProbableSign(float accuracy, string predictedSign)
|
||||
public void SaveScores()
|
||||
{
|
||||
Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper() == predictedSign);
|
||||
// Calculate new score
|
||||
int newScore = CalculateScore();
|
||||
|
||||
// If there is a feedback-object, we wil change its appearance
|
||||
if (feedbackText != null && feedbackProgressImage != null)
|
||||
// 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<Score> latestScores = progress.latestScores;
|
||||
List<Score> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set score metrics
|
||||
/// </summary>
|
||||
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()}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the scoreboard
|
||||
/// </summary>
|
||||
private void SetScoreBoard()
|
||||
{
|
||||
// Clean the previous scoreboard entries
|
||||
for (int i = 0; i < scoreboardEntries.Count; i++)
|
||||
{
|
||||
Color col;
|
||||
if (accuracy > predSign.thresholdPercentage)
|
||||
Destroy(scoreboardEntries[i]);
|
||||
}
|
||||
scoreboardEntries.Clear();
|
||||
|
||||
// Instantiate new entries
|
||||
// Get all scores from all users
|
||||
List<Tuple<string, Score>> allScores = new List<Tuple<string, Score>>();
|
||||
foreach (User user in UserList.GetUsers())
|
||||
{
|
||||
// Get user's progress for this minigame
|
||||
var progress = user.GetMinigameProgress(minigame.index);
|
||||
if (progress != null)
|
||||
{
|
||||
feedbackText.text = $"Herkent '{predictedSign}'";
|
||||
col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
|
||||
// Add scores to dictionary
|
||||
List<Score> scores = progress.highestScores;
|
||||
foreach (Score score in scores)
|
||||
{
|
||||
allScores.Add(new Tuple<string, Score>(user.GetUsername(), score));
|
||||
}
|
||||
}
|
||||
else if (accuracy > 0.9 * predSign.thresholdPercentage)
|
||||
}
|
||||
|
||||
// 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<string, Score> 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<Image>().sprite = UserList.GetUserByUsername(username).GetAvatar();
|
||||
|
||||
// Set the player name
|
||||
entry.transform.Find("PlayerName").GetComponent<TMP_Text>().text = username;
|
||||
|
||||
// Set the score
|
||||
entry.transform.Find("Score").GetComponent<TMP_Text>().text = score.scoreValue.ToString();
|
||||
|
||||
// Set the rank
|
||||
entry.transform.Find("Rank").GetComponent<TMP_Text>().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)
|
||||
{
|
||||
feedbackText.text = $"Lijkt op '{predictedSign}'";
|
||||
col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f);
|
||||
formatted = $"{diff.Days}d ";
|
||||
}
|
||||
else if (diff.Hours > 0)
|
||||
{
|
||||
formatted = $"{diff.Hours}h ";
|
||||
}
|
||||
else if (diff.Minutes > 0)
|
||||
{
|
||||
formatted = $"{diff.Minutes}m ";
|
||||
}
|
||||
else
|
||||
{
|
||||
feedbackText.text = "Detecteren...";
|
||||
col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
|
||||
formatted = "now";
|
||||
}
|
||||
|
||||
feedbackText.color = col;
|
||||
feedbackProgressImage.color = col;
|
||||
entry.transform.Find("Ago").GetComponent<TMP_Text>().text = formatted;
|
||||
|
||||
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) =>
|
||||
|
||||
// Alternating colors looks nice
|
||||
if (rank % 2 == 0)
|
||||
{
|
||||
if (feedbackProgress != null)
|
||||
{
|
||||
feedbackProgress.value = t.CurrentValue;
|
||||
}
|
||||
});
|
||||
Image image = entry.transform.GetComponent<Image>();
|
||||
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>();
|
||||
image.color = new Color(0, 229, 255, 233);
|
||||
}
|
||||
|
||||
rank++;
|
||||
}
|
||||
}
|
||||
|
||||
// The logic for the internal workings of the game
|
||||
if (accuracy > predSign.thresholdPercentage)
|
||||
/// <summary>
|
||||
/// The updateFunction that is called when new probabilities become available
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override IEnumerator UpdateFeedback()
|
||||
{
|
||||
// Get the predicted sign
|
||||
if (signPredictor != null && signPredictor.learnableProbabilities != null && gameIsActive)
|
||||
{
|
||||
int matchedSymbolIndex = activeWords.IndexOf(predictedSign.ToUpper());
|
||||
// Get highest predicted sign
|
||||
string predictedSign = signPredictor.learnableProbabilities.Aggregate((a, b) => a.Value > b.Value ? a : b).Key;
|
||||
float accuracy = signPredictor.learnableProbabilities[predictedSign];
|
||||
|
||||
// Destroy the oldest symbol if the current input matches it
|
||||
if (0 <= matchedSymbolIndex)
|
||||
// vvv TEMPORARY STUFF vvv
|
||||
if (predictedSign == "J" && accuracy <= 0.97f)
|
||||
{
|
||||
float x = activeSymbols[matchedSymbolIndex].transform.localPosition.x;
|
||||
predictedSign = signPredictor.learnableProbabilities.Aggregate((x, y) => x.Value > y.Value && x.Key != "J" ? x : y).Key;
|
||||
}
|
||||
accuracy = signPredictor.learnableProbabilities[predictedSign];
|
||||
// ^^^ TEMPORARY STUFF ^^^
|
||||
|
||||
// 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;
|
||||
Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper().Replace(" ", "-") == predictedSign);
|
||||
|
||||
if (perfectCenter - perfectRange / 2 <= x && x <= perfectCenter + perfectRange / 2)
|
||||
if (feedbackText != null && feedbackProgressImage != null)
|
||||
{
|
||||
Color col;
|
||||
if (accuracy > predSign.thresholdPercentage)
|
||||
{
|
||||
timingFeedback.text = $"Perfect! \n +{perfectScore}";
|
||||
imageFeedback.sprite = perfectSprite;
|
||||
perfectSigns++;
|
||||
timingFeedback.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
|
||||
feedbackText.text = $"Herkent '{predictedSign}'";
|
||||
col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
|
||||
}
|
||||
else if (goodCenter - goodRange / 2 <= x && x <= goodCenter + goodRange / 2)
|
||||
else if (accuracy > 0.9 * predSign.thresholdPercentage)
|
||||
{
|
||||
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);
|
||||
feedbackText.text = $"Lijkt op '{predictedSign}'";
|
||||
col = 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);
|
||||
feedbackText.text = "Detecteren...";
|
||||
col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
|
||||
}
|
||||
|
||||
DestroySymbolAt(matchedSymbolIndex);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logic to set the scoreboard of justsign
|
||||
/// </summary>
|
||||
/// <param name="victory">Shows whether or not the player won, is not relevant for JustSIgn</param>
|
||||
protected override void SetScoreBoard(bool victory)
|
||||
{
|
||||
gameEndedPanel.GetComponent<JustSignGameEndedPanel>().GenerateContent(
|
||||
perfectSigns: perfectSigns,
|
||||
goodSigns: goodSigns,
|
||||
mehSigns: mehSigns,
|
||||
terribleSigns: terribleSigns,
|
||||
incorrectSigns: incorrectSigns,
|
||||
duration: currentSong.duration,
|
||||
score: CalculateScore()
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The justsign-specific logic that needs to be called at the start of the game
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The justsign-specific logic that needs to be called at the end of a game
|
||||
/// </summary>
|
||||
/// <param name="victory"></param>
|
||||
protected override void EndGameLogic(bool victory)
|
||||
{
|
||||
gameIsActive = false;
|
||||
while (activeSymbols.Count > 0)
|
||||
else if (feedbackProgressBar != null)
|
||||
{
|
||||
DestroySymbolAt(0);
|
||||
|
||||
feedbackProgressBar.value = 0.0f;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
/// <summary>
|
||||
/// The JustSign-variant of the ScoreBoard
|
||||
/// </summary>
|
||||
public class JustSignGameEndedPanel : AbstractGameEndedPanel
|
||||
{
|
||||
/// <summary>
|
||||
/// Tell the scoreboard that the scoreboard is for JustSign
|
||||
/// </summary>
|
||||
protected override MinigameIndex minigameIndex
|
||||
{
|
||||
get { return MinigameIndex.JUST_SIGN; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The field that will display the amount of perfect signs
|
||||
/// </summary>
|
||||
public TMP_Text perfectSignsText;
|
||||
|
||||
/// <summary>
|
||||
/// The field that will display the amount of good signs
|
||||
/// </summary>
|
||||
public TMP_Text goodSignsText;
|
||||
|
||||
/// <summary>
|
||||
/// The field that will display the amount of meh signs
|
||||
/// </summary>
|
||||
public TMP_Text mehSignsText;
|
||||
|
||||
/// <summary>
|
||||
/// The field that will display the amount of terrible signs
|
||||
/// </summary>
|
||||
public TMP_Text terribleSignsText;
|
||||
|
||||
/// <summary>
|
||||
/// The field that will display the amount of not found signs
|
||||
/// </summary>
|
||||
public TMP_Text notFoundSignsText;
|
||||
|
||||
/// <summary>
|
||||
/// The field that will display the signs per minute
|
||||
/// </summary>
|
||||
public TMP_Text gpmText;
|
||||
|
||||
/// <summary>
|
||||
/// Score
|
||||
/// </summary>
|
||||
public TMP_Text scoreText;
|
||||
|
||||
/// <summary>
|
||||
/// Generate the content of the gameEnded panel
|
||||
/// </summary>
|
||||
/// <param name="perfectSigns">The amount of perfect signs</param>
|
||||
/// <param name="goodSigns">The amount of good signs</param>
|
||||
/// <param name="mehSigns">The amount of meh signs</param>
|
||||
/// <param name="terribleSigns">The emount of terrible signs</param>
|
||||
/// <param name="incorrectSigns">The amount of incorrect signs</param>
|
||||
/// <param name="duration">The duration of the song that was played</param>
|
||||
/// <param name="score">The score obtained by the player</param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a86c239be1aa1543ba8a4ace5f658b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -7,8 +7,7 @@
|
||||
"GUID:1631ed2680c61245b8211d943c1639a8",
|
||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
|
||||
"GUID:58e104b97fb3752438ada2902a36dcbf",
|
||||
"GUID:d0b6b39a21908f94fbbd9f2c196a9725",
|
||||
"GUID:403dd94a93598934eb522dc36df43d7b"
|
||||
"GUID:d0b6b39a21908f94fbbd9f2c196a9725"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -297,7 +297,6 @@ public class SignPredictor : MonoBehaviour
|
||||
/// </summary>
|
||||
private static bool resourceManagerIsInitialized = false;
|
||||
|
||||
private List<string> signs;
|
||||
private EmbeddingDataList embeddingDataList;
|
||||
|
||||
private ModelIndex modelID;
|
||||
@@ -522,6 +521,15 @@ public class SignPredictor : MonoBehaviour
|
||||
{
|
||||
learnableProbabilities = new Dictionary<string, float>();
|
||||
|
||||
// Temporary fix
|
||||
List<string> signs = new List<string>()
|
||||
{
|
||||
"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]);
|
||||
@@ -707,8 +715,4 @@ public class SignPredictor : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSignsList(List<string> signs)
|
||||
{
|
||||
this.signs = signs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 353d02d53aeb14341835f87efae01039
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5e1253d871fce14ab568e5c9ad4ced2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73d452eb6e118ec4091d6cdd82f3550c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,221 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
/// <summary>
|
||||
/// Shared abstract class for the minigameControllers
|
||||
/// </summary>
|
||||
public abstract class AbstractMinigameController : AbstractFeedback
|
||||
{
|
||||
[Header("AbstractVariables")]
|
||||
/// <summary>
|
||||
/// We keep the minigamelist so that the minigame-index doesn't get reset
|
||||
/// DO NOT REMOVE
|
||||
/// </summary>
|
||||
public MinigameList minigamelist;
|
||||
|
||||
/// <summary>
|
||||
/// A bool to denote whether or not the game is still being played
|
||||
/// </summary>
|
||||
protected bool gameIsActive;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar
|
||||
/// </summary>
|
||||
public Slider feedbackProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the current user
|
||||
/// </summary>
|
||||
private User user;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the minigame ScriptableObject
|
||||
/// </summary>
|
||||
protected Minigame minigame;
|
||||
|
||||
/// <summary>
|
||||
/// Each minigame has a webcamTexture, this will be used in children-methods
|
||||
/// </summary>
|
||||
public RawImage webcamScreen;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the gameEnded panel, so we can update its display
|
||||
/// </summary>
|
||||
public GameObject gameEndedPanel;
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
/// </summary>
|
||||
protected abstract Theme signPredictorTheme
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start is called before the first frame update, seal it to prevent minigames from changing it
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="System.NotImplementedException"></exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Each game keeps a score, this score needs to be saved at some point
|
||||
/// </summary>
|
||||
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<Score> latestScores = progress.latestScores;
|
||||
List<Score> 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();
|
||||
}
|
||||
/// <summary>
|
||||
/// The function that activates when the game ends, handles some endgame logic and displays the EndPanel
|
||||
/// </summary>
|
||||
/// <param name="won"></param>
|
||||
public void ActivateEnd(bool victory)
|
||||
{
|
||||
EndGameLogic(victory);
|
||||
SaveScores();
|
||||
SetScoreBoard(victory);
|
||||
|
||||
gameEndedPanel.SetActive(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once the most probable sign has been fetched, they can be processed
|
||||
/// </summary>
|
||||
/// <param name="accuracy">The accuracy of the passed sign</param>
|
||||
/// <param name="predictedSign">The name of the passed sign</param>
|
||||
protected abstract void ProcessMostProbableSign(float accuracy, string predictedSign);
|
||||
|
||||
/// <summary>
|
||||
/// Each minigame has their own way of calculating their score
|
||||
/// </summary>
|
||||
/// <returns>The score that the user has at that point</returns>
|
||||
public abstract int CalculateScore();
|
||||
|
||||
/// <summary>
|
||||
/// Each minigame has an AbstractGameEndedPanel at the end, but they each have their own unique concrete instance
|
||||
/// </summary>
|
||||
/// <param name="victory">1 if the player won, 0 if they lost. Some games need this</param>
|
||||
protected abstract void SetScoreBoard(bool victory);
|
||||
|
||||
/// <summary>
|
||||
/// Each minigame puts their GameLogic to be called at (re)start in a seperate function from Start()
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logic to be called at the start of the game
|
||||
/// </summary>
|
||||
protected abstract void StartGameLogic();
|
||||
|
||||
/// <summary>
|
||||
/// Function that contains all the logic to end the game
|
||||
/// </summary>
|
||||
/// <param name="victory">1 if the player won, 0 if they lost. Some games need this</param>
|
||||
protected abstract void EndGameLogic(bool victory);
|
||||
|
||||
/// <summary>
|
||||
/// All non-fingerspelling-minigames have the same logic for the GetSignsList
|
||||
/// </summary>
|
||||
/// <returns>The signsList that needs to be passed to the signPredictor</returns>
|
||||
private List<string> GetSignsList()
|
||||
{
|
||||
List<string> signsList = new List<string>();
|
||||
foreach (Learnable learnable in signPredictorTheme.learnables)
|
||||
{
|
||||
signsList.Add(learnable.name);
|
||||
}
|
||||
|
||||
return signsList;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a32c0ecc5507e4542a79c1b96a47b0a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 403dd94a93598934eb522dc36df43d7b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -5,7 +5,7 @@ using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class SpellingBeeGameEndedPanelTests
|
||||
public class GameEndedPanelTests
|
||||
{
|
||||
[UnitySetUp]
|
||||
public IEnumerator SetupFunction()
|
||||
@@ -31,15 +31,15 @@ public class SpellingBeeGameEndedPanelTests
|
||||
yield return new WaitForSeconds(1f);
|
||||
|
||||
|
||||
spellingBeeController.ActivateEnd(true);
|
||||
spellingBeeController.ActivateWin();
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ public class SpellingBeeControllerTests
|
||||
public IEnumerator ActivateGameOverTest()
|
||||
{
|
||||
SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController));
|
||||
spellingBeeController.ActivateEnd(false);
|
||||
spellingBeeController.ActivateGameOver();
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
|
||||
Assert.NotNull(SpellingBeeGameEndedPanel);
|
||||
Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text);
|
||||
GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
|
||||
Assert.NotNull(gameEndedPanel);
|
||||
Assert.AreEqual("VERLOREN", gameEndedPanel.endText.text);
|
||||
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@ public class SpellingBeeControllerTests
|
||||
public IEnumerator ActivateWinTests()
|
||||
{
|
||||
SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController));
|
||||
spellingBeeController.ActivateEnd(true);
|
||||
spellingBeeController.ActivateWin();
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
|
||||
Assert.NotNull(SpellingBeeGameEndedPanel);
|
||||
Assert.AreEqual("GEWONNEN", SpellingBeeGameEndedPanel.endText.text);
|
||||
GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
|
||||
Assert.NotNull(gameEndedPanel);
|
||||
Assert.AreEqual("GEWONNEN", gameEndedPanel.endText.text);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
@@ -64,8 +64,8 @@ public class SpellingBeeControllerTests
|
||||
spellingBeeController.AddSeconds(-60);
|
||||
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel));
|
||||
Assert.NotNull(SpellingBeeGameEndedPanel);
|
||||
Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text);
|
||||
GameEndedPanel gameEndedPanel = (GameEndedPanel)GameObject.FindObjectOfType(typeof(GameEndedPanel));
|
||||
Assert.NotNull(gameEndedPanel);
|
||||
Assert.AreEqual("VERLOREN", gameEndedPanel.endText.text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
"Unity.TextMeshPro",
|
||||
"SpellingBeeScripts",
|
||||
"AccountsScripts",
|
||||
"ArchitectureScripts",
|
||||
"SignPredictor",
|
||||
"MinigameScripts"
|
||||
"SystemArchitecture",
|
||||
"SignPredictor"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -1432,8 +1432,6 @@ 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}
|
||||
@@ -1443,6 +1441,8 @@ 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,20 +3982,21 @@ 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
|
||||
|
||||
@@ -4,19 +4,50 @@ using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
/// <summary>
|
||||
/// Abstract class for all minigame-gameEndedPanels
|
||||
/// </summary>
|
||||
public abstract class AbstractGameEndedPanel : MonoBehaviour
|
||||
|
||||
public class GameEndedPanel : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The index of minigame that needs a GameEndedPanel
|
||||
/// "VERLOREN" or "GEWONNEN"
|
||||
/// </summary>
|
||||
protected abstract MinigameIndex minigameIndex
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public TMP_Text endText;
|
||||
|
||||
/// <summary>
|
||||
/// LPM
|
||||
/// </summary>
|
||||
public TMP_Text lpmText;
|
||||
|
||||
/// <summary>
|
||||
/// Letters ( right | wrong )
|
||||
/// </summary>
|
||||
public TMP_Text lettersRightText;
|
||||
public TMP_Text lettersWrongText;
|
||||
|
||||
/// <summary>
|
||||
/// Letters
|
||||
/// </summary>
|
||||
public TMP_Text lettersTotalText;
|
||||
|
||||
/// <summary>
|
||||
/// Accuracy
|
||||
/// </summary>
|
||||
public TMP_Text accuracyText;
|
||||
|
||||
/// <summary>
|
||||
/// Words
|
||||
/// </summary>
|
||||
public TMP_Text wordsText;
|
||||
|
||||
/// <summary>
|
||||
/// Time
|
||||
/// </summary>
|
||||
public TMP_Text timeText;
|
||||
|
||||
/// <summary>
|
||||
/// Score
|
||||
/// </summary>
|
||||
public TMP_Text scoreText;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the scoreboard entries container
|
||||
/// </summary>
|
||||
@@ -32,10 +63,55 @@ public abstract class AbstractGameEndedPanel : MonoBehaviour
|
||||
/// </summary>
|
||||
public GameObject scoreboardEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Generate the content of the GameEnded panel
|
||||
/// </summary>
|
||||
/// <param name="startTime">Time of starting the minigame</param>
|
||||
/// <param name="totalWords">Total number of words</param>
|
||||
/// <param name="correctLetters">Total number of correctly spelled letters</param>
|
||||
/// <param name="incorrectLetters">Total number of incorrectly spelled letters</param>
|
||||
/// <param name="result">"VERLOREN" or "GEWONNEN"</param>
|
||||
/// <param name="score">Final score</param>
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the scoreboard
|
||||
/// </summary>
|
||||
protected void SetScoreBoard()
|
||||
private void SetScoreBoard()
|
||||
{
|
||||
// Clean the previous scoreboard entries
|
||||
for (int i = 0; i < scoreboardEntries.Count; i++)
|
||||
@@ -50,7 +126,7 @@ public abstract class AbstractGameEndedPanel : MonoBehaviour
|
||||
foreach (User user in UserList.GetUsers())
|
||||
{
|
||||
// Get user's progress for this minigame
|
||||
var progress = user.GetMinigameProgress(minigameIndex);
|
||||
var progress = user.GetMinigameProgress(MinigameIndex.SPELLING_BEE);
|
||||
if (progress != null)
|
||||
{
|
||||
// Add scores to dictionary
|
||||
@@ -7,7 +7,7 @@ using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public partial class SpellingBeeController : AbstractMinigameController
|
||||
public partial class SpellingBeeController : AbstractFeedback
|
||||
{
|
||||
/// <summary>
|
||||
/// All of the words that can be used in this session
|
||||
@@ -45,6 +45,11 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// </summary>
|
||||
private float timerValue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the game is still going
|
||||
/// </summary>
|
||||
private bool gameEnded;
|
||||
|
||||
/// <summary>
|
||||
/// List of learnables to get the threshold for the letters
|
||||
/// </summary>
|
||||
@@ -76,6 +81,22 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// </summary>
|
||||
private DateTime startTime;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the current user
|
||||
/// </summary>
|
||||
private User user;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the minigame ScriptableObject
|
||||
/// </summary>
|
||||
public Minigame minigame;
|
||||
|
||||
/// <summary>
|
||||
/// We keep the minigamelist as well so that the minigame-index doesn't get reset
|
||||
/// DO NOT REMOVE
|
||||
/// </summary>
|
||||
public MinigameList minigamelist;
|
||||
|
||||
/// <summary>
|
||||
/// Letter prefab
|
||||
/// </summary>
|
||||
@@ -116,11 +137,21 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public Transform Scoreboard;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the gameEnded panel, so we can update its display
|
||||
/// </summary>
|
||||
public GameObject gameEndedPanel;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the feedback field
|
||||
/// </summary>
|
||||
public TMP_Text feedbackText;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar
|
||||
/// </summary>
|
||||
public Slider feedbackProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the progress bar image, so we can add fancy colors
|
||||
/// </summary>
|
||||
@@ -141,6 +172,11 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// </summary>
|
||||
protected string previousIncorrectSign = null;
|
||||
|
||||
/// <summary>
|
||||
/// Reference used to set the webcam for the SignPredictor
|
||||
/// </summary>
|
||||
public RawImage webcamScreen;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to display the score
|
||||
/// </summary>
|
||||
@@ -162,11 +198,57 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
private int incorrectLettersScore = -5;
|
||||
|
||||
/// <summary>
|
||||
/// Set the AbstractMinigameController variable to inform it of the theme for the signPredictor
|
||||
/// Start is called before the first frame update
|
||||
/// </summary>
|
||||
protected override Theme signPredictorTheme
|
||||
public void Start()
|
||||
{
|
||||
get { return fingerspelling; }
|
||||
signPredictor.SetModel(ModelIndex.FINGERSPELLING);
|
||||
signPredictor.SwapScreen(webcamScreen);
|
||||
AddSelfAsListener();
|
||||
|
||||
StartController();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is called at the start of the scene AND when the game is replayed
|
||||
/// </summary>
|
||||
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 = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -174,7 +256,7 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
if (gameIsActive)
|
||||
if (!gameEnded)
|
||||
{
|
||||
timerValue -= Time.deltaTime;
|
||||
if (bonusActiveRemaining <= 0.0 && bonusTimeText.activeSelf)
|
||||
@@ -190,8 +272,7 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
if (timerValue <= 0.0f)
|
||||
{
|
||||
timerValue = 0.0f;
|
||||
//ActivateGameOver();
|
||||
ActivateEnd(false);
|
||||
ActivateGameOver();
|
||||
}
|
||||
|
||||
int minutes = Mathf.FloorToInt(timerValue / 60.0f);
|
||||
@@ -221,11 +302,89 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// Calculate the score
|
||||
/// </summary>
|
||||
/// <returns>The calculated score</returns>
|
||||
public override int CalculateScore()
|
||||
public int CalculateScore()
|
||||
{
|
||||
return correctLetters * correctLettersScore + incorrectLetters * incorrectLettersScore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays the game over panel and score values
|
||||
/// </summary>
|
||||
public void ActivateGameOver()
|
||||
{
|
||||
gameEnded = true;
|
||||
DeleteWord();
|
||||
|
||||
// Save the scores and show the scoreboard
|
||||
SaveScores();
|
||||
gameEndedPanel.GetComponent<GameEndedPanel>().GenerateContent(
|
||||
startTime: startTime,
|
||||
totalWords: spelledWords,
|
||||
correctLetters: correctLetters,
|
||||
incorrectLetters: incorrectLetters,
|
||||
result: "VERLOREN",
|
||||
score: CalculateScore()
|
||||
);
|
||||
|
||||
gameEndedPanel.SetActive(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display win screen
|
||||
/// </summary>
|
||||
public void ActivateWin()
|
||||
{
|
||||
gameEnded = true;
|
||||
DeleteWord();
|
||||
|
||||
// Save the scores and show the scoreboard
|
||||
SaveScores();
|
||||
gameEndedPanel.GetComponent<GameEndedPanel>().GenerateContent(
|
||||
startTime: startTime,
|
||||
totalWords: spelledWords,
|
||||
correctLetters: correctLetters,
|
||||
incorrectLetters: incorrectLetters,
|
||||
result: "GEWONNEN",
|
||||
score: CalculateScore()
|
||||
);
|
||||
|
||||
gameEndedPanel.SetActive(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update and save the scores
|
||||
/// </summary>
|
||||
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<Score> latestScores = progress.latestScores;
|
||||
List<Score> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete all letter objects
|
||||
/// </summary>
|
||||
@@ -255,7 +414,7 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
/// <param name="successful">true if the letter was correctly signed, false otherwise</param>
|
||||
public void NextLetter(bool successful)
|
||||
{
|
||||
if (!gameIsActive) { return; }
|
||||
if (gameEnded) { return; }
|
||||
|
||||
// Change color of current letter (skip spaces)
|
||||
if (successful)
|
||||
@@ -310,8 +469,7 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
}
|
||||
else
|
||||
{
|
||||
//ActivateWin();
|
||||
ActivateEnd(true);
|
||||
ActivateWin();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +514,7 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
Learnable letter = fingerspelling.learnables.Find(l => l.name == sign);
|
||||
return letter.thresholdPercentage;
|
||||
}
|
||||
/*
|
||||
|
||||
/// <summary>
|
||||
/// The updateFunction that is called when new probabilities become available
|
||||
/// </summary>
|
||||
@@ -367,7 +525,7 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
string currentSign = GetSign();
|
||||
// Get the predicted sign
|
||||
if (signPredictor != null && signPredictor.learnableProbabilities != null &&
|
||||
currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign) && gameIsActive)
|
||||
currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign))
|
||||
{
|
||||
float accCurrentSign = signPredictor.learnableProbabilities[currentSign];
|
||||
float thresholdCurrentSign = GetTresholdPercentage(currentSign);
|
||||
@@ -455,7 +613,6 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// Function to get the current letter that needs to be signed
|
||||
/// </summary>
|
||||
@@ -481,157 +638,4 @@ public partial class SpellingBeeController : AbstractMinigameController
|
||||
}
|
||||
NextLetter(successful);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logic to process the signs sent by the signPredictor
|
||||
/// </summary>
|
||||
/// <param name="accuracy">The accuracy of the passed sign</param>
|
||||
/// <param name="predictedSign">The name of the passed sign</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logic to set the scoreboard of spellingbee
|
||||
/// </summary>
|
||||
/// <param name="victory">SHows whether or not the player won</param>
|
||||
protected override void SetScoreBoard(bool victory)
|
||||
{
|
||||
string resultTxt;
|
||||
if (victory)
|
||||
{
|
||||
resultTxt = "GEWONNEN";
|
||||
}
|
||||
else
|
||||
{
|
||||
resultTxt = "VERLOREN";
|
||||
}
|
||||
// Save the scores and show the scoreboard
|
||||
gameEndedPanel.GetComponent<SpellingBeeGameEndedPanel>().GenerateContent(
|
||||
startTime: startTime,
|
||||
totalWords: spelledWords,
|
||||
correctLetters: correctLetters,
|
||||
incorrectLetters: incorrectLetters,
|
||||
result: resultTxt,
|
||||
score: CalculateScore()
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The spellinbee-specific logic that needs to be called at the start of the game
|
||||
/// </summary>
|
||||
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 = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The spellingbee-specific logic that needs to be called at the end of a game
|
||||
/// </summary>
|
||||
/// <param name="victory"></param>
|
||||
protected override void EndGameLogic(bool victory)
|
||||
{
|
||||
gameIsActive = false;
|
||||
DeleteWord();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class SpellingBeeGameEndedPanel : AbstractGameEndedPanel
|
||||
{
|
||||
/// <summary>
|
||||
/// Tell the scoreboard that the scoreboard is for SpellingBee
|
||||
/// </summary>
|
||||
protected override MinigameIndex minigameIndex
|
||||
{
|
||||
get { return MinigameIndex.SPELLING_BEE; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "VERLOREN" or "GEWONNEN"
|
||||
/// </summary>
|
||||
public TMP_Text endText;
|
||||
|
||||
/// <summary>
|
||||
/// LPM
|
||||
/// </summary>
|
||||
public TMP_Text lpmText;
|
||||
|
||||
/// <summary>
|
||||
/// Letters ( right | wrong )
|
||||
/// </summary>
|
||||
public TMP_Text lettersRightText;
|
||||
public TMP_Text lettersWrongText;
|
||||
|
||||
/// <summary>
|
||||
/// Letters
|
||||
/// </summary>
|
||||
public TMP_Text lettersTotalText;
|
||||
|
||||
/// <summary>
|
||||
/// Accuracy
|
||||
/// </summary>
|
||||
public TMP_Text accuracyText;
|
||||
|
||||
/// <summary>
|
||||
/// Words
|
||||
/// </summary>
|
||||
public TMP_Text wordsText;
|
||||
|
||||
/// <summary>
|
||||
/// Time
|
||||
/// </summary>
|
||||
public TMP_Text timeText;
|
||||
|
||||
/// <summary>
|
||||
/// Score
|
||||
/// </summary>
|
||||
public TMP_Text scoreText;
|
||||
|
||||
/// <summary>
|
||||
/// Generate the content of the GameEnded panel
|
||||
/// </summary>
|
||||
/// <param name="startTime">Time of starting the minigame</param>
|
||||
/// <param name="totalWords">Total number of words</param>
|
||||
/// <param name="correctLetters">Total number of correctly spelled letters</param>
|
||||
/// <param name="incorrectLetters">Total number of incorrectly spelled letters</param>
|
||||
/// <param name="result">"VERLOREN" or "GEWONNEN"</param>
|
||||
/// <param name="score">Final score</param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,7 @@
|
||||
"GUID:d0b6b39a21908f94fbbd9f2c196a9725",
|
||||
"GUID:58e104b97fb3752438ada2902a36dcbf",
|
||||
"GUID:e83ddf9a537a96b4a804a16bb7872ec1",
|
||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
|
||||
"GUID:403dd94a93598934eb522dc36df43d7b"
|
||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "ArchitectureScripts",
|
||||
"name": "SystemArchitecture",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
@@ -1,12 +1,14 @@
|
||||
{
|
||||
"name": "ArchitectureTests",
|
||||
"name": "SystemArchitectureTests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityEditor.TestRunner",
|
||||
"UnityEngine.TestRunner",
|
||||
"ArchitectureScripts"
|
||||
"SystemArchitecture"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
Binary file not shown.
@@ -168,8 +168,7 @@ PlayerSettings:
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
- {fileID: 11400000, guid: 57fdfdc7df920454ba35444c783867d8, type: 2}
|
||||
metroInputSource: 0
|
||||
wsaTransparentSwapchain: 0
|
||||
m_HolographicPauseOnTrackingLoss: 1
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user