Unity 3D中Firebase问答游戏按ID逐个加载问题的代码修改
问题描述
我正在Unity 3D中开发基于Firebase的问答游戏,当前遇到问题:尝试通过层级子节点ID获取数据时,该层级下的所有问题会一次性加载到场景中,我希望能按ID逐个加载问题,请问需要修改代码的哪些部分?
当前加载代码
private IEnumerator LoadQuestionData(string level) { var DBTask = DBreference.Child("questions").OrderByChild("level").GetValueAsync(); yield return new WaitUntil(predicate: () => DBTask.IsCompleted); if (DBTask.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}"); } else { // Data has been retrieved DataSnapshot snapshot = DBTask.Result; // Destroy any existing question elements foreach (Transform child in questionuserContent.transform) { Destroy(child.gameObject); } List<DataSnapshot> questionSnapshots = new List<DataSnapshot>(); // Loop through each level foreach (DataSnapshot childLevelSnapshot in snapshot.Children.Reverse<DataSnapshot>()) { // Loop through each question of the level foreach (DataSnapshot childSnapshot in childLevelSnapshot.Children.Reverse<DataSnapshot>()) { questionSnapshots.Add(childSnapshot); } } // Shuffle the question snapshots using Fisher-Yates algorithm int n = questionSnapshots.Count; while (n > 1) { n--; int k = UnityEngine.Random.Range(0, n + 1); DataSnapshot temp = questionSnapshots[k]; questionSnapshots[k] = questionSnapshots[n]; questionSnapshots[n] = temp; } int questionCount = 10; for (int i = 0; i < questionCount; i++) { DataSnapshot questionSnapshot = questionSnapshots[i]; string questionId = questionSnapshot.Key; string question = questionSnapshot.Child("question").Value.ToString(); string optiona = questionSnapshot.Child("optiona").Value.ToString(); string optionb = questionSnapshot.Child("optionb").Value.ToString(); string optionc = questionSnapshot.Child("optionc").Value.ToString(); string optiond = questionSnapshot.Child("optiond").Value.ToString(); string correctAnswer = questionSnapshot.Child("correctAnswer").Value.ToString(); int score = int.Parse(questionSnapshot.Child("score").Value.ToString()); string userAnswer = "user's answer"; // Calculate score based on correct answer if (CheckAnswer(userAnswer, correctAnswer)) { // Increase the total score totalScore += score; } // Instantiate elemen pertanyaan baru GameObject questionObj = Instantiate(questionuserElement, questionuserContent); // Setel nilai-nilai elemen pertanyaan questionObj.GetComponent<UserQuestionElement>().UserQuestionData(questionId, level, question, optiona, optionb, optionc, optiond, correctAnswer, score); } // Save the total score automatically SaveScore(totalScore); // Tampilkan layar admin dengan tabel pertanyaan UIManager.instance.EasyUIScreen(); } }
Firebase数据结构



解决方案
要实现按ID逐个加载问题,需从数据获取逻辑、问题管理方式、加载触发时机三个核心部分修改:
1. 预加载目标层级的所有问题ID(而非全量数据)
原代码一次性拉取层级下所有问题的完整数据,现在改为先获取该层级下的所有问题ID,后续按需加载单条数据:
// 新增成员变量存储当前层级的问题ID列表、当前加载索引、当前层级 private List<string> _currentLevelQuestionIds = new List<string>(); private int _currentQuestionIndex = 0; private string _currentLevel; // 替换原LoadQuestionData为预加载ID的方法 private IEnumerator PreloadQuestionIds(string level) { _currentLevel = level; _currentQuestionIndex = 0; _currentLevelQuestionIds.Clear(); // 仅拉取目标层级的问题节点(匹配你的数据结构:questions -> level节点 -> questionId节点) var DBTask = DBreference.Child("questions").Child(level).GetValueAsync(); yield return new WaitUntil(() => DBTask.IsCompleted); if (DBTask.Exception != null) { Debug.LogWarning($"获取问题ID失败: {DBTask.Exception}"); yield break; } DataSnapshot levelSnapshot = DBTask.Result; // 遍历所有问题节点,只存储ID foreach (DataSnapshot questionSnapshot in levelSnapshot.Children.Reverse<DataSnapshot>()) { _currentLevelQuestionIds.Add(questionSnapshot.Key); } // 打乱ID顺序(保留原随机逻辑) int n = _currentLevelQuestionIds.Count; while (n > 1) { n--; int k = UnityEngine.Random.Range(0, n + 1); string temp = _currentLevelQuestionIds[k]; _currentLevelQuestionIds[k] = _currentLevelQuestionIds[n]; _currentLevelQuestionIds[n] = temp; } // 加载第一个问题 if (_currentLevelQuestionIds.Count > 0) { StartCoroutine(LoadSingleQuestion(_currentLevelQuestionIds[_currentQuestionIndex])); } }
2. 新增单条问题加载方法
单独实现根据ID加载单条问题数据的方法,每次只加载当前需要的问题:
private IEnumerator LoadSingleQuestion(string questionId) { // 销毁当前显示的问题(如果有) foreach (Transform child in questionuserContent.transform) { Destroy(child.gameObject); } // 直接通过层级+ID拉取单条数据 var DBTask = DBreference.Child("questions").Child(_currentLevel).Child(questionId).GetValueAsync(); yield return new WaitUntil(() => DBTask.IsCompleted); if (DBTask.Exception != null) { Debug.LogWarning($"加载问题失败: {DBTask.Exception}"); yield break; } DataSnapshot questionSnapshot = DBTask.Result; // 解析数据(逻辑与原代码一致) string question = questionSnapshot.Child("question").Value.ToString(); string optiona = questionSnapshot.Child("optiona").Value.ToString(); string optionb = questionSnapshot.Child("optionb").Value.ToString(); string optionc = questionSnapshot.Child("optionc").Value.ToString(); string optiond = questionSnapshot.Child("optiond").Value.ToString(); string correctAnswer = questionSnapshot.Child("correctAnswer").Value.ToString(); int score = int.Parse(questionSnapshot.Child("score").Value.ToString()); // 实例化问题UI GameObject questionObj = Instantiate(questionuserElement, questionuserContent); questionObj.GetComponent<UserQuestionElement>().UserQuestionData(questionId, _currentLevel, question, optiona, optionb, optionc, optiond, correctAnswer, score); }
3. 新增"下一题"触发逻辑
添加触发下一题的方法(可绑定到按钮点击事件),更新索引并加载下一个问题:
public void LoadNextQuestion() { _currentQuestionIndex++; if (_currentQuestionIndex >= _currentLevelQuestionIds.Count) { // 所有问题加载完成,执行结算逻辑 SaveScore(totalScore); UIManager.instance.EasyUIScreen(); return; } StartCoroutine(LoadSingleQuestion(_currentLevelQuestionIds[_currentQuestionIndex])); }
4. 调整分数计算逻辑
原代码在加载时直接计算分数,现在将分数计算移到用户提交答案的逻辑中(比如用户点击选项后调用):
// 用户提交答案时调用此方法计算分数 public void OnUserSubmitAnswer(string userAnswer, string correctAnswer, int score) { if (CheckAnswer(userAnswer, correctAnswer)) { totalScore += score; } }
关键修改点总结
- 将全量数据拉取改为先拉取ID列表,再按需拉取单条数据,减少一次性加载的数据量
- 新增成员变量管理当前层级的ID列表和加载进度
- 拆分加载逻辑为"预加载ID"和"加载单题"两个独立方法,实现分步加载
- 将分数计算从加载阶段移到用户提交答案阶段,符合交互逻辑
- 新增下一题触发逻辑,控制逐个加载的流程
内容的提问来源于stack exchange,提问作者Alya Rahmawati
相关产品推荐
相关产品推荐

