Resolve WES-131-Feedback-REfactor
This commit is contained in:
committed by
Dries Van Schuylenbergh
parent
b955d2164c
commit
a808e73a29
@@ -8,7 +8,8 @@
|
|||||||
"CommonScripts",
|
"CommonScripts",
|
||||||
"InterfacesScripts",
|
"InterfacesScripts",
|
||||||
"Unity.TextMeshPro",
|
"Unity.TextMeshPro",
|
||||||
"AccountsScripts"
|
"AccountsScripts",
|
||||||
|
"SignPredictor"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||||
"GUID:63c63e721f65ebb7d871cb9ef49f4752",
|
"GUID:63c63e721f65ebb7d871cb9ef49f4752",
|
||||||
"GUID:1631ed2680c61245b8211d943c1639a8",
|
"GUID:1631ed2680c61245b8211d943c1639a8",
|
||||||
"GUID:5c2b5ba89f9e74e418232e154bc5cc7a",
|
|
||||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
|
|||||||
@@ -1273,7 +1273,6 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2}
|
modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2}
|
||||||
model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
|
||||||
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
|
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
|
||||||
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
||||||
screen: {fileID: 378145456}
|
screen: {fileID: 378145456}
|
||||||
@@ -1529,6 +1528,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 6b3f784c065813a4a8364b1299284816, type: 3}
|
m_Script: {fileID: 11500000, guid: 6b3f784c065813a4a8364b1299284816, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
signPredictor: {fileID: 883853268}
|
||||||
previewModel: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
previewModel: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
||||||
feedbackProgressBar: {fileID: 4318122121437849759}
|
feedbackProgressBar: {fileID: 4318122121437849759}
|
||||||
previewMessage: {fileID: 2070775951}
|
previewMessage: {fileID: 2070775951}
|
||||||
@@ -1544,7 +1544,9 @@ MonoBehaviour:
|
|||||||
ResultsDecription: {fileID: 100123246}
|
ResultsDecription: {fileID: 100123246}
|
||||||
CoursesButton: {fileID: 839294691}
|
CoursesButton: {fileID: 839294691}
|
||||||
timeSpent: {fileID: 77614869}
|
timeSpent: {fileID: 77614869}
|
||||||
feedback: {fileID: 1714882683}
|
feedbackText: {fileID: 4318122121437849762}
|
||||||
|
feedbackProgress: {fileID: 4318122121437849761}
|
||||||
|
feedbackProgressImage: {fileID: 4318122121437849760}
|
||||||
--- !u!4 &1122267057
|
--- !u!4 &1122267057
|
||||||
Transform:
|
Transform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2284,17 +2286,6 @@ RectTransform:
|
|||||||
m_CorrespondingSourceObject: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
m_CorrespondingSourceObject: {fileID: 4318122119930585316, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
m_PrefabInstance: {fileID: 4318122121437849758}
|
m_PrefabInstance: {fileID: 4318122121437849758}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
--- !u!114 &1714882683 stripped
|
|
||||||
MonoBehaviour:
|
|
||||||
m_CorrespondingSourceObject: {fileID: 4318122119930585317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
|
||||||
m_PrefabInstance: {fileID: 4318122121437849758}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 4318122121437849759}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 44e682a32ee15cc489bf50f3a06f717b, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
--- !u!1 &1773033262
|
--- !u!1 &1773033262
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2897,3 +2888,36 @@ GameObject:
|
|||||||
m_CorrespondingSourceObject: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
m_CorrespondingSourceObject: {fileID: 4318122119930585319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
m_PrefabInstance: {fileID: 4318122121437849758}
|
m_PrefabInstance: {fileID: 4318122121437849758}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
--- !u!114 &4318122121437849760 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 4318122120334233319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 4318122121437849758}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
--- !u!114 &4318122121437849761 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 4318122119968934242, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 4318122121437849758}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 67db9e8f0e2ae9c40bc1e2b64352a6b4, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
--- !u!114 &4318122121437849762 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 4318122121437849758}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"Unity.TextMeshPro",
|
"Unity.TextMeshPro",
|
||||||
"AccountsScripts",
|
"AccountsScripts",
|
||||||
"InterfacesScripts",
|
"InterfacesScripts",
|
||||||
"SignPredictor",
|
"Tween",
|
||||||
"Unity.Barracuda"
|
"SignPredictor"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
using DigitalRuby.Tween;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using Unity.Barracuda;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityEngine.Video;
|
using UnityEngine.Video;
|
||||||
@@ -8,13 +9,10 @@ using UnityEngine.Video;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// TemplateCourse scene manager
|
/// TemplateCourse scene manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CoursesController : MonoBehaviour
|
public class CoursesController : AbstractFeedback
|
||||||
{
|
{
|
||||||
// vvv TEMPORARY STUFF vvv
|
|
||||||
public NNModel previewModel;
|
|
||||||
public GameObject feedbackProgressBar;
|
public GameObject feedbackProgressBar;
|
||||||
public GameObject previewMessage;
|
public GameObject previewMessage;
|
||||||
// ^^^ TEMPORARY STUFF ^^^
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reference to instructional video player
|
/// Reference to instructional video player
|
||||||
@@ -112,10 +110,37 @@ public class CoursesController : MonoBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public TMP_Text timeSpent;
|
public TMP_Text timeSpent;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reference to the feedback script on the Feedback prefab
|
/// Reference to the feedback field
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Feedback feedback;
|
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>
|
||||||
|
/// Timer to keep track of how long a incorrect sign is performed
|
||||||
|
/// </summary>
|
||||||
|
protected DateTime timer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current predicted sign
|
||||||
|
/// </summary>
|
||||||
|
protected string predictedSign = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs
|
||||||
|
/// </summary>
|
||||||
|
protected string previousIncorrectSign = null;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function is called when the script is initialised.
|
/// This function is called when the script is initialised.
|
||||||
@@ -124,19 +149,25 @@ public class CoursesController : MonoBehaviour
|
|||||||
/// Then it checks whether or not the User has started the course yet, to possibly create a new progress atribute for the course.
|
/// Then it checks whether or not the User has started the course yet, to possibly create a new progress atribute for the course.
|
||||||
/// Then it sets up the course-screen to display relevant information from the course-scriptable.
|
/// Then it sets up the course-screen to display relevant information from the course-scriptable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Awake()
|
void Start()
|
||||||
|
{
|
||||||
|
StartCourseController();
|
||||||
|
|
||||||
|
signPredictor.SetModel(course.theme.modelIndex);
|
||||||
|
AddSelfAsListener();
|
||||||
|
}
|
||||||
|
/// <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>
|
||||||
|
public void StartCourseController()
|
||||||
{
|
{
|
||||||
// Setting up course
|
// Setting up course
|
||||||
course = courselist.courses[courselist.currentCourseIndex];
|
course = courselist.courses[courselist.currentCourseIndex];
|
||||||
feedback.signPredictor.ChangeModel(course.theme.modelIndex);
|
|
||||||
maxWords = course.theme.learnables.Count;
|
maxWords = course.theme.learnables.Count;
|
||||||
|
|
||||||
// vvv TEMPORARY STUFF vvv
|
// Show preview messages if there is no model
|
||||||
feedbackProgressBar.SetActive(course.theme.modelIndex != ModelIndex.NONE);
|
feedbackProgressBar.SetActive(course.theme.modelIndex != ModelIndex.NONE);
|
||||||
previewMessage.SetActive(course.theme.modelIndex == ModelIndex.NONE);
|
previewMessage.SetActive(course.theme.modelIndex == ModelIndex.NONE);
|
||||||
// Instead, the NONE-modelIndex points to Fingerspelling, which gives the same result
|
|
||||||
//feedback.signPredictor.model = previewModel;
|
|
||||||
// ^^^ TEMPORARY STUFF ^^^
|
|
||||||
|
|
||||||
// Create entry in current user for keeping track of progress
|
// Create entry in current user for keeping track of progress
|
||||||
userList.Load();
|
userList.Load();
|
||||||
@@ -164,23 +195,6 @@ public class CoursesController : MonoBehaviour
|
|||||||
ResultPanel.SetActive(false);
|
ResultPanel.SetActive(false);
|
||||||
// Set the startTime
|
// Set the startTime
|
||||||
startMoment = DateTime.Now;
|
startMoment = DateTime.Now;
|
||||||
|
|
||||||
// Set callbacks
|
|
||||||
feedback.getSignCallback = () =>
|
|
||||||
{
|
|
||||||
if (currentWordIndex < course.theme.learnables.Count)
|
|
||||||
{
|
|
||||||
return course.theme.learnables[currentWordIndex].name;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
feedback.predictSignCallback = (sign) =>
|
|
||||||
{
|
|
||||||
if (sign == course.theme.learnables[currentWordIndex].name)
|
|
||||||
{
|
|
||||||
NextSign();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -287,4 +301,104 @@ public class CoursesController : MonoBehaviour
|
|||||||
progress.AddOrUpdate<float>("courseProgress", 1f);
|
progress.AddOrUpdate<float>("courseProgress", 1f);
|
||||||
userList.Save();
|
userList.Save();
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// The updateFunction that is called when new probabilities become available
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override IEnumerator UpdateFeedback()
|
||||||
|
{
|
||||||
|
// Get current sign
|
||||||
|
string currentSign = course.theme.learnables[currentWordIndex].name;
|
||||||
|
// Get the predicted sign
|
||||||
|
if (signPredictor != null && signPredictor.learnableProbabilities != null &&
|
||||||
|
currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign))
|
||||||
|
{
|
||||||
|
float accuracy = signPredictor.learnableProbabilities[currentSign];
|
||||||
|
if (feedbackText != null && feedbackProgressImage != null)
|
||||||
|
{
|
||||||
|
if (accuracy > 0.90)
|
||||||
|
{
|
||||||
|
feedbackText.text = "Goed";
|
||||||
|
feedbackText.color = Color.green;
|
||||||
|
feedbackProgressImage.color = Color.green;
|
||||||
|
}
|
||||||
|
else if (accuracy > 0.80)
|
||||||
|
{
|
||||||
|
feedbackText.text = "Bijna...";
|
||||||
|
Color col = new Color(0xff / 255.0f, 0x66 / 255.0f, 0x00 / 255.0f);
|
||||||
|
feedbackText.color = col;
|
||||||
|
feedbackProgressImage.color = col;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
feedbackText.text = "Detecteren...";
|
||||||
|
feedbackText.color = Color.red;
|
||||||
|
feedbackProgressImage.color = Color.red;
|
||||||
|
}
|
||||||
|
|
||||||
|
float oldValue = feedbackProgress.value;
|
||||||
|
// use an exponential scale
|
||||||
|
float newValue = Mathf.Exp(4 * (accuracy - 1.0f));
|
||||||
|
feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
|
||||||
|
{
|
||||||
|
if (feedbackProgress != null)
|
||||||
|
{
|
||||||
|
feedbackProgress.value = t.CurrentValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether (in)correct sign has high accuracy
|
||||||
|
foreach (var kv in signPredictor.learnableProbabilities)
|
||||||
|
{
|
||||||
|
if (kv.Value > 0.90)
|
||||||
|
{
|
||||||
|
predictedSign = kv.Key;
|
||||||
|
// Correct sign
|
||||||
|
if (predictedSign == currentSign)
|
||||||
|
{
|
||||||
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
CheckEquality(predictedSign);
|
||||||
|
timer = DateTime.Now;
|
||||||
|
predictedSign = null;
|
||||||
|
previousIncorrectSign = null;
|
||||||
|
}
|
||||||
|
// Incorrect sign
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (previousIncorrectSign != predictedSign)
|
||||||
|
{
|
||||||
|
timer = DateTime.Now;
|
||||||
|
previousIncorrectSign = predictedSign;
|
||||||
|
}
|
||||||
|
else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f))
|
||||||
|
{
|
||||||
|
CheckEquality(predictedSign);
|
||||||
|
timer = DateTime.Now;
|
||||||
|
predictedSign = null;
|
||||||
|
previousIncorrectSign = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (feedbackProgress != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
feedbackProgress.value = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Function to check equality between the current sign and the sign that the model predicted, if they are equal then the next sign is fetched.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="predicted"></param>
|
||||||
|
private void CheckEquality(string predicted)
|
||||||
|
{
|
||||||
|
if (predicted == course.theme.learnables[currentWordIndex].name)
|
||||||
|
{
|
||||||
|
NextSign();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ RenderSettings:
|
|||||||
m_ReflectionIntensity: 1
|
m_ReflectionIntensity: 1
|
||||||
m_CustomReflection: {fileID: 0}
|
m_CustomReflection: {fileID: 0}
|
||||||
m_Sun: {fileID: 0}
|
m_Sun: {fileID: 0}
|
||||||
m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1}
|
m_IndirectSpecularColor: {r: 0.37311918, g: 0.3807398, b: 0.35872716, a: 1}
|
||||||
m_UseRadianceAmbientProbe: 0
|
m_UseRadianceAmbientProbe: 0
|
||||||
--- !u!157 &3
|
--- !u!157 &3
|
||||||
LightmapSettings:
|
LightmapSettings:
|
||||||
@@ -5129,6 +5129,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 2db44635e0eb1e9429a2e6195785364d, type: 3}
|
m_Script: {fileID: 11500000, guid: 2db44635e0eb1e9429a2e6195785364d, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
signPredictor: {fileID: 1991376311}
|
||||||
themelist: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2}
|
themelist: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2}
|
||||||
letterPrefab: {fileID: 4639383499500021565, guid: c3e66e8957864914cb022af914df6a28, type: 3}
|
letterPrefab: {fileID: 4639383499500021565, guid: c3e66e8957864914cb022af914df6a28, type: 3}
|
||||||
letterContainer: {fileID: 1870283439}
|
letterContainer: {fileID: 1870283439}
|
||||||
@@ -5153,8 +5154,10 @@ MonoBehaviour:
|
|||||||
Scoreboard: {fileID: 1007532375}
|
Scoreboard: {fileID: 1007532375}
|
||||||
EntriesGrid: {fileID: 1391137944}
|
EntriesGrid: {fileID: 1391137944}
|
||||||
scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
|
scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
|
||||||
feedback: {fileID: 5233312447513285388}
|
|
||||||
gottogamebutton: {fileID: 1581633295}
|
gottogamebutton: {fileID: 1581633295}
|
||||||
|
feedbackText: {fileID: 0}
|
||||||
|
feedbackProgress: {fileID: 0}
|
||||||
|
feedbackProgressImage: {fileID: 0}
|
||||||
--- !u!1 &1678036720
|
--- !u!1 &1678036720
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -6183,7 +6186,6 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2}
|
modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2}
|
||||||
model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
|
||||||
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
|
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
|
||||||
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
||||||
screen: {fileID: 1649505745}
|
screen: {fileID: 1649505745}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
public class HangManWebcam : WebCam
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The display for player 1
|
|
||||||
/// </summary>
|
|
||||||
public RawImage display1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The display for player 2
|
|
||||||
/// </summary>
|
|
||||||
public RawImage display2;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We use a different awake, since we dont want the camera to start immediatelly
|
|
||||||
/// </summary>
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
WebCamDevice device = WebCamTexture.devices[camdex];
|
|
||||||
tex = new WebCamTexture(device.name);
|
|
||||||
display.texture = tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hangman uses two different webcam_textures, we need to be able to toggle between them
|
|
||||||
/// </summary>
|
|
||||||
public void Switch_texture()
|
|
||||||
{
|
|
||||||
if(display == display1)
|
|
||||||
{
|
|
||||||
display = display2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
display = display1;
|
|
||||||
}
|
|
||||||
// Give the webcamTexture to the new webcam
|
|
||||||
display.texture = tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Scene changing is implemented here to avoid problems with webcam
|
|
||||||
/// </summary>
|
|
||||||
public new void GotoThemeSelection()
|
|
||||||
{
|
|
||||||
//minigameList.GetIndexInMinigameList(MinigameIndex.HANGMAN);
|
|
||||||
if (tex != null)
|
|
||||||
{
|
|
||||||
if (tex.isPlaying)
|
|
||||||
{
|
|
||||||
display.texture = null;
|
|
||||||
tex.Stop();
|
|
||||||
tex = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SystemController.GetInstance().BackToPreviousScene();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using DigitalRuby.Tween;
|
||||||
|
|
||||||
public class HangmanController : MonoBehaviour
|
public class HangmanController : AbstractFeedback
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The scriptable with all the themes, will be used to select a random word for hangman.
|
/// The scriptable with all the themes, will be used to select a random word for hangman.
|
||||||
@@ -18,11 +20,6 @@ public class HangmanController : MonoBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private string currentWord;
|
private string currentWord;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// All of the words that can be used in this session
|
|
||||||
/// </summary>
|
|
||||||
private string[] words;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This integer holds the total amount of wrong guesses the player has made
|
/// This integer holds the total amount of wrong guesses the player has made
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -200,11 +197,6 @@ public class HangmanController : MonoBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public GameObject scoreboardEntry;
|
public GameObject scoreboardEntry;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Accuracy feeback object
|
|
||||||
/// </summary>
|
|
||||||
public Feedback feedback;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The button to go into the game
|
/// The button to go into the game
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -215,8 +207,50 @@ public class HangmanController : MonoBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private String currentsign = "";
|
private String currentsign = "";
|
||||||
|
|
||||||
// Start is called before the first frame update
|
/// <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>
|
||||||
|
public Image feedbackProgressImage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timer to keep track of how long a incorrect sign is performed
|
||||||
|
/// </summary>
|
||||||
|
protected DateTime timer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current predicted sign
|
||||||
|
/// </summary>
|
||||||
|
protected string predictedSign = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs
|
||||||
|
/// </summary>
|
||||||
|
protected string previousIncorrectSign = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start is called before the first frame update
|
||||||
|
/// </summary>
|
||||||
void Start()
|
void Start()
|
||||||
|
{
|
||||||
|
StartController();
|
||||||
|
|
||||||
|
signPredictor.SetModel(ModelIndex.FINGERSPELLING);
|
||||||
|
AddSelfAsListener();
|
||||||
|
}
|
||||||
|
/// <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
|
// Make sure the mode starts at zero
|
||||||
mode = 0;
|
mode = 0;
|
||||||
@@ -240,19 +274,6 @@ public class HangmanController : MonoBehaviour
|
|||||||
user.minigames.Add(progress);
|
user.minigames.Add(progress);
|
||||||
}
|
}
|
||||||
userList.Save();
|
userList.Save();
|
||||||
|
|
||||||
// Hangman always uses fingerspelling
|
|
||||||
feedback.signPredictor.ChangeModel(ModelIndex.FINGERSPELLING);
|
|
||||||
|
|
||||||
// Set calllbacks
|
|
||||||
feedback.getSignCallback = () =>
|
|
||||||
{
|
|
||||||
return "A";
|
|
||||||
};
|
|
||||||
feedback.predictSignCallback = (sign) =>
|
|
||||||
{
|
|
||||||
currentsign = sign;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -281,7 +302,7 @@ public class HangmanController : MonoBehaviour
|
|||||||
DeleteWord();
|
DeleteWord();
|
||||||
DisplayWord(currentWord);
|
DisplayWord(currentWord);
|
||||||
|
|
||||||
replayButton.onClick.AddListener(Start);
|
replayButton.onClick.AddListener(StartController);
|
||||||
// Call to display the first image, corresponding to a clean image.
|
// Call to display the first image, corresponding to a clean image.
|
||||||
ChangeSprite();
|
ChangeSprite();
|
||||||
}
|
}
|
||||||
@@ -352,7 +373,7 @@ public class HangmanController : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (mode == 1)
|
if (mode == 1)
|
||||||
{
|
{
|
||||||
if (currentsign != "")
|
if (currentsign != null && currentsign != "")
|
||||||
{
|
{
|
||||||
char letter = currentsign.ToLower()[0];
|
char letter = currentsign.ToLower()[0];
|
||||||
currentsign = "";
|
currentsign = "";
|
||||||
@@ -393,7 +414,7 @@ public class HangmanController : MonoBehaviour
|
|||||||
// For the first input char given by the user, check if the letter is in the word that needs to be spelled.
|
// For the first input char given by the user, check if the letter is in the word that needs to be spelled.
|
||||||
|
|
||||||
// Check to make sure the inputfield is not empty
|
// Check to make sure the inputfield is not empty
|
||||||
if (currentsign != "")
|
if (currentsign != null && currentsign != "")
|
||||||
{
|
{
|
||||||
char firstLetter = currentsign.ToLower()[0];
|
char firstLetter = currentsign.ToLower()[0];
|
||||||
currentsign = "";
|
currentsign = "";
|
||||||
@@ -543,21 +564,6 @@ public class HangmanController : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Randomly shuffle the list of words
|
|
||||||
/// </summary>
|
|
||||||
private void ShuffleWords()
|
|
||||||
{
|
|
||||||
for (int i = words.Length - 1; i > 0; i--)
|
|
||||||
{
|
|
||||||
// Generate a random index between 0 and i (inclusive)
|
|
||||||
int j = UnityEngine.Random.Range(0, i + 1);
|
|
||||||
|
|
||||||
// Swap the values at indices i and j
|
|
||||||
(words[j], words[i]) = (words[i], words[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update and save the scores
|
/// Update and save the scores
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -731,4 +737,97 @@ public class HangmanController : MonoBehaviour
|
|||||||
rank++;
|
rank++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// The updateFunction that is called when new probabilities become available
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override IEnumerator UpdateFeedback()
|
||||||
|
{
|
||||||
|
// Get current sign
|
||||||
|
string currentSign = "A";
|
||||||
|
// Get the predicted sign
|
||||||
|
if (signPredictor != null && signPredictor.learnableProbabilities != null &&
|
||||||
|
currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign))
|
||||||
|
{
|
||||||
|
float accuracy = signPredictor.learnableProbabilities[currentSign];
|
||||||
|
if (feedbackText != null && feedbackProgressImage != null)
|
||||||
|
{
|
||||||
|
if (accuracy > 0.90)
|
||||||
|
{
|
||||||
|
feedbackText.text = "Goed";
|
||||||
|
feedbackText.color = Color.green;
|
||||||
|
feedbackProgressImage.color = Color.green;
|
||||||
|
}
|
||||||
|
else if (accuracy > 0.80)
|
||||||
|
{
|
||||||
|
feedbackText.text = "Bijna...";
|
||||||
|
Color col = new Color(0xff / 255.0f, 0x66 / 255.0f, 0x00 / 255.0f);
|
||||||
|
feedbackText.color = col;
|
||||||
|
feedbackProgressImage.color = col;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
feedbackText.text = "Detecteren...";
|
||||||
|
feedbackText.color = Color.red;
|
||||||
|
feedbackProgressImage.color = Color.red;
|
||||||
|
}
|
||||||
|
|
||||||
|
float oldValue = feedbackProgress.value;
|
||||||
|
// use an exponential scale
|
||||||
|
float newValue = Mathf.Exp(4 * (accuracy - 1.0f));
|
||||||
|
feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
|
||||||
|
{
|
||||||
|
if (feedbackProgress != null)
|
||||||
|
{
|
||||||
|
feedbackProgress.value = t.CurrentValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether (in)correct sign has high accuracy
|
||||||
|
foreach (var kv in signPredictor.learnableProbabilities)
|
||||||
|
{
|
||||||
|
if (kv.Value > 0.90)
|
||||||
|
{
|
||||||
|
predictedSign = kv.Key;
|
||||||
|
// Correct sign
|
||||||
|
if (predictedSign == currentSign)
|
||||||
|
{
|
||||||
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
CheckEquality(predictedSign);
|
||||||
|
timer = DateTime.Now;
|
||||||
|
predictedSign = null;
|
||||||
|
previousIncorrectSign = null;
|
||||||
|
}
|
||||||
|
// Incorrect sign
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (previousIncorrectSign != predictedSign)
|
||||||
|
{
|
||||||
|
timer = DateTime.Now;
|
||||||
|
previousIncorrectSign = predictedSign;
|
||||||
|
}
|
||||||
|
else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f))
|
||||||
|
{
|
||||||
|
CheckEquality(predictedSign);
|
||||||
|
timer = DateTime.Now;
|
||||||
|
predictedSign = null;
|
||||||
|
previousIncorrectSign = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (feedbackProgress != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
feedbackProgress.value = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private void CheckEquality(string sign)
|
||||||
|
{
|
||||||
|
currentsign = sign;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
using UnityEngine.UI;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class WebCam : MonoBehaviour
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Index of the current camera
|
|
||||||
/// </summary>
|
|
||||||
protected int camdex = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Texture to paste on the display
|
|
||||||
/// </summary>
|
|
||||||
protected WebCamTexture tex;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Display for the video feed
|
|
||||||
/// </summary>
|
|
||||||
public RawImage display;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Setup the webcam correctly
|
|
||||||
/// </summary>
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
WebCamDevice device = WebCamTexture.devices[camdex];
|
|
||||||
tex = new WebCamTexture(device.name);
|
|
||||||
display.texture = tex;
|
|
||||||
|
|
||||||
tex.Play();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Function to toggle between stopping and starting
|
|
||||||
/// </summary>
|
|
||||||
/*
|
|
||||||
public void toggle()
|
|
||||||
{
|
|
||||||
if (tex.isPlaying)
|
|
||||||
{
|
|
||||||
tex.Stop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tex.Play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public void PlayCam()
|
|
||||||
{
|
|
||||||
if (!tex.isPlaying) tex.Play();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopCam()
|
|
||||||
{
|
|
||||||
if (tex.isPlaying) tex.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Swap webcam by cycling through the `WebCamTexture.devices` list
|
|
||||||
/// </summary>
|
|
||||||
public void SwapCam()
|
|
||||||
{
|
|
||||||
if (WebCamTexture.devices.Length > 0)
|
|
||||||
{
|
|
||||||
// Stop the old camera
|
|
||||||
display.texture = null;
|
|
||||||
tex.Stop();
|
|
||||||
tex = null;
|
|
||||||
|
|
||||||
// Find the new camera
|
|
||||||
camdex += 1;
|
|
||||||
camdex %= WebCamTexture.devices.Length;
|
|
||||||
|
|
||||||
// Start the new camera
|
|
||||||
WebCamDevice device = WebCamTexture.devices[camdex];
|
|
||||||
tex = new WebCamTexture(device.name);
|
|
||||||
display.texture = tex;
|
|
||||||
|
|
||||||
tex.Play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Scene changing is implemented here to avoid problems with webcam
|
|
||||||
/// </summary>
|
|
||||||
public void GotoThemeSelection()
|
|
||||||
{
|
|
||||||
display.texture = null;
|
|
||||||
tex.Stop();
|
|
||||||
tex = null;
|
|
||||||
|
|
||||||
SystemController.GetInstance().BackToPreviousScene();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5db51e2552e03de4b9e7e91b5746adbc
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
8
Assets/MediaPipeUnity/Interfaces.meta
Normal file
8
Assets/MediaPipeUnity/Interfaces.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 73c615986873dc246893879daf74c05d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
14
Assets/MediaPipeUnity/Interfaces/Listener.cs
Normal file
14
Assets/MediaPipeUnity/Interfaces/Listener.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
/// <summary>
|
||||||
|
/// Listener interface with an IEnumerator as its processing-function.
|
||||||
|
/// </summary>
|
||||||
|
public interface Listener
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The function that is called by the publisher.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IEnumerator ProcessIncomingCall();
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 44e682a32ee15cc489bf50f3a06f717b
|
guid: e4c1da9896d9ba2449549a016b5fd15e
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "SignPredictorInterfaces",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f55a02e98b01bc849b30d9650ccd8f15
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -9,7 +9,6 @@ GameObject:
|
|||||||
serializedVersion: 6
|
serializedVersion: 6
|
||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 4318122119930585316}
|
- component: {fileID: 4318122119930585316}
|
||||||
- component: {fileID: 4318122119930585317}
|
|
||||||
m_Layer: 5
|
m_Layer: 5
|
||||||
m_Name: Feedback
|
m_Name: Feedback
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
@@ -39,22 +38,6 @@ RectTransform:
|
|||||||
m_AnchoredPosition: {x: 0, y: 200}
|
m_AnchoredPosition: {x: 0, y: 200}
|
||||||
m_SizeDelta: {x: 500, y: 150}
|
m_SizeDelta: {x: 500, y: 150}
|
||||||
m_Pivot: {x: 0.5, y: 0}
|
m_Pivot: {x: 0.5, y: 0}
|
||||||
--- !u!114 &4318122119930585317
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 4318122119930585319}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 44e682a32ee15cc489bf50f3a06f717b, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
feedbackText: {fileID: 4318122120222767928}
|
|
||||||
feedbackProgress: {fileID: 4318122119968934242}
|
|
||||||
feedbackProgressImage: {fileID: 4318122120334233319}
|
|
||||||
signPredictor: {fileID: 0}
|
|
||||||
--- !u!1 &4318122119968934244
|
--- !u!1 &4318122119968934244
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -17,4 +17,4 @@ MonoBehaviour:
|
|||||||
- index: 0
|
- index: 0
|
||||||
model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
||||||
- index: 1
|
- index: 1
|
||||||
model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
model: {fileID: 0}
|
||||||
|
|||||||
40
Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs
Normal file
40
Assets/MediaPipeUnity/Scripts/AbstractFeedback.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using DigitalRuby.Tween;
|
||||||
|
using Mediapipe.Unity.Tutorial;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class to display feedback during a course
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AbstractFeedback : MonoBehaviour, Listener
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference to the sign predictor
|
||||||
|
/// </summary>
|
||||||
|
public SignPredictor signPredictor;
|
||||||
|
/// <summary>
|
||||||
|
/// The function that is called by the publisher on all its listeners
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IEnumerator ProcessIncomingCall()
|
||||||
|
{
|
||||||
|
yield return StartCoroutine(UpdateFeedback());
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// A function to add yourself as listener to the signPredictor you are holding
|
||||||
|
/// </summary>
|
||||||
|
public void AddSelfAsListener()
|
||||||
|
{
|
||||||
|
signPredictor.listeners.Add(this);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// The function that holds the logic to process the new probabilities of the signPredictor
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected abstract IEnumerator UpdateFeedback();
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: a62d2b8bded916443835dc19010b83c1
|
guid: 7b5ac794337a54143a6e3077483d96c9
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
using DigitalRuby.Tween;
|
|
||||||
using Mediapipe.Unity.Tutorial;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class to display feedback during a course
|
|
||||||
/// </summary>
|
|
||||||
public class Feedback : MonoBehaviour
|
|
||||||
{
|
|
||||||
/// <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>
|
|
||||||
public Image feedbackProgressImage;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reference to the sign predictor
|
|
||||||
/// </summary>
|
|
||||||
public SignPredictor signPredictor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Callback for getting the correct sign
|
|
||||||
/// </summary>
|
|
||||||
public Func<string> getSignCallback;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Callback to initiate the next sign
|
|
||||||
/// </summary>
|
|
||||||
public UnityAction<string> predictSignCallback;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Timer to keep track of how long a incorrect sign is performed
|
|
||||||
/// </summary>
|
|
||||||
private DateTime timer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Current predicted sign
|
|
||||||
/// </summary>
|
|
||||||
private string predictedSign = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs
|
|
||||||
/// </summary>
|
|
||||||
private string previousIncorrectSign = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start is called before the first frame update
|
|
||||||
/// </summary>
|
|
||||||
void Start()
|
|
||||||
{
|
|
||||||
// Start the coroutine to update the scale every 200 milliseconds
|
|
||||||
StartCoroutine(UpdateFeedback());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// UpdateScale updates the progress bar every 200ms, updated the feedback text, and progress bar color
|
|
||||||
/// If a high enough accuracy is detected, it will go to the next sign
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
IEnumerator UpdateFeedback()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (getSignCallback != null && predictSignCallback != null)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Get current sign
|
|
||||||
string currentSign = getSignCallback();
|
|
||||||
// Get the predicted sign
|
|
||||||
if (signPredictor != null && signPredictor.learnableProbabilities != null &&
|
|
||||||
currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign))
|
|
||||||
{
|
|
||||||
float accuracy = signPredictor.learnableProbabilities[currentSign];
|
|
||||||
if (feedbackText != null && feedbackProgressImage != null){
|
|
||||||
if (accuracy > 0.98)
|
|
||||||
{
|
|
||||||
// TODO: fix emojis
|
|
||||||
feedbackText.text = "✨ Perfect ✨";
|
|
||||||
Color col = new Color(0xff / 255.0f, 0xcc / 255.0f, 0x00 / 255.0f);
|
|
||||||
feedbackText.color = col;
|
|
||||||
feedbackProgressImage.color = col;
|
|
||||||
}
|
|
||||||
else if (accuracy > 0.95)
|
|
||||||
{
|
|
||||||
feedbackText.text = "Super!";
|
|
||||||
Color col = new Color(0x00 / 255.0f, 0xff / 255.0f, 0xcc / 255.0f);
|
|
||||||
feedbackText.color = col;
|
|
||||||
feedbackProgressImage.color = col;
|
|
||||||
}
|
|
||||||
else if (accuracy > 0.90)
|
|
||||||
{
|
|
||||||
feedbackText.text = "Goed";
|
|
||||||
feedbackText.color = Color.green;
|
|
||||||
feedbackProgressImage.color = Color.green;
|
|
||||||
}
|
|
||||||
else if (accuracy > 0.80)
|
|
||||||
{
|
|
||||||
feedbackText.text = "Bijna...";
|
|
||||||
Color col = new Color(0xff / 255.0f, 0x66 / 255.0f, 0x00 / 255.0f);
|
|
||||||
feedbackText.color = col;
|
|
||||||
feedbackProgressImage.color = col;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
feedbackText.text = "Detecteren...";
|
|
||||||
feedbackText.color = Color.red;
|
|
||||||
feedbackProgressImage.color = Color.red;
|
|
||||||
}
|
|
||||||
|
|
||||||
float oldValue = feedbackProgress.value;
|
|
||||||
// use an exponential scale
|
|
||||||
float newValue = Mathf.Exp(4 * (accuracy - 1.0f));
|
|
||||||
feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
|
|
||||||
{
|
|
||||||
if (feedbackProgress != null)
|
|
||||||
{
|
|
||||||
feedbackProgress.value = t.CurrentValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether (in)correct sign has high accuracy
|
|
||||||
foreach (var kv in signPredictor.learnableProbabilities)
|
|
||||||
{
|
|
||||||
if (kv.Value > 0.90)
|
|
||||||
{
|
|
||||||
predictedSign = kv.Key;
|
|
||||||
// Correct sign
|
|
||||||
if (predictedSign == currentSign)
|
|
||||||
{
|
|
||||||
yield return new WaitForSeconds(1.0f);
|
|
||||||
predictSignCallback(predictedSign);
|
|
||||||
timer = DateTime.Now;
|
|
||||||
predictedSign = null;
|
|
||||||
previousIncorrectSign = null;
|
|
||||||
}
|
|
||||||
// Incorrect sign
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (previousIncorrectSign != predictedSign)
|
|
||||||
{
|
|
||||||
timer = DateTime.Now;
|
|
||||||
previousIncorrectSign = predictedSign;
|
|
||||||
}
|
|
||||||
else if (DateTime.Now - timer > TimeSpan.FromSeconds(2.0f))
|
|
||||||
{
|
|
||||||
predictSignCallback(predictedSign);
|
|
||||||
timer = DateTime.Now;
|
|
||||||
predictedSign = null;
|
|
||||||
previousIncorrectSign = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(feedbackProgress != null)
|
|
||||||
{
|
|
||||||
|
|
||||||
feedbackProgress.value = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for 200 milliseconds before updating the scale again
|
|
||||||
yield return new WaitForSeconds(0.2f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
"GUID:04c4d86a70aa56c55a78c61f1ab1a56d",
|
"GUID:04c4d86a70aa56c55a78c61f1ab1a56d",
|
||||||
"GUID:edc93f477bb73a743a97d6882ed330b3",
|
"GUID:edc93f477bb73a743a97d6882ed330b3",
|
||||||
"GUID:58e104b97fb3752438ada2902a36dcbf",
|
"GUID:58e104b97fb3752438ada2902a36dcbf",
|
||||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
|
||||||
|
"GUID:f55a02e98b01bc849b30d9650ccd8f15"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ namespace Mediapipe.Unity.Tutorial
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Tensor inputTensor;
|
private Tensor inputTensor;
|
||||||
|
|
||||||
|
public List<Listener> listeners = new List<Listener>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Google Mediapipe setup & run
|
/// Google Mediapipe setup & run
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -159,6 +161,7 @@ namespace Mediapipe.Unity.Tutorial
|
|||||||
|
|
||||||
webcamTexture.Play();
|
webcamTexture.Play();
|
||||||
|
|
||||||
|
|
||||||
yield return new WaitUntil(() => webcamTexture.width > 16);
|
yield return new WaitUntil(() => webcamTexture.width > 16);
|
||||||
|
|
||||||
// Set webcam aspect ratio
|
// Set webcam aspect ratio
|
||||||
@@ -167,63 +170,63 @@ namespace Mediapipe.Unity.Tutorial
|
|||||||
float webcamAspect = (float)webcamTexture.width / (float)webcamTexture.height;
|
float webcamAspect = (float)webcamTexture.width / (float)webcamTexture.height;
|
||||||
screen.rectTransform.sizeDelta = new Vector2(screen.rectTransform.sizeDelta.y * webcamAspect, (screen.rectTransform.sizeDelta.y));
|
screen.rectTransform.sizeDelta = new Vector2(screen.rectTransform.sizeDelta.y * webcamAspect, (screen.rectTransform.sizeDelta.y));
|
||||||
screen.texture = webcamTexture;
|
screen.texture = webcamTexture;
|
||||||
if(screen2 != null)
|
if (screen2 != null)
|
||||||
{
|
{
|
||||||
screen2.rectTransform.sizeDelta = new Vector2(screen2.rectTransform.sizeDelta.y * webcamAspect, (screen2.rectTransform.sizeDelta.y));
|
screen2.rectTransform.sizeDelta = new Vector2(screen2.rectTransform.sizeDelta.y * webcamAspect, (screen2.rectTransform.sizeDelta.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this method is kinda meh you should use
|
if (modelList.GetCurrentModel() != null)
|
||||||
inputTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
|
||||||
pixelData = new Color32[width * height];
|
|
||||||
|
|
||||||
if (!resourceManagerIsInitialized)
|
|
||||||
{
|
{
|
||||||
resourceManager = new StreamingAssetsResourceManager();
|
// TODO this method is kinda meh you should use
|
||||||
yield return resourceManager.PrepareAssetAsync("pose_detection.bytes");
|
inputTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||||
yield return resourceManager.PrepareAssetAsync("pose_landmark_full.bytes");
|
pixelData = new Color32[width * height];
|
||||||
yield return resourceManager.PrepareAssetAsync("face_landmark.bytes");
|
|
||||||
yield return resourceManager.PrepareAssetAsync("hand_landmark_full.bytes");
|
if (!resourceManagerIsInitialized)
|
||||||
yield return resourceManager.PrepareAssetAsync("face_detection_short_range.bytes");
|
{
|
||||||
yield return resourceManager.PrepareAssetAsync("hand_recrop.bytes");
|
resourceManager = new StreamingAssetsResourceManager();
|
||||||
yield return resourceManager.PrepareAssetAsync("handedness.txt");
|
yield return resourceManager.PrepareAssetAsync("pose_detection.bytes");
|
||||||
resourceManagerIsInitialized = true;
|
yield return resourceManager.PrepareAssetAsync("pose_landmark_full.bytes");
|
||||||
|
yield return resourceManager.PrepareAssetAsync("face_landmark.bytes");
|
||||||
|
yield return resourceManager.PrepareAssetAsync("hand_landmark_full.bytes");
|
||||||
|
yield return resourceManager.PrepareAssetAsync("face_detection_short_range.bytes");
|
||||||
|
yield return resourceManager.PrepareAssetAsync("hand_recrop.bytes");
|
||||||
|
yield return resourceManager.PrepareAssetAsync("handedness.txt");
|
||||||
|
resourceManagerIsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopwatch = new Stopwatch();
|
||||||
|
|
||||||
|
// Setting up the graph
|
||||||
|
graph = new CalculatorGraph(configAsset.text);
|
||||||
|
|
||||||
|
posestream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(graph, "pose_landmarks", "pose_landmarks_presence");
|
||||||
|
leftstream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(graph, "left_hand_landmarks", "left_hand_landmarks_presence");
|
||||||
|
rightstream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(graph, "right_hand_landmarks", "right_hand_landmarks_presence");
|
||||||
|
|
||||||
|
posestream.StartPolling().AssertOk();
|
||||||
|
leftstream.StartPolling().AssertOk();
|
||||||
|
rightstream.StartPolling().AssertOk();
|
||||||
|
|
||||||
|
graph.StartRun().AssertOk();
|
||||||
|
stopwatch.Start();
|
||||||
|
|
||||||
|
|
||||||
|
keypointManager = new KeypointManager(modelInfoFile);
|
||||||
|
// check if model exists at path
|
||||||
|
//var model = ModelLoader.Load(Resources.Load<NNModel>("Models/Fingerspelling/model_A-L"));
|
||||||
|
worker = modelList.GetCurrentModel().CreateWorker();
|
||||||
|
|
||||||
|
StartCoroutine(SignRecognitionCoroutine());
|
||||||
|
StartCoroutine(MediapipeCoroutine());
|
||||||
}
|
}
|
||||||
|
|
||||||
stopwatch = new Stopwatch();
|
|
||||||
|
|
||||||
// Setting up the graph
|
|
||||||
graph = new CalculatorGraph(configAsset.text);
|
|
||||||
|
|
||||||
posestream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(graph, "pose_landmarks", "pose_landmarks_presence");
|
|
||||||
leftstream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(graph, "left_hand_landmarks", "left_hand_landmarks_presence");
|
|
||||||
rightstream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(graph, "right_hand_landmarks", "right_hand_landmarks_presence");
|
|
||||||
|
|
||||||
posestream.StartPolling().AssertOk();
|
|
||||||
leftstream.StartPolling().AssertOk();
|
|
||||||
rightstream.StartPolling().AssertOk();
|
|
||||||
|
|
||||||
graph.StartRun().AssertOk();
|
|
||||||
stopwatch.Start();
|
|
||||||
|
|
||||||
|
|
||||||
keypointManager = new KeypointManager(modelInfoFile);
|
|
||||||
|
|
||||||
// check if model exists at path
|
|
||||||
//var model = ModelLoader.Load(Resources.Load<NNModel>("Models/Fingerspelling/model_A-L"));
|
|
||||||
worker = modelList.GetCurrentModel().CreateWorker();
|
|
||||||
|
|
||||||
StartCoroutine(SignRecognitionCoroutine());
|
|
||||||
StartCoroutine(MediapipeCoroutine());
|
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
public void ChangeModel(ModelIndex index)
|
/// Called at the start of course/Minigame, will set the model before the start of SIgnPredictor is called.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the model to be used</param>
|
||||||
|
public void SetModel(ModelIndex index)
|
||||||
{
|
{
|
||||||
this.modelList.SetCurrentModel(index);
|
this.modelList.SetCurrentModel(index);
|
||||||
// If a worker already existed, we throw it out
|
|
||||||
worker?.Dispose();
|
|
||||||
|
|
||||||
// Add a new worker for the new model
|
|
||||||
worker = modelList.GetCurrentModel().CreateWorker();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -325,6 +328,10 @@ namespace Mediapipe.Unity.Tutorial
|
|||||||
learnableProbabilities.Add(((char)(i + 65)).ToString(), softmaxedOutput2[i]);
|
learnableProbabilities.Add(((char)(i + 65)).ToString(), softmaxedOutput2[i]);
|
||||||
}
|
}
|
||||||
//Debug.Log($"prob = [{learnableProbabilities.Aggregate(" ", (t, kv) => $"{t}{kv.Key}:{kv.Value} ")}]");
|
//Debug.Log($"prob = [{learnableProbabilities.Aggregate(" ", (t, kv) => $"{t}{kv.Key}:{kv.Value} ")}]");
|
||||||
|
foreach(Listener listener in listeners)
|
||||||
|
{
|
||||||
|
yield return listener.ProcessIncomingCall();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"InterfacesScripts",
|
"InterfacesScripts",
|
||||||
"Unity.TextMeshPro",
|
"Unity.TextMeshPro",
|
||||||
"SpellingBeeScripts",
|
"SpellingBeeScripts",
|
||||||
"AccountsScripts"
|
"AccountsScripts",
|
||||||
|
"SignPredictor"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|||||||
@@ -1741,13 +1741,35 @@ RectTransform:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
--- !u!114 &967164045 stripped
|
--- !u!114 &967164045 stripped
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_CorrespondingSourceObject: {fileID: 4318122119930585317, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
m_CorrespondingSourceObject: {fileID: 4318122120334233319, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
m_PrefabInstance: {fileID: 967164043}
|
m_PrefabInstance: {fileID: 967164043}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 0}
|
m_GameObject: {fileID: 0}
|
||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 11500000, guid: 44e682a32ee15cc489bf50f3a06f717b, type: 3}
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
--- !u!114 &967164046 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 4318122119968934242, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 967164043}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 67db9e8f0e2ae9c40bc1e2b64352a6b4, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
--- !u!114 &967164047 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 4318122120222767928, guid: 7c71c65ecb5fe0449a8b0d178987f016, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 967164043}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
--- !u!1 &978093274
|
--- !u!1 &978093274
|
||||||
@@ -3584,6 +3606,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 44fbed5ae228de39b9f727def7578d06, type: 3}
|
m_Script: {fileID: 11500000, guid: 44fbed5ae228de39b9f727def7578d06, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
signPredictor: {fileID: 1592592444}
|
||||||
themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2}
|
themeList: {fileID: 11400000, guid: a247e2ce790f0f746a3bc521e6ab7d58, type: 2}
|
||||||
userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2}
|
userList: {fileID: 11400000, guid: 072bec636a40f7e4e93b0ac624a3bda2, type: 2}
|
||||||
minigame: {fileID: 11400000, guid: 8a087d241d652634eb4f6352267ea7dc, type: 2}
|
minigame: {fileID: 11400000, guid: 8a087d241d652634eb4f6352267ea7dc, type: 2}
|
||||||
@@ -3594,8 +3617,10 @@ MonoBehaviour:
|
|||||||
timerText: {fileID: 1843239267}
|
timerText: {fileID: 1843239267}
|
||||||
bonusTimeText: {fileID: 1812475780}
|
bonusTimeText: {fileID: 1812475780}
|
||||||
Scoreboard: {fileID: 862382568}
|
Scoreboard: {fileID: 862382568}
|
||||||
feedback: {fileID: 967164045}
|
|
||||||
gameEndedPanel: {fileID: 757133117}
|
gameEndedPanel: {fileID: 757133117}
|
||||||
|
feedbackText: {fileID: 967164047}
|
||||||
|
feedbackProgress: {fileID: 967164046}
|
||||||
|
feedbackProgressImage: {fileID: 967164045}
|
||||||
--- !u!1 &1499197558
|
--- !u!1 &1499197558
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -3957,7 +3982,6 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2}
|
modelList: {fileID: 11400000, guid: 39516e4e6e56f0f4f80647d9c4d8034c, type: 2}
|
||||||
model: {fileID: 5022602860645237092, guid: e6d85df707405ad4f97c23b07227ee99, type: 3}
|
|
||||||
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
|
modelInfoFile: {fileID: 4900000, guid: fb8b51022bdcd654a9f29c054832a1b5, type: 3}
|
||||||
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
||||||
screen: {fileID: 1743003084}
|
screen: {fileID: 1743003084}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ using System.Linq;
|
|||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using DigitalRuby.Tween;
|
||||||
|
|
||||||
public partial class SpellingBeeController : MonoBehaviour
|
public partial class SpellingBeeController : AbstractFeedback
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All of the words that can be used in this session
|
/// All of the words that can be used in this session
|
||||||
@@ -136,20 +137,55 @@ public partial class SpellingBeeController : MonoBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Transform Scoreboard;
|
public Transform Scoreboard;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Accuracy feeback object
|
|
||||||
/// </summary>
|
|
||||||
public Feedback feedback;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reference to the gameEnded panel, so we can update its display
|
/// Reference to the gameEnded panel, so we can update its display
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GameObject gameEndedPanel;
|
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>
|
||||||
|
public Image feedbackProgressImage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timer to keep track of how long a incorrect sign is performed
|
||||||
|
/// </summary>
|
||||||
|
protected DateTime timer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current predicted sign
|
||||||
|
/// </summary>
|
||||||
|
protected string predictedSign = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Previous incorrect sign, so we can keep track whether the user is wrong or the user is still changing signs
|
||||||
|
/// </summary>
|
||||||
|
protected string previousIncorrectSign = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start is called before the first frame update
|
/// Start is called before the first frame update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Start()
|
public void Start()
|
||||||
|
{
|
||||||
|
StartController();
|
||||||
|
|
||||||
|
signPredictor.SetModel(currentTheme.modelIndex);
|
||||||
|
AddSelfAsListener();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Is called at the start of the scene AND when the game is replayed
|
||||||
|
/// </summary>
|
||||||
|
public void StartController()
|
||||||
{
|
{
|
||||||
correctLetters = 0;
|
correctLetters = 0;
|
||||||
incorrectLetters = 0;
|
incorrectLetters = 0;
|
||||||
@@ -182,29 +218,10 @@ public partial class SpellingBeeController : MonoBehaviour
|
|||||||
userList.Save();
|
userList.Save();
|
||||||
|
|
||||||
currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
|
currentTheme = minigame.themeList.themes[minigame.themeList.currentThemeIndex];
|
||||||
feedback.signPredictor.ChangeModel(currentTheme.modelIndex);
|
//feedback.signPredictor.ChangeModel(currentTheme.modelIndex);
|
||||||
words.AddRange(currentTheme.learnables);
|
words.AddRange(currentTheme.learnables);
|
||||||
ShuffleWords();
|
ShuffleWords();
|
||||||
NextWord();
|
NextWord();
|
||||||
|
|
||||||
// Set calllbacks
|
|
||||||
feedback.getSignCallback = () =>
|
|
||||||
{
|
|
||||||
if (letterIndex < currentWord.Length)
|
|
||||||
{
|
|
||||||
return currentWord[letterIndex].ToString().ToUpper();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
feedback.predictSignCallback = (sign) =>
|
|
||||||
{
|
|
||||||
bool successful = sign.ToUpper() == currentWord[letterIndex].ToString().ToUpper();
|
|
||||||
if (successful)
|
|
||||||
{
|
|
||||||
AddSeconds(secondsPerLetter);
|
|
||||||
}
|
|
||||||
NextLetter(successful);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -453,4 +470,116 @@ public partial class SpellingBeeController : MonoBehaviour
|
|||||||
{
|
{
|
||||||
yield return new WaitForSecondsRealtime(2);
|
yield return new WaitForSecondsRealtime(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The updateFunction that is called when new probabilities become available
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override IEnumerator UpdateFeedback()
|
||||||
|
{
|
||||||
|
// Get current sign
|
||||||
|
string currentSign = GetSign();
|
||||||
|
// Get the predicted sign
|
||||||
|
if (signPredictor != null && signPredictor.learnableProbabilities != null &&
|
||||||
|
currentSign != null && signPredictor.learnableProbabilities.ContainsKey(currentSign))
|
||||||
|
{
|
||||||
|
float accuracy = signPredictor.learnableProbabilities[currentSign];
|
||||||
|
if (feedbackText != null && feedbackProgressImage != null)
|
||||||
|
{
|
||||||
|
if (accuracy > 0.90)
|
||||||
|
{
|
||||||
|
feedbackText.text = "Goed";
|
||||||
|
feedbackText.color = Color.green;
|
||||||
|
feedbackProgressImage.color = Color.green;
|
||||||
|
}
|
||||||
|
else if (accuracy > 0.80)
|
||||||
|
{
|
||||||
|
feedbackText.text = "Bijna...";
|
||||||
|
Color col = new Color(0xff / 255.0f, 0x66 / 255.0f, 0x00 / 255.0f);
|
||||||
|
feedbackText.color = col;
|
||||||
|
feedbackProgressImage.color = col;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
feedbackText.text = "Detecteren...";
|
||||||
|
feedbackText.color = Color.red;
|
||||||
|
feedbackProgressImage.color = Color.red;
|
||||||
|
}
|
||||||
|
|
||||||
|
float oldValue = feedbackProgress.value;
|
||||||
|
// use an exponential scale
|
||||||
|
float newValue = Mathf.Exp(4 * (accuracy - 1.0f));
|
||||||
|
feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) =>
|
||||||
|
{
|
||||||
|
if (feedbackProgress != null)
|
||||||
|
{
|
||||||
|
feedbackProgress.value = t.CurrentValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether (in)correct sign has high accuracy
|
||||||
|
foreach (var kv in signPredictor.learnableProbabilities)
|
||||||
|
{
|
||||||
|
if (kv.Value > 0.90)
|
||||||
|
{
|
||||||
|
predictedSign = kv.Key;
|
||||||
|
// Correct sign
|
||||||
|
if (predictedSign == currentSign)
|
||||||
|
{
|
||||||
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
predictSign(predictedSign);
|
||||||
|
timer = DateTime.Now;
|
||||||
|
predictedSign = null;
|
||||||
|
previousIncorrectSign = null;
|
||||||
|
}
|
||||||
|
// Incorrect sign
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (feedbackProgress != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
feedbackProgress.value = 0.0f;
|
||||||
|
}
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Function to get the current letter that needs to be signed
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>the current letter that needs to be signed</returns>
|
||||||
|
public string GetSign(){
|
||||||
|
if (letterIndex<currentWord.Length){
|
||||||
|
return currentWord[letterIndex].ToString().ToUpper();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Function to confirm your prediction and check if it is correct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sign"></param>
|
||||||
|
public void predictSign(string sign) {
|
||||||
|
bool successful = sign.ToUpper() == currentWord[letterIndex].ToString().ToUpper();
|
||||||
|
if (successful)
|
||||||
|
{
|
||||||
|
AddSeconds(secondsPerLetter);
|
||||||
|
}
|
||||||
|
NextLetter(successful);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,21 +3,7 @@ guid: 44fbed5ae228de39b9f727def7578d06
|
|||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences:
|
defaultReferences: []
|
||||||
- input: {instanceID: 0}
|
|
||||||
- endText: {instanceID: 0}
|
|
||||||
- correctWordsText: {instanceID: 0}
|
|
||||||
- correctLettersText: {instanceID: 0}
|
|
||||||
- gameEndedPanel: {instanceID: 0}
|
|
||||||
- replayButton: {instanceID: 0}
|
|
||||||
- userList: {instanceID: 0}
|
|
||||||
- minigame: {instanceID: 0}
|
|
||||||
- letterPrefab: {instanceID: 0}
|
|
||||||
- letterContainer: {instanceID: 0}
|
|
||||||
- wordImage: {instanceID: 0}
|
|
||||||
- timerText: {instanceID: 0}
|
|
||||||
- Scoreboard: {instanceID: 0}
|
|
||||||
- scoreboardEntry: {fileID: 9154151134820372555, guid: d4a3a228b08d61847acc6da35b44e52c, type: 3}
|
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {instanceID: 0}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
"GUID:1631ed2680c61245b8211d943c1639a8",
|
"GUID:1631ed2680c61245b8211d943c1639a8",
|
||||||
"GUID:3444c67d5a3a93e5a95a48906078c372",
|
"GUID:3444c67d5a3a93e5a95a48906078c372",
|
||||||
"GUID:d0b6b39a21908f94fbbd9f2c196a9725",
|
"GUID:d0b6b39a21908f94fbbd9f2c196a9725",
|
||||||
"GUID:5c2b5ba89f9e74e418232e154bc5cc7a",
|
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25",
|
||||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
"GUID:58e104b97fb3752438ada2902a36dcbf"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|||||||
Reference in New Issue
Block a user