Files
unity-application/Assets/Courses/Scripts/PanelMultipleChoice.cs
2023-05-14 20:18:29 +00:00

223 lines
6.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
/// <summary>
/// Class to handle panel with multiple choice options
/// </summary>
public class PanelMultipleChoice : MonoBehaviour
{
/// <summary>
/// Reference to the webcam screen
/// </summary>
public RawImage webcamScreen;
/// <summary>
/// Video 'play' sprite
/// </summary>
public Sprite playSprite;
/// <summary>
/// Video 'pause' sprite
/// </summary>
public Sprite pauseSprite;
/// <summary>
/// Reference to its course controller to be able to go to call NextSignMultipleChoice to go to the next panel
/// </summary>
public CoursesController courseController;
/// <summary>
/// Reference to instructional video player
/// </summary>
public VideoPlayer videoPlayer;
/// <summary>
/// Refrence to the video play/pause button
/// </summary>
public Image playButton;
/// <summary>
/// Reference to the image for displaying the current words sprite
/// </summary>
public Transform optionContainer;
/// <summary>
/// Reference to the image for displaying the current words sprite, for a fingerspelling courses
/// </summary>
public Transform optionFingerspellingContainer;
/// <summary>
/// Reference to the option prefab
/// </summary>
public GameObject optionPrefab;
/// <summary>
/// Reference to the option prefab, for a fingerspelling course
/// </summary>
public GameObject optionFingerspellingPrefab;
/// <summary>
/// Reference to the saved progress
/// </summary>
public PersistentDataController.SavedCourseProgress progress;
/// <summary>
/// The current sign that will be displayed
/// </summary>
private Learnable currentSign;
/// <summary>
/// Reference to all signs in this course
/// </summary>
public List<Learnable> signs;
/// <summary>
/// Index of the current sign
/// </summary>
public int currentSignIndex;
/// <summary>
/// Boolean used to check whether the current course is a fingerspelling course
/// </summary>
public bool isFingerSpelling;
/// <summary>
/// Boolean used to check whether the user has already answered the question
/// </summary>
private bool hasAnswered = false;
/// <summary>
/// Get a list of wrongs answers
/// </summary>
/// <param name="notThisIndex">The index of the correct sign</param>
/// <returns></returns>
public List<Learnable> GetWrongOptions(int notThisIndex)
{
var test = progress.learnables.FindAll((l) => l.index != notThisIndex && l.inUse);
for (int i = test.Count - 1; i > 0; i--)
{
// Generate a random index between 0 and i (inclusive)
int j = UnityEngine.Random.Range(0, i + 1);
// Swap the values at indices i and j
(test[j], test[i]) = (test[i], test[j]);
}
List<Learnable> randomSigns = new List<Learnable>();
foreach (var sign in test.Take(3))
{
randomSigns.Add(signs[sign.index]);
}
return randomSigns;
}
/// <summary>
/// Update the display of this panel
/// </summary>
public void Display()
{
currentSign = signs[currentSignIndex];
videoPlayer.aspectRatio = VideoAspectRatio.FitInside;
videoPlayer.clip = currentSign.clip;
videoPlayer.Play();
// Gets three random selected signs from the list signs which are not equal to currentSign
List<Learnable> allOptions = GetWrongOptions(currentSignIndex);
// Add the correct sign at a random position in the list of all options
int randomIndex = UnityEngine.Random.Range(0, allOptions.Count + 1);
allOptions.Insert(randomIndex, currentSign);
var prefab = isFingerSpelling ? optionFingerspellingPrefab : optionPrefab;
var container = isFingerSpelling ? optionFingerspellingContainer : optionContainer;
foreach (Learnable option in allOptions)
{
GameObject multipleChoiceOption = GameObject.Instantiate(prefab, container);
if (!isFingerSpelling)
multipleChoiceOption.transform.Find("TextOption").GetComponent<TMP_Text>().text = option.name;
multipleChoiceOption.transform.Find("ImageOption").GetComponent<Image>().sprite = option.image;
Button button = multipleChoiceOption.GetComponent<Button>();
button.onClick.AddListener(() =>
{
if (!hasAnswered)
{
courseController.NextSignMultipleChoice(currentSign.name, option.name);
ShowAnswers(option.name);
hasAnswered = true;
}
});
}
}
/// <summary>
/// Show the asnwers
/// </summary>
/// <param name="answerName">The name of the clicked sign</param>
public void ShowAnswers(string answerName)
{
if (answerName == currentSign.name)
{
courseController.courseTitle.text = "Correct!";
}
else
{
courseController.courseTitle.text = "Spijtig, fout";
}
var container = isFingerSpelling ? optionFingerspellingContainer : optionContainer;
for (int i = 0; i < container.childCount; i++)
{
// Get the i-th child object
Transform childTransform = container.GetChild(i);
// Change the background color of the Button
Color col = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f);
if (childTransform.Find("ImageOption").GetComponent<Image>().sprite == currentSign.image)
{
col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f);
}
childTransform.GetComponent<Image>().color = col;
}
StartCoroutine(GoToNextScreen());
}
/// <summary>
/// Wait and go to the next sign
/// </summary>
/// <returns></returns>
private IEnumerator GoToNextScreen()
{
// Wait for 5 seconds
yield return new WaitForSeconds(1.5f);
courseController.NextSign();
}
/// <summary>
/// This function is called when the pause-button is pressed on the video.
/// It switches between playing and pausing the video.
/// It then makes the button invisible when the video is playing, or visible when it's paused.
/// </summary>
public void TogglePlayPause()
{
if (!videoPlayer.isPlaying)
{
// Play video and switch sprite of button
playButton.sprite = pauseSprite;
videoPlayer.Play();
}
else
{
// Pause video and and switch sprite of button
playButton.sprite = playSprite;
videoPlayer.Pause();
}
}
}