MathQuizManager.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using UnityEngine;
  2. using TMPro;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. public class MathQuizManager : MonoBehaviour
  6. {
  7. [Header("UI")]
  8. [SerializeField] private TextMeshProUGUI questionText;
  9. [SerializeField] private TextMeshProUGUI coinText;
  10. [SerializeField] private GameObject answerPrefab;
  11. [Header("参数")]
  12. [SerializeField] private float wrongPenalty = 0.1f;
  13. [SerializeField] private int correctReward = 10;
  14. [SerializeField] private float answerLife = 15f;
  15. [SerializeField] private float floatSpeed = 0.3f;
  16. [SerializeField] private float correctBoost = 0.2f;
  17. [SerializeField] private float boostTime = 5f;
  18. [SerializeField] private float spawnRadius = 3f;
  19. [SerializeField] private float minSpawnDist = 1.5f;
  20. [SerializeField] private int maxAnswers = 6;
  21. [SerializeField] private float correctChance = 0.3f;
  22. private int currentAnswer;
  23. private int coins;
  24. private List<Warrior> penalized = new();
  25. private List<AnswerOption> answers = new();
  26. private Vector3 lastEnemyPos;
  27. private int deathCount = 0;
  28. void Start() { NewProblem(); UpdateCoin(); }
  29. void NewProblem()
  30. {
  31. int a = Random.Range(1, 11), b = Random.Range(1, 11);
  32. if (Random.value < 0.5f) // 加法
  33. {
  34. currentAnswer = a + b;
  35. questionText.text = $"{a} + {b} = ?";
  36. }
  37. else // 减法
  38. {
  39. if (b > a) (a, b) = (b, a);
  40. currentAnswer = a - b;
  41. questionText.text = $"{a} - {b} = ?";
  42. }
  43. }
  44. public bool CheckAnswer(AnswerOption opt)
  45. {
  46. bool correct = opt.GetAnswerValue() == currentAnswer;
  47. if (correct) OnCorrect();
  48. else OnWrong(opt);
  49. return correct;
  50. }
  51. void OnCorrect()
  52. {
  53. coins += correctReward;
  54. UpdateCoin();
  55. ResetPenalties();
  56. ClearAnswers();
  57. NewProblem();
  58. }
  59. void OnWrong(AnswerOption opt)
  60. {
  61. ApplyPenalty();
  62. RemoveAnswer(opt);
  63. Destroy(opt.gameObject);
  64. }
  65. void ClearAnswers()
  66. {
  67. foreach (var a in answers) if (a) Destroy(a.gameObject);
  68. answers.Clear();
  69. }
  70. public void RemoveAnswer(AnswerOption a) => answers.Remove(a);
  71. void UpdateCoin() => coinText.text = coins.ToString();
  72. void ApplyPenalty()
  73. {
  74. foreach (var w in FindObjectsOfType<Warrior>())
  75. if (!w.IsEnemy && !penalized.Contains(w))
  76. {
  77. w.ApplyDamagePenalty(wrongPenalty);
  78. penalized.Add(w);
  79. }
  80. }
  81. void ResetPenalties()
  82. {
  83. foreach (var w in penalized) if (w) w.ResetDamagePenalty();
  84. penalized.Clear();
  85. }
  86. public void OnEnemyDeath(Vector3 pos, int _)
  87. {
  88. lastEnemyPos = pos;
  89. if (++deathCount >= 2)
  90. {
  91. SpawnAnswer();
  92. deathCount = 0;
  93. }
  94. }
  95. void SpawnAnswer()
  96. {
  97. if (answers.Count >= maxAnswers) RemoveOldest();
  98. int val = Random.value < correctChance ? currentAnswer : Mathf.Clamp(currentAnswer + Random.Range(-3, 4), 1, 20);
  99. Vector3 p = lastEnemyPos + Quaternion.Euler(0, Random.Range(0, 360f), 0) * (Vector3.forward * Random.Range(minSpawnDist, spawnRadius));
  100. var obj = Instantiate(answerPrefab, p, Quaternion.identity);
  101. var opt = obj.GetComponent<AnswerOption>();
  102. if (opt)
  103. {
  104. opt.Initialize(this, val, val == currentAnswer);
  105. answers.Add(opt);
  106. }
  107. else
  108. {
  109. Destroy(obj);
  110. }
  111. // 新手引导
  112. if (!PlayerPrefs.HasKey("FirstQuizTutorial"))
  113. {
  114. PlayerPrefs.SetInt("FirstQuizTutorial", 1);
  115. var tut = FindObjectOfType<Tutorial>();
  116. if (tut) tut.ShowQuizTutorial(answerPrefab.transform);
  117. }
  118. }
  119. void RemoveOldest()
  120. {
  121. if (answers.Count > 0)
  122. {
  123. var oldest = answers[0];
  124. answers.RemoveAt(0);
  125. if (oldest) Destroy(oldest.gameObject);
  126. }
  127. }
  128. }