123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- 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<Warrior> penalized = new();
- private List<AnswerOption> 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<Warrior>())
- 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<AnswerOption>();
- 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<Tutorial>();
- if (tut) tut.ShowQuizTutorial(answerPrefab.transform);
- }
- }
- void RemoveOldest()
- {
- if (answers.Count > 0)
- {
- var oldest = answers[0];
- answers.RemoveAt(0);
- if (oldest) Destroy(oldest.gameObject);
- }
- }
- }
|