Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
341 lines
11 KiB
C#
341 lines
11 KiB
C#
// ==============================================
|
|
// QuizOverlay.cs - Quiz-UI Anzeige
|
|
// ==============================================
|
|
// Zeigt Quiz-Fragen an (Quick und Pause Mode)
|
|
// mit Timer, Antwort-Buttons und Feedback.
|
|
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
|
|
namespace BreakpilotDrive
|
|
{
|
|
public class QuizOverlay : MonoBehaviour
|
|
{
|
|
[Header("Panels")]
|
|
[SerializeField] private GameObject quickQuizPanel;
|
|
[SerializeField] private GameObject pauseQuizPanel;
|
|
[SerializeField] private GameObject feedbackPanel;
|
|
|
|
[Header("Quick Quiz UI")]
|
|
[SerializeField] private TextMeshProUGUI quickQuestionText;
|
|
[SerializeField] private Button[] quickAnswerButtons;
|
|
[SerializeField] private Slider timerSlider;
|
|
[SerializeField] private TextMeshProUGUI timerText;
|
|
|
|
[Header("Pause Quiz UI")]
|
|
[SerializeField] private TextMeshProUGUI pauseQuestionText;
|
|
[SerializeField] private Button[] pauseAnswerButtons;
|
|
[SerializeField] private TextMeshProUGUI pauseHintText;
|
|
|
|
[Header("Feedback UI")]
|
|
[SerializeField] private TextMeshProUGUI feedbackText;
|
|
[SerializeField] private Image feedbackIcon;
|
|
[SerializeField] private Sprite correctIcon;
|
|
[SerializeField] private Sprite wrongIcon;
|
|
|
|
[Header("Farben")]
|
|
[SerializeField] private Color normalColor = Color.white;
|
|
[SerializeField] private Color correctColor = Color.green;
|
|
[SerializeField] private Color wrongColor = Color.red;
|
|
[SerializeField] private Color selectedColor = Color.yellow;
|
|
|
|
[Header("Animation")]
|
|
[SerializeField] private Animator quizAnimator;
|
|
[SerializeField] private float feedbackDuration = 1.5f;
|
|
|
|
// Aktuelle Frage
|
|
private QuizQuestion currentQuestion;
|
|
private int selectedAnswer = -1;
|
|
private bool isAnswered = false;
|
|
|
|
void Start()
|
|
{
|
|
// Panels verstecken
|
|
HideAll();
|
|
|
|
// QuizManager Events abonnieren
|
|
if (QuizManager.Instance != null)
|
|
{
|
|
QuizManager.Instance.OnQuizStarted += OnQuizStarted;
|
|
QuizManager.Instance.OnQuizEnded += OnQuizEnded;
|
|
QuizManager.Instance.OnQuestionAnswered += OnQuestionAnswered;
|
|
}
|
|
|
|
// Button-Listener einrichten
|
|
SetupButtons();
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
if (QuizManager.Instance != null)
|
|
{
|
|
QuizManager.Instance.OnQuizStarted -= OnQuizStarted;
|
|
QuizManager.Instance.OnQuizEnded -= OnQuizEnded;
|
|
QuizManager.Instance.OnQuestionAnswered -= OnQuestionAnswered;
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Button Setup
|
|
// ==============================================
|
|
private void SetupButtons()
|
|
{
|
|
// Quick Answer Buttons
|
|
for (int i = 0; i < quickAnswerButtons.Length; i++)
|
|
{
|
|
int index = i;
|
|
quickAnswerButtons[i].onClick.AddListener(() => OnAnswerClicked(index));
|
|
}
|
|
|
|
// Pause Answer Buttons
|
|
for (int i = 0; i < pauseAnswerButtons.Length; i++)
|
|
{
|
|
int index = i;
|
|
pauseAnswerButtons[i].onClick.AddListener(() => OnAnswerClicked(index));
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Quiz Events
|
|
// ==============================================
|
|
private void OnQuizStarted()
|
|
{
|
|
isAnswered = false;
|
|
selectedAnswer = -1;
|
|
}
|
|
|
|
private void OnQuizEnded()
|
|
{
|
|
StartCoroutine(HideAfterDelay(feedbackDuration));
|
|
}
|
|
|
|
private void OnQuestionAnswered(bool correct, int points)
|
|
{
|
|
isAnswered = true;
|
|
ShowFeedback(correct, points);
|
|
}
|
|
|
|
// ==============================================
|
|
// Quick Quiz anzeigen
|
|
// ==============================================
|
|
public void ShowQuickQuiz(QuizQuestion question, float timeLimit)
|
|
{
|
|
currentQuestion = question;
|
|
isAnswered = false;
|
|
|
|
// Panel aktivieren
|
|
HideAll();
|
|
if (quickQuizPanel) quickQuizPanel.SetActive(true);
|
|
|
|
// Frage anzeigen
|
|
if (quickQuestionText) quickQuestionText.text = question.question_text;
|
|
|
|
// Antworten anzeigen
|
|
for (int i = 0; i < quickAnswerButtons.Length; i++)
|
|
{
|
|
if (i < question.options.Length)
|
|
{
|
|
quickAnswerButtons[i].gameObject.SetActive(true);
|
|
var text = quickAnswerButtons[i].GetComponentInChildren<TextMeshProUGUI>();
|
|
if (text) text.text = $"[{i + 1}] {question.options[i]}";
|
|
ResetButtonColor(quickAnswerButtons[i]);
|
|
}
|
|
else
|
|
{
|
|
quickAnswerButtons[i].gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// Timer starten
|
|
StartCoroutine(UpdateTimer(timeLimit));
|
|
|
|
// Animation
|
|
if (quizAnimator) quizAnimator.SetTrigger("ShowQuick");
|
|
}
|
|
|
|
private IEnumerator UpdateTimer(float duration)
|
|
{
|
|
float timeRemaining = duration;
|
|
|
|
while (timeRemaining > 0 && !isAnswered)
|
|
{
|
|
timeRemaining -= Time.deltaTime;
|
|
|
|
// UI aktualisieren
|
|
if (timerSlider) timerSlider.value = timeRemaining / duration;
|
|
if (timerText) timerText.text = $"{timeRemaining:F1}s";
|
|
|
|
// Farbe aendern wenn Zeit knapp
|
|
if (timerSlider && timeRemaining < duration * 0.3f)
|
|
{
|
|
timerSlider.fillRect.GetComponent<Image>().color = Color.red;
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Pause Quiz anzeigen
|
|
// ==============================================
|
|
public void ShowPauseQuiz(QuizQuestion question)
|
|
{
|
|
currentQuestion = question;
|
|
isAnswered = false;
|
|
|
|
// Panel aktivieren
|
|
HideAll();
|
|
if (pauseQuizPanel) pauseQuizPanel.SetActive(true);
|
|
|
|
// Frage anzeigen
|
|
if (pauseQuestionText) pauseQuestionText.text = question.question_text;
|
|
|
|
// Hint anzeigen (falls aktiviert)
|
|
if (pauseHintText)
|
|
{
|
|
bool hintsEnabled = GameManager.Instance?.DifficultySettings?.hints_enabled ?? false;
|
|
pauseHintText.gameObject.SetActive(hintsEnabled);
|
|
// TODO: Hint-Text generieren
|
|
}
|
|
|
|
// Antworten anzeigen
|
|
for (int i = 0; i < pauseAnswerButtons.Length; i++)
|
|
{
|
|
if (i < question.options.Length)
|
|
{
|
|
pauseAnswerButtons[i].gameObject.SetActive(true);
|
|
var text = pauseAnswerButtons[i].GetComponentInChildren<TextMeshProUGUI>();
|
|
if (text) text.text = $"[{i + 1}] {question.options[i]}";
|
|
ResetButtonColor(pauseAnswerButtons[i]);
|
|
}
|
|
else
|
|
{
|
|
pauseAnswerButtons[i].gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// Animation
|
|
if (quizAnimator) quizAnimator.SetTrigger("ShowPause");
|
|
}
|
|
|
|
// ==============================================
|
|
// Antwort-Handling
|
|
// ==============================================
|
|
private void OnAnswerClicked(int index)
|
|
{
|
|
if (isAnswered || currentQuestion == null) return;
|
|
|
|
selectedAnswer = index;
|
|
|
|
// Button hervorheben
|
|
Button[] buttons = currentQuestion.quiz_mode == "quick" ?
|
|
quickAnswerButtons : pauseAnswerButtons;
|
|
|
|
if (index < buttons.Length)
|
|
{
|
|
HighlightButton(buttons[index]);
|
|
}
|
|
|
|
// An QuizManager melden (wird dort verarbeitet)
|
|
// QuizManager ruft dann OnQuestionAnswered auf
|
|
}
|
|
|
|
// ==============================================
|
|
// Feedback anzeigen
|
|
// ==============================================
|
|
private void ShowFeedback(bool correct, int points)
|
|
{
|
|
// Richtige Antwort markieren
|
|
Button[] buttons = currentQuestion?.quiz_mode == "quick" ?
|
|
quickAnswerButtons : pauseAnswerButtons;
|
|
|
|
if (currentQuestion != null && buttons != null)
|
|
{
|
|
int correctIndex = currentQuestion.correct_index;
|
|
if (correctIndex >= 0 && correctIndex < buttons.Length)
|
|
{
|
|
SetButtonColor(buttons[correctIndex], correctColor);
|
|
}
|
|
|
|
// Falsche Antwort rot markieren
|
|
if (!correct && selectedAnswer >= 0 && selectedAnswer < buttons.Length)
|
|
{
|
|
SetButtonColor(buttons[selectedAnswer], wrongColor);
|
|
}
|
|
}
|
|
|
|
// Feedback Panel
|
|
if (feedbackPanel)
|
|
{
|
|
feedbackPanel.SetActive(true);
|
|
|
|
if (feedbackText)
|
|
{
|
|
string pointsStr = points >= 0 ? $"+{points}" : $"{points}";
|
|
feedbackText.text = correct ?
|
|
$"Richtig! {pointsStr} Punkte" :
|
|
$"Leider falsch. {pointsStr} Punkte";
|
|
feedbackText.color = correct ? correctColor : wrongColor;
|
|
}
|
|
|
|
if (feedbackIcon)
|
|
{
|
|
feedbackIcon.sprite = correct ? correctIcon : wrongIcon;
|
|
}
|
|
}
|
|
|
|
// Sound abspielen
|
|
if (correct)
|
|
{
|
|
AudioManager.Instance?.PlayCorrectSound();
|
|
}
|
|
else
|
|
{
|
|
AudioManager.Instance?.PlayWrongSound();
|
|
}
|
|
|
|
// Animation
|
|
if (quizAnimator)
|
|
{
|
|
quizAnimator.SetTrigger(correct ? "Correct" : "Wrong");
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Helper
|
|
// ==============================================
|
|
private void HideAll()
|
|
{
|
|
if (quickQuizPanel) quickQuizPanel.SetActive(false);
|
|
if (pauseQuizPanel) pauseQuizPanel.SetActive(false);
|
|
if (feedbackPanel) feedbackPanel.SetActive(false);
|
|
}
|
|
|
|
private IEnumerator HideAfterDelay(float delay)
|
|
{
|
|
yield return new WaitForSecondsRealtime(delay);
|
|
HideAll();
|
|
}
|
|
|
|
private void ResetButtonColor(Button button)
|
|
{
|
|
SetButtonColor(button, normalColor);
|
|
}
|
|
|
|
private void HighlightButton(Button button)
|
|
{
|
|
SetButtonColor(button, selectedColor);
|
|
}
|
|
|
|
private void SetButtonColor(Button button, Color color)
|
|
{
|
|
var colors = button.colors;
|
|
colors.normalColor = color;
|
|
colors.highlightedColor = color;
|
|
button.colors = colors;
|
|
}
|
|
}
|
|
}
|