You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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数据结构

Firebase数据结构1
Firebase数据结构2
Firebase数据结构3


解决方案

要实现按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 18:15:01