Commit 0ed084a6 authored by mohamed20047's avatar mohamed20047

complete new mcq game

parent 90197342
This source diff could not be displayed because it is too large. You can view the blob instead.
fileFormatVersion: 2
guid: dc77d4f7977b6514e96035771e5e547f
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 20ba488acbcf34d438c13bfb24840820
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;
using LightSide;
public class AnswerButtonUI : MonoBehaviour
{
[SerializeField] private Button button;
[SerializeField] private Image answerImageComponent;
[SerializeField] private UniText answerTextComponent;
[SerializeField] private LayoutGroup answerLayout;
[SerializeField] private Image buttonBackgroundImage;
[SerializeField] private Color normalColor = Color.white;
[SerializeField] private Color normalTextColor = Color.black;
[SerializeField] private Color selectedCorrectColor = Color.green;
[SerializeField] private Color selectedIncorrectColor = Color.red;
[SerializeField] private Color correctAnswerColor = new Color(0.2f, 0.8f, 0.2f, 1f); // Light green
[SerializeField] private Color disabledColor = new Color(0.7f, 0.7f, 0.7f, 1f); // Gray
private int answerIndex;
private Action<int> onClicked;
private bool isInteractable = true;
private void OnEnable()
{
if (button != null)
{
button.onClick.RemoveAllListeners();
}
}
/// <summary>
/// Setup answer button with text and optional image
/// </summary>
public void Setup(string answerText, Sprite answerImage, int index, Action<int> callback)
{
button.Select();
answerIndex = index;
onClicked = callback;
isInteractable = true;
// Setup text
if (answerTextComponent != null)
{
answerTextComponent.Text = answerText;
answerTextComponent.color = normalTextColor;
}
// Setup image
if (answerImageComponent != null)
{
if (answerImage != null)
{
answerImageComponent.sprite = answerImage;
answerImageComponent.gameObject.SetActive(true);
}
else
{
answerImageComponent.gameObject.SetActive(false);
}
}
// Setup button
if (button != null)
{
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() => HandleClick());
button.interactable = true;
}
// Reset background color
if (buttonBackgroundImage != null)
{
buttonBackgroundImage.color = normalColor;
}
// Rebuild layout
if (answerLayout != null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(answerLayout.transform as RectTransform);
}
}
/// <summary>
/// Handle button click
/// </summary>
private void HandleClick()
{
if (!isInteractable || button == null || !button.interactable)
return;
onClicked?.Invoke(answerIndex);
}
/// <summary>
/// Mark this answer as selected and correct
/// </summary>
public void SetSelected(bool isCorrect)
{
isInteractable = false;
if (buttonBackgroundImage != null)
{
buttonBackgroundImage.color = isCorrect ? selectedCorrectColor : selectedIncorrectColor;
}
if (button != null)
{
button.interactable = false;
}
}
/// <summary>
/// Show this as the correct answer (when user selected wrong)
/// </summary>
public void SetCorrect()
{
isInteractable = false;
if (buttonBackgroundImage != null)
{
buttonBackgroundImage.color = correctAnswerColor;
}
if (button != null)
{
button.interactable = false;
}
}
/// <summary>
/// Disable this button without highlighting
/// </summary>
public void SetDisabled()
{
isInteractable = false;
if (buttonBackgroundImage != null)
{
buttonBackgroundImage.color = disabledColor;
}
if (button != null)
{
button.interactable = false;
}
}
/// <summary>
/// Reset button to normal state
/// </summary>
public void Reset()
{
isInteractable = true;
if (buttonBackgroundImage != null)
{
buttonBackgroundImage.color = normalColor;
}
if (answerTextComponent != null)
{
answerTextComponent.color = normalTextColor;
}
if (button != null)
{
button.interactable = true;
}
}
/// <summary>
/// Get answer index
/// </summary>
public int GetAnswerIndex()
{
return answerIndex;
}
/// <summary>
/// Check if button is interactable
/// </summary>
public bool IsInteractable()
{
return isInteractable;
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: cb8a50d45c5491e45a8c75803f8df92c
\ No newline at end of file
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;
using DG.Tweening;
using com.al_arcade.shared;
using com.al_arcade.mcq;
namespace com.al_arcade.mcq
{
public class NewMCQGameManger : MonoBehaviour
{
[SerializeField] private int totalLives = 5;
[SerializeField] private float questionTime = 5;
[SerializeField] private float streakBonusThreshold = 3;
[Header("Audio — SFX Clips")]
[SerializeField] private AudioClip sfxCorrect;
[SerializeField] private AudioClip sfxWrong;
[SerializeField] private AudioClip sfxClick;
[SerializeField] private AudioClip sfxVictory;
[SerializeField] private AudioClip sfxDefeat;
[SerializeField] private AudioClip sfxWhoosh;
[SerializeField] private AudioClip sfxPop;
[SerializeField] private AudioClip sfxCheer;
[SerializeField] private AudioClip sfxCountdown;
private McqQuestion[] _questions;
private McqQuestion currentQuestion;
private int currentQuestionIndex;
private int _score, _streak, _bestStreak, _lives;
private int _correctCount, _wrongCount;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
SetupAudioManager();
_lives = totalLives;
if (NewMCQUIManager.Instance != null)
{
NewMCQUIManager.Instance.SetLives(totalLives, totalLives);
NewMCQUIManager.Instance.SetScore(0);
NewMCQUIManager.Instance.ShowGameUI();
}
StartCoroutine(StartGame());
}
private IEnumerator StartGame()
{
NewMCQUIManager.Instance.ShowLoading("جاري تحميل الأسئلة...");
var session = SSGameSession.EnsureInstance();
var api = SSApiManager.EnsureInstance();
string error = null;
yield return api.FetchMcq(
session.buildType, session.classCode,
session.questionCount, session.gradeId,
qs => _questions = qs,
err => error = err
);
if (error != null || _questions == null || _questions.Length == 0)
{
NewMCQUIManager.Instance.ShowError(error ?? "لا توجد أسئلة متاحة");
yield break;
}
NewMCQUIManager.Instance.HideLoading();
ShowNextQuestion();
}
private void ShowNextQuestion()
{
NewMCQUIManager.Instance.SetProgress(currentQuestionIndex, _questions.Length);
if (currentQuestionIndex > _questions.Length)
{
StartCoroutine(VictorySequence());
return;
}
McqQuestion question = _questions[currentQuestionIndex];
QuestionUi.Instance.DisplayQuestion(question, OnAnswerSubmitted);
}
private void OnAnswerSubmitted(int selectedIndex, bool isCorrect)
{
Debug.Log($"Answer Index: {selectedIndex}, Correct:{isCorrect}");
if (isCorrect)
{
_correctCount++;
_streak++;
if (_bestStreak < _streak)
{
_bestStreak = _streak;
}
int points = 100;
if (_streak >= streakBonusThreshold)
points += (_streak - (int)streakBonusThreshold + 1) * 25;
_score += points;
ShowCorrectFeedback(points);
var audio = SSAudioManager.Instance;
if (audio != null)
{
if (audio.sfxCorrect != null) audio.PlayCorrect();
else audio.PlayCorrectBeep();
}
}
else
{
_streak = 0;
_wrongCount++;
_lives--;
ShowWrongFeedback();
NewMCQUIManager.Instance.SetScore(_score);
NewMCQUIManager.Instance.SetLives(_lives, totalLives);
if (_lives <= 0)
{
StartCoroutine(GameOverSequence());
return;
}
var audio = SSAudioManager.Instance;
if (audio != null)
{
if (audio.sfxWrong != null) audio.PlayWrong();
else audio.PlayWrongBeep();
}
}
Invoke(nameof(GoToNextQuestion),1f);
}
private void GoToNextQuestion()
{
currentQuestionIndex++;
QuestionUi.Instance.ResetForNextQuestion();
ShowNextQuestion();
}
private IEnumerator VictorySequence()
{
var audio = SSAudioManager.Instance;
if (audio != null)
{ if (audio.sfxVictory != null) audio.PlayVictory(); else audio.PlaySuccessJingle(); }
var particles = SSParticleManager.Instance;
if (particles != null) particles.PlayScreenConfetti();
yield return new WaitForSeconds(0.5f);
NewMCQUIManager.Instance.ShowResults(_score, _correctCount, _wrongCount,
_bestStreak, _questions.Length, true);
}
private IEnumerator GameOverSequence()
{
var audio = SSAudioManager.Instance;
if (audio != null)
{ if (audio.sfxDefeat != null) audio.PlayDefeat(); else audio.PlayFailBuzz(); }
yield return new WaitForSeconds(0.5f);
NewMCQUIManager.Instance.ShowResults(_score, _correctCount, _wrongCount,
_bestStreak, _questions.Length, false);
}
private void ShowCorrectFeedback(int points)
{
if (NewMCQUIManager.Instance != null)
{
string msg = _streak >= streakBonusThreshold
? $"ممتاز! +{points} (سلسلة {_streak}×)"
: $"صحيح! +{points}";
NewMCQUIManager.Instance.ShowFeedback(msg, true);
}
}
private void ShowWrongFeedback()
{
if (NewMCQUIManager.Instance != null) NewMCQUIManager.Instance.ShowFeedback("خطأ!", false);
if (Camera.main != null)
{
DOTween.Kill(Camera.main.transform, "camShake");
Camera.main.transform.DOShakePosition(0.4f, 0.3f, 15, 90f, false, true)
.SetEase(Ease.OutQuad).SetId("camShake");
}
}
private void SetupAudioManager()
{
var a = SSAudioManager.EnsureInstance();
if (sfxCorrect != null) a.sfxCorrect = sfxCorrect;
if (sfxWrong != null) a.sfxWrong = sfxWrong;
if (sfxClick != null) a.sfxClick = sfxClick;
if (sfxVictory != null) a.sfxVictory = sfxVictory;
if (sfxDefeat != null) a.sfxDefeat = sfxDefeat;
if (sfxWhoosh != null) a.sfxWhoosh = sfxWhoosh;
if (sfxPop != null) a.sfxPop = sfxPop;
if (sfxCheer != null) a.sfxCheer = sfxCheer;
if (sfxCountdown != null) a.sfxCountdown = sfxCountdown;
}
}
}
fileFormatVersion: 2
guid: 8b4109c5dc3e965418f041d490b09d96
\ No newline at end of file
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
// using ALArcade.ArabicTMP;
namespace com.al_arcade.mcq
{
using DG.Tweening;
using LightSide;
using shared;
using UnityEngine.SceneManagement;
public class NewMCQUIManager : MonoBehaviour
{
public static NewMCQUIManager Instance;
[Header("CanvasGroups")]
[SerializeField] private CanvasGroup _gameUI;
[SerializeField] private CanvasGroup _loadingUI;
[SerializeField] private CanvasGroup _errorUI;
[SerializeField] private CanvasGroup _resultsUI;
[SerializeField] private CanvasGroup _feedbackUI;
[Header("Game UI")]
[SerializeField] private UniText _scoreText;
[SerializeField] private UniText _streakText;
[SerializeField] private UniText _progressText;
[SerializeField] private UniText _loadingText;
[SerializeField] private UniText _errorText;
[SerializeField] private UniText _feedbackText;
[SerializeField] private Image _feedbackBg;
[SerializeField] private Image[] _heartIcons;
[Header("Results UI")]
[SerializeField] private UniText _resultTitle;
[SerializeField] private UniText _resultScore;
[SerializeField] private UniText _resultCorrect;
[SerializeField] private UniText _resultWrong;
[SerializeField] private UniText _resultStreak;
[SerializeField] private Button _resultRestartBtn;
[SerializeField] private Slider _progressSlider;
[SerializeField] private GameObject _winIcon;
[SerializeField] private GameObject _loseIcon;
private Image _progressFill;
[Header("Events")]
public UnityEvent onRestartClicked;
private void Awake()
{
if (_gameUI != null)
{
_gameUI.alpha = 0; _gameUI.gameObject.SetActive(false);
}
if (_loadingUI != null)
{
_loadingUI.alpha = 0; _loadingUI.gameObject.SetActive(false);
}
if (_errorUI != null)
{
_errorUI.alpha = 0; _errorUI.gameObject.SetActive(false);
}
if (_resultsUI != null)
{
_resultsUI.alpha = 0; _resultsUI.gameObject.SetActive(false);
}
if (_feedbackUI != null)
{
_feedbackUI.alpha = 0; _feedbackUI.gameObject.SetActive(true);
}
if (_winIcon != null) _winIcon.SetActive(false);
if (_loseIcon != null) _loseIcon.SetActive(false);
if(Instance != null)
{
Debug.LogError("there is two ui manager");
}
else
{
Instance = this;
}
}
private void Start()
{
_resultRestartBtn.onClick.AddListener(() => { SceneManager.LoadScene(SceneManager.GetActiveScene().name); });
}
public void ShowGameUI()
{
_gameUI.gameObject.SetActive(true);
_gameUI.DOFade(1f, 0.5f);
}
public void SetScore(int score)
{
if (_scoreText == null) return;
_scoreText.Text = score.ToString("N0");
DOTween.Kill(_scoreText.transform, "scorePunch");
_scoreText.transform.DOPunchScale(Vector3.one * 0.2f, 0.3f, 6, 0.3f)
.SetId("scorePunch");
}
public void SetStreak(int streak)
{
if (_streakText == null) return;
_streakText.Text = streak > 1 ? $"🔥 ×{streak}" : "";
if (streak > 1)
{
DOTween.Kill(_streakText.transform, "streakPop");
_streakText.transform.localScale = Vector3.one * 1.3f;
_streakText.transform.DOScale(Vector3.one, 0.4f)
.SetEase(Ease.OutElastic).SetId("streakPop");
}
}
public void SetLives(int lives, int maxLives)
{
for (int i = 0; i < _heartIcons.Length; i++)
{
bool active = i < maxLives;
_heartIcons[i].gameObject.SetActive(active);
if (active)
{
bool alive = i < lives;
_heartIcons[i].color = alive
? SSColorPalette.Danger
: SSColorPalette.WithAlpha(SSColorPalette.Danger, 0.2f);
if (!alive && i == lives)
{
DOTween.Kill(_heartIcons[i].transform);
_heartIcons[i].transform.DOPunchScale(Vector3.one * 0.5f, 0.3f);
}
}
}
}
public void SetProgress(int current, int total)
{
if (_progressText != null) _progressText.Text = $"{current} / {total}";
if (_progressFill != null && total > 0)
{
float t = (float)current / total;
DOTween.Kill(_progressFill.rectTransform, "progFill");
_progressFill.rectTransform.DOAnchorMax(new Vector2(t, 1f), 0.5f)
.SetEase(Ease.OutQuad).SetId("progFill");
}
if (_progressSlider != null)
{
DOTween.Kill("progSlider");
DOVirtual.Float(_progressSlider.value, (float)current, 0.5f, score =>
{
_progressSlider.value = score;
}).SetEase(Ease.OutQuad).SetId("progSlider");
}
}
public void ShowFeedback(string message, bool isCorrect)
{
if (_feedbackText != null) _feedbackText.Text = message;
if (_feedbackBg != null)
_feedbackBg.color = SSColorPalette.WithAlpha(
isCorrect ? SSColorPalette.Success : SSColorPalette.Danger, 0.92f);
DOTween.Kill(_feedbackUI);
_feedbackUI.alpha = 0;
var bgRect = _feedbackBg?.rectTransform;
if (bgRect != null)
{
print("Showing Feedback");
bgRect.localScale = new Vector3(0.5f, 0f, 1f);
var seq = DOTween.Sequence();
seq.Append(_feedbackUI.DOFade(1f, 0.15f));
seq.Join(bgRect.DOScaleX(1f, 0.25f).SetEase(Ease.OutBack));
seq.Join(bgRect.DOScaleY(1f, 0.2f).SetEase(Ease.OutBack).SetDelay(0.05f));
seq.AppendInterval(1.2f);
seq.Append(_feedbackUI.DOFade(0f, 0.3f));
}
}
public void ShowLoading(string msg)
{
_loadingUI.gameObject.SetActive(true);
if (_loadingText != null) _loadingText.Text = msg;
_loadingUI.DOFade(1f, 0.3f);
}
public void HideLoading()
{
_loadingUI.DOFade(0f, 0.3f)
.OnComplete(() => _loadingUI.gameObject.SetActive(false));
}
public void ShowError(string msg)
{
_errorUI.gameObject.SetActive(true);
if (_errorText != null) _errorText.Text = msg;
_errorUI.DOFade(1f, 0.3f);
}
public void ShowResults(int score, int correct, int wrong,
int bestStreak, int total, bool won)
{
_resultsUI.gameObject.SetActive(true);
_resultsUI.alpha = 0;
if (_resultTitle != null) _resultTitle.Text = won ? "أحسنت!" : "حظ أوفر!";
if (_resultScore != null) _resultScore.Text = score.ToString("N0");
if (_resultCorrect != null) _resultCorrect.Text = $"صحيح: {correct}";
if (_resultWrong != null) _resultWrong.Text = $"خطأ: {wrong}";
if (_resultStreak != null) _resultStreak.Text = $"أعلى سلسلة: {bestStreak}";
if (_winIcon != null) _winIcon.SetActive(won);
if (_loseIcon != null) _loseIcon.SetActive(!won);
var seq = DOTween.Sequence();
seq.Append(_resultsUI.DOFade(1f, 0.5f));
if (_resultTitle != null)
{
_resultTitle.transform.localScale = Vector3.zero;
seq.Append(_resultTitle.transform.DOScale(1f, 0.5f).SetEase(Ease.OutBack));
}
if (_winIcon != null)
{
_winIcon.transform.localScale = Vector3.zero;
seq.Append(_winIcon.transform.DOScale(1f, 0.5f).SetEase(Ease.OutBack));
}
if (_loseIcon != null)
{
_loseIcon.transform.localScale = Vector3.zero;
seq.Append(_loseIcon.transform.DOScale(1f, 0.5f).SetEase(Ease.OutBack));
}
if (_resultScore != null)
{
_resultScore.transform.localScale = Vector3.zero;
seq.Append(_resultScore.transform.DOScale(1f, 0.4f).SetEase(Ease.OutBack));
}
}
public void HideResults()
{
_resultsUI.DOFade(0f, 0.3f)
.OnComplete(() => _resultsUI.gameObject.SetActive(false));
}
public void RestartButtonFunction()
{
HideResults();
onRestartClicked?.Invoke();
McqGameManager.Instance.ResetGame();
McqGameManager.Instance.StartGame();
}
public void ResetUI()
{
_gameUI.gameObject.SetActive(false);
_loadingUI.gameObject.SetActive(false);
_errorUI.gameObject.SetActive(false);
_resultsUI.gameObject.SetActive(false);
_feedbackUI.alpha = 0;
}
}
}
fileFormatVersion: 2
guid: 168f088242b9231408ef684c9094c66e
\ No newline at end of file
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;
using com.al_arcade.shared;
using LightSide;
public class QuestionUi : MonoBehaviour
{
public static QuestionUi Instance;
[SerializeField] private Image questionImageComponent;
[SerializeField] private UniText questionTextComponent;
[SerializeField] private Transform answersGrid;
[SerializeField] private AnswerButtonUI[] answerButtons = new AnswerButtonUI[4];
[SerializeField] private LayoutGroup questionContainer;
[SerializeField] private LayoutGroup answersContainer;
private McqQuestion currentQuestion;
private int correctAnswerIndex = -1;
private bool hasAnswered = false;
private Action<int, bool> onAnswerSelected;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Debug.LogError("there is two questionUI");
}
}
private void OnEnable()
{
if (answerButtons.Length != 4)
{
Debug.LogError("MultiChoiceQuestionUI: Must have exactly 4 answer buttons!");
}
}
/// <summary>
/// Display a multiple choice question with all its data
/// </summary>
public void DisplayQuestion(McqQuestion question, Action<int, bool> onAnswerCallback = null)
{
if (question == null)
{
Debug.LogError("MultiChoiceQuestionUI: Question is null!");
return;
}
currentQuestion = question;
onAnswerSelected = onAnswerCallback;
hasAnswered = false;
correctAnswerIndex = -1;
// Reset previous shuffle
question.ResetShuffle();
// Setup question display
SetupQuestion(question);
// Get shuffled answers WITH images
question.GetShuffledAnswersWithImages(
out string[] shuffledAnswers,
out Sprite[] shuffledImages,
out int correctIndex
);
correctAnswerIndex = correctIndex;
// Setup answer buttons with shuffled data
SetupAnswerButtons(shuffledAnswers, shuffledImages);
//RectTransform example = answerButtons[1].GetComponent<RectTransform>();
//(answersContainer as GridLayoutGroup).cellSize = new Vector2(example.rect.width, example.rect.height);
// Rebuild layout hierarchy
LayoutRebuilder.ForceRebuildLayoutImmediate(questionContainer.GetComponent<RectTransform>());
LayoutRebuilder.ForceRebuildLayoutImmediate(answersContainer.GetComponent<RectTransform>());
}
/// <summary>
/// Setup the question text and image
/// </summary>
private void SetupQuestion(McqQuestion question)
{
// Setup question text
questionTextComponent.Text = question.question_text;
// Setup question image (if exists)
if (question.questionImage != null)
{
questionImageComponent.sprite = question.questionImage;
questionImageComponent.gameObject.SetActive(true);
}
else
{
questionImageComponent.gameObject.SetActive(false);
}
}
/// <summary>
/// Setup all 4 answer buttons with text and images
/// </summary>
private void SetupAnswerButtons(string[] answers, Sprite[] images)
{
if (answers.Length != 4 || images.Length != 4)
{
Debug.LogError("MultiChoiceQuestionUI: Answer arrays must have exactly 4 elements!");
return;
}
for (int i = 0; i < 4; i++)
{
answerButtons[i].Setup(
answerText: answers[i],
answerImage: images[i],
index: i,
callback: OnAnswerClicked
);
}
}
/// <summary>
/// Called when an answer button is clicked
/// </summary>
private void OnAnswerClicked(int selectedIndex)
{
Debug.Log("pressed");
if (hasAnswered)
return;
hasAnswered = true;
bool isCorrect = selectedIndex == correctAnswerIndex;
// Show visual feedback
ShowAnswerFeedback(selectedIndex, isCorrect);
// Invoke callback
onAnswerSelected?.Invoke(selectedIndex, isCorrect);
}
/// <summary>
/// Show visual feedback for selected answer
/// </summary>
private void ShowAnswerFeedback(int selectedIndex, bool isCorrect)
{
for (int i = 0; i < 4; i++)
{
if (i == selectedIndex)
{
answerButtons[i].SetSelected(isCorrect);
}
else if (i == correctAnswerIndex && !isCorrect)
{
answerButtons[i].SetCorrect();
}
else
{
answerButtons[i].SetDisabled();
}
}
}
/// <summary>
/// Reset all buttons for next question
/// </summary>
public void ResetForNextQuestion()
{
hasAnswered = false;
correctAnswerIndex = -1;
foreach (var button in answerButtons)
{
button.Reset();
}
}
/// <summary>
/// Get current question
/// </summary>
public McqQuestion GetCurrentQuestion()
{
return currentQuestion;
}
/// <summary>
/// Get the correct answer index for current question
/// </summary>
public int GetCorrectAnswerIndex()
{
return correctAnswerIndex;
}
/// <summary>
/// Check if user has answered
/// </summary>
public bool HasAnswered()
{
return hasAnswered;
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: 68aee830395e108478a9643b20de1689
\ No newline at end of file
...@@ -61,28 +61,120 @@ namespace com.al_arcade.shared ...@@ -61,28 +61,120 @@ namespace com.al_arcade.shared
{ {
public string id; public string id;
public string question_text; public string question_text;
public Sprite questionImage;
public string answer1; public string answer1;
public Sprite answer1Image;
public string answer2; public string answer2;
public Sprite answer2Image;
public string answer3; public string answer3;
public Sprite answer3Image;
public string answer4; public string answer4;
public Sprite answer4Image;
public string source; public string source;
public string grade_name; public string grade_name;
// Private shuffle state (keeps track of current shuffle)
private int[] _shuffleIndices;
private int _cachedCorrectIndex = -1;
/// <summary>
/// Original method - unchanged for backwards compatibility
/// </summary>
public string[] GetShuffledAnswers(out int correctIndex) public string[] GetShuffledAnswers(out int correctIndex)
{ {
string[] arr = { answer1, answer2, answer3, answer4 }; string[] arr = { answer1, answer2, answer3, answer4 };
string correct = answer1; string correct = answer1;
// Generate and cache shuffle indices
for (int i = arr.Length - 1; i > 0; i--) _shuffleIndices = new int[] { 0, 1, 2, 3 };
for (int i = _shuffleIndices.Length - 1; i > 0; i--)
{ {
int j = UnityEngine.Random.Range(0, i + 1); int j = UnityEngine.Random.Range(0, i + 1);
(arr[i], arr[j]) = (arr[j], arr[i]); (_shuffleIndices[i], _shuffleIndices[j]) = (_shuffleIndices[j], _shuffleIndices[i]);
}
// Apply shuffle
string[] shuffled = new string[4];
for (int i = 0; i < 4; i++)
{
shuffled[i] = arr[_shuffleIndices[i]];
}
correctIndex = Array.IndexOf(shuffled, correct);
_cachedCorrectIndex = correctIndex;
return shuffled;
}
/// <summary>
/// NEW: Get shuffled answers WITH images
/// Returns answer text + images in the same shuffled order
/// </summary>
public void GetShuffledAnswersWithImages(
out string[] answers,
out Sprite[] images,
out int correctIndex)
{
string[] textArr = { answer1, answer2, answer3, answer4 };
Sprite[] imageArr = { answer1Image, answer2Image, answer3Image, answer4Image };
string correct = answer1;
// Generate shuffle indices if not already done
if (_shuffleIndices == null || _shuffleIndices.Length == 0)
{
_shuffleIndices = new int[] { 0, 1, 2, 3 };
for (int i = _shuffleIndices.Length - 1; i > 0; i--)
{
int j = UnityEngine.Random.Range(0, i + 1);
(_shuffleIndices[i], _shuffleIndices[j]) = (_shuffleIndices[j], _shuffleIndices[i]);
}
}
// Apply shuffle to both text and images
string[] shuffledText = new string[4];
Sprite[] shuffledImages = new Sprite[4];
for (int i = 0; i < 4; i++)
{
int originalIndex = _shuffleIndices[i];
shuffledText[i] = textArr[originalIndex];
shuffledImages[i] = imageArr[originalIndex];
} }
correctIndex = Array.IndexOf(arr, correct); answers = shuffledText;
return arr; images = shuffledImages;
correctIndex = Array.IndexOf(shuffledText, correct);
_cachedCorrectIndex = correctIndex;
}
/// <summary>
/// HELPER: Get image for a specific answer index (after shuffle)
/// Useful if you only have the index
/// </summary>
public Sprite GetAnswerImageByIndex(int shuffledIndex)
{
if (_shuffleIndices == null || _shuffleIndices.Length == 0)
return null;
int originalIndex = _shuffleIndices[shuffledIndex];
Sprite[] allImages = { answer1Image, answer2Image, answer3Image, answer4Image };
return allImages[originalIndex];
}
/// <summary>
/// HELPER: Get the cached correct index from last shuffle
/// </summary>
public int GetCachedCorrectIndex()
{
return _cachedCorrectIndex;
}
/// <summary>
/// HELPER: Reset shuffle state (call before new question)
/// </summary>
public void ResetShuffle()
{
_shuffleIndices = null;
_cachedCorrectIndex = -1;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment