using UnityEngine; using TMPro; using System.Collections.Generic; using System.Linq; public class MathQuizManager : MonoBehaviour { [Header("UI")] [SerializeField] private TextMeshProUGUI questionText; [SerializeField] private TextMeshProUGUI coinText; [SerializeField] private GameObject answerPrefab; [Header("参数")] [SerializeField] private float wrongPenalty = 0.1f; [SerializeField] private int correctReward = 10; [SerializeField] private float answerLife = 15f; [SerializeField] private float floatSpeed = 0.3f; [SerializeField] private float correctBoost = 0.2f; [SerializeField] private float boostTime = 5f; [SerializeField] private float spawnRadius = 3f; [SerializeField] private float minSpawnDist = 1.5f; [SerializeField] private int maxAnswers = 6; [SerializeField] private float correctChance = 0.3f; private int currentAnswer; private int coins; private List penalized = new(); private List answers = new(); private Vector3 lastEnemyPos; private int deathCount = 0; void Start() { NewProblem(); UpdateCoin(); } void NewProblem() { int a = Random.Range(1, 11), b = Random.Range(1, 11); if (Random.value < 0.5f) // 加法 { currentAnswer = a + b; questionText.text = $"{a} + {b} = ?"; } else // 减法 { if (b > a) (a, b) = (b, a); currentAnswer = a - b; questionText.text = $"{a} - {b} = ?"; } } public bool CheckAnswer(AnswerOption opt) { bool correct = opt.GetAnswerValue() == currentAnswer; if (correct) OnCorrect(); else OnWrong(opt); return correct; } void OnCorrect() { coins += correctReward; UpdateCoin(); ResetPenalties(); ClearAnswers(); NewProblem(); } void OnWrong(AnswerOption opt) { ApplyPenalty(); RemoveAnswer(opt); Destroy(opt.gameObject); } void ClearAnswers() { foreach (var a in answers) if (a) Destroy(a.gameObject); answers.Clear(); } public void RemoveAnswer(AnswerOption a) => answers.Remove(a); void UpdateCoin() => coinText.text = coins.ToString(); void ApplyPenalty() { foreach (var w in FindObjectsOfType()) if (!w.IsEnemy && !penalized.Contains(w)) { w.ApplyDamagePenalty(wrongPenalty); penalized.Add(w); } } void ResetPenalties() { foreach (var w in penalized) if (w) w.ResetDamagePenalty(); penalized.Clear(); } public void OnEnemyDeath(Vector3 pos, int _) { lastEnemyPos = pos; if (++deathCount >= 2) { SpawnAnswer(); deathCount = 0; } } void SpawnAnswer() { if (answers.Count >= maxAnswers) RemoveOldest(); int val = Random.value < correctChance ? currentAnswer : Mathf.Clamp(currentAnswer + Random.Range(-3, 4), 1, 20); Vector3 p = lastEnemyPos + Quaternion.Euler(0, Random.Range(0, 360f), 0) * (Vector3.forward * Random.Range(minSpawnDist, spawnRadius)); var obj = Instantiate(answerPrefab, p, Quaternion.identity); var opt = obj.GetComponent(); if (opt) { opt.Initialize(this, val, val == currentAnswer); answers.Add(opt); } else { Destroy(obj); } // 新手引导 if (!PlayerPrefs.HasKey("FirstQuizTutorial")) { PlayerPrefs.SetInt("FirstQuizTutorial", 1); var tut = FindObjectOfType(); if (tut) tut.ShowQuizTutorial(answerPrefab.transform); } } void RemoveOldest() { if (answers.Count > 0) { var oldest = answers[0]; answers.RemoveAt(0); if (oldest) Destroy(oldest.gameObject); } } }