Files
unity-application/Assets/Courses/Scripts/TemplateCourse.cs
Helena Van Breugel a19d89db03 Resolve WES-80 "Data"
2023-03-18 22:32:36 +00:00

349 lines
10 KiB
C#

using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
/// <summary>
/// TemplateCourse scene manager
/// </summary>
public class TemplateCourse : MonoBehaviour
{
/// <summary>
/// Index to indicate which camera is being used
/// </summary>
private int camdex = 0;
/// <summary>
/// This texture is used as an intermidiary between the camera output and the display image
/// </summary>
private WebCamTexture tex;
/// <summary>
/// Reference to the RawImage that will display the video
/// </summary>
public RawImage webcamDisplay;
/// <summary>
/// Reference to the button that is currently used to test the feedback-display
/// </summary>
public Button feedback;
/// <summary>
/// This is a reference to the textfield that holds the part of the feedback-window that will change: bad/good/excellent
/// </summary>
public TMP_Text dynamic;
/// <summary>
/// Reference to instructional video player
/// </summary>
public VideoPlayer player;
/// <summary>
/// Reference to pause button
/// </summary>
public Button button;
/// <summary>
/// Reference to sprite for the pause button
/// </summary>
public Sprite pauseSprite;
/// <summary>
/// Reference to the image for displaying the current words sprite
/// </summary>
public Image wordImage;
/// <summary>
/// Reference to the text object for displaying the current word
/// </summary>
public TMP_Text title;
/// <summary>
/// Reference to user list to get current user
/// </summary>
public UserList userList;
/// <summary>
/// The current user
/// </summary>
private User user;
/// <summary>
/// Current user progress for this course
/// </summary>
private Progress progress = null;
/// <summary>
/// ScriptableObject with list of all courses
/// </summary>
public CourseList courselist;
/// <summary>
/// Reference to Course ScriptableObject
/// </summary>
private Course course;
/// <summary>
/// Index of the current word/letter in the course.learnables list
/// </summary>
private int currentWordIndex = 0;
/// <summary>
/// This holds the amount of words in the course
/// </summary>
private int maxWords;
/// <summary>
/// Number of correct words so far
/// (can be modified to a list or something like that to give better feedback)
/// </summary>
private int correctWords = 0;
/// <summary>
/// The "finished" screen
/// </summary>
public GameObject ResultPanel;
/// <summary>
/// Button to go back to courses list
/// </summary>
public Button CoursesButton;
/// <summary>
/// DateTime containint the start moment
/// </summary>
private DateTime startMoment;
/// <summary>
/// Reference to the timeSpent UI
/// </summary>
public TMP_Text timeSpent;
/// <summary>
/// This function is called when the script is initialised.
/// It inactivatis the popup, finds a webcam to use and links it via the WebcamTexture to the display RawImage.
/// It takes the correct course from the courselist, using the courseIndex.
/// 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.
/// </summary>
void Awake()
{
// Setting up Webcam
// feedbackPopup.SetActive(false);
//if (WebCamTexture.devices.Length > 0)
//{
// WebCamDevice device = WebCamTexture.devices[camdex];
// tex = new WebCamTexture(device.name);
// webcamDisplay.texture = tex;
// tex.Play();
//}
// Setting up course
course = courselist.courses[courselist.currentCourseIndex];
maxWords = course.theme.learnables.Count;
// Create entry in current user for keeping track of progress
user = userList.GetCurrentUser();
progress = user.GetCourseProgress(course.index);
if (progress == null)
{
progress = new Progress();
progress.AddOrUpdate<CourseIndex>("courseIndex", course.index);
progress.AddOrUpdate<float>("courseProgress", -1.0f);
user.courses.Add(progress);
}
userList.Save();
// Force the videoplayer to add bars to preserve aspect ratio
player.aspectRatio = VideoAspectRatio.FitInside;
// Setup UI
button.image.sprite = pauseSprite;
title.text = course.name;
NextVideo();
NextImage();
// Hide the result panel
ResultPanel.SetActive(false);
// Set the startTime
startMoment = DateTime.Now;
}
/// <summary>
/// This function uses the word_i integer to grab the correct video from the course.learnabels.
/// When it has this video, it will load it into the videoplayer and set it to start.
/// </summary>
private void NextVideo()
{
player.clip = course.theme.learnables[currentWordIndex].clip;
// This loads first frame, so that it can be used as a sort-of preview for the video
player.Play();
// As the video will start playiing -> hide button
Color col = button.image.color;
col.a = 0;
button.image.color = col;
}
/// <summary>
/// This function uses the word_i integer to grab the correct image from the course.learnabels.
/// Then it simply loads it into wordImage so that it can be displayed.
/// </summary>
private void NextImage()
{
wordImage.sprite = course.theme.learnables[currentWordIndex].image;
}
/// <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 Pause()
{
if (!player.isPlaying)
{
// Play video and hide button
player.Play();
Color col = button.image.color;
col.a = 0;
button.image.color = col;
}
else
{
// Pause video and show button
player.Pause();
Color col = button.image.color;
col.a = 255;
button.image.color = col;
}
}
/// <summary>
/// This function is called when the next-sign button is pressed.
/// It increased the wordindex and fetches new videos/images if index<max, because then the coure is not fincished yet.
/// If the maximum is reached, finishcourse is called to save the "finished" progress to the user.
/// </summary>
public void NextSign()
{
// If the currentindex >= maxwords, it indicated that the course is already finished, running the next code is the meaningless.
if (currentWordIndex >= maxWords) { return; }
// Goto the next word/letter
currentWordIndex++;
// TODO: fix correct word count
correctWords++;
progress.AddOrUpdate<float>("courseProgress", (float)correctWords / (float)maxWords);
userList.Save();
// Update UI if course is not finished yet
if (currentWordIndex < maxWords)
{
NextVideo();
NextImage();
}
// Finish course and record progress
else
{
FinishCourse();
}
}
/// <summary>
/// finishcourse is called to save the "finished" progress to the user.
/// </summary>
public void FinishCourse()
{
// Show the "finished" screen
ResultPanel.SetActive(true);
// Set the total time spent UI
TimeSpan time = DateTime.Now - startMoment;
timeSpent.text = time.ToString(@"hh\:mm\:ss");
// Link button
CoursesButton.onClick.AddListener(() => { SystemController.GetInstance().BackToPreviousScene(); });
progress.AddOrUpdate<float>("courseProgress", 1f);
userList.Save();
}
/// <summary>
/// So long as there are cameras to use, you swap the camera you are using to another in the list.
/// </summary>
public void SwapCam()
{
if (WebCamTexture.devices.Length > 0)
{
// Stop the old camera
// If there was no camera playing before, then you dont have to reset the texture, as it wasn't assigned in the first place.
if (tex.isPlaying)
{
webcamDisplay.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);
webcamDisplay.texture = tex;
tex.Play();
}
}
/// <summary>
/// The normal sceneChanger cannot be used here since the camera also needs to be stopped.
/// This extra functionality is implemented in this function
/// </summary>
/// <param name="sceneName"> The path for the scene you want to travel to, assuming root-directory is Assets</param>
public void Back()
{
//webcamDisplay.texture = null;
//tex.Stop();
//tex = null;
SystemController.GetInstance().BackToPreviousScene();
}
/// <summary>
/// This function toggles between inactivity and activity for the popup panel.
/// This will be changed later when the model gets integrated, probably being timed to dissapear.
/// </summary>
//public void ShowFeedback()
//{
// if (feedbackPopup.activeSelf)
// {
// dynamic.text = "";
// feedbackPopup.SetActive(false);
// return;
// }
// double index = UnityEngine.Random.value;
// if (index < 0.5)
// {
// dynamic.text = "Poor";
// }
// else if (index > 0.8)
// {
// dynamic.text = "Excellent";
// }
// else
// {
// dynamic.text = "Good";
// }
// feedbackPopup.SetActive(true);
//}
// Get currentWordIndex
public int GetWordIndex()
{
return currentWordIndex;
}
}