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

Unity中C#协程异步加载SQL数据需两次点击的解决问询

解决Unity中SQL存档加载需点击两次按钮的问题

这是典型的异步操作时序问题——你的Load方法启动了一个协程去执行HTTP请求,但协程是异步运行的,你在调用Load后立刻检查LoadedData,这时候请求还没完成,数据自然还没赋值,所以第一次点击没效果;第二次点击时,之前的协程已经跑完,数据才存在。

下面给你几种直接有效的解决方案,按推荐程度排序:

方案1:使用回调函数(最直接)

修改SavingLoading脚本,让加载完成后触发回调,把数据处理逻辑放在回调里,确保只有数据加载完成才执行赋值:

// 修改SavingLoading中的Load和LoadCall方法
public void Load(string name, Action<string> onLoaded) { 
    StartCoroutine(LoadCall(name, onLoaded)); 
} 

IEnumerator LoadCall(string name, Action<string> onLoaded) { 
    WWWForm form = new WWWForm(); 
    form.AddField("name", name); 
    WWW www = new WWW(LoadPhP, form); 
    yield return www; 

    // 新增:处理网络请求错误
    if (!string.IsNullOrEmpty(www.error)) {
        Debug.LogError($"加载数据失败:{www.error}");
        onLoaded?.Invoke("");
        yield break;
    }

    string _return = www.text; 
    LoadedData = _return; 
    // 数据加载完成后触发回调
    onLoaded?.Invoke(_return);
}

然后修改你的loadData方法,把赋值逻辑移到回调中:

public void loadData() { 
    var savingLoading = GetComponent<SavingLoading>();
    string username = GameObject.Find("LoginSystem").GetComponent<LoginSystem>().Username;
    
    savingLoading.Load(username, (loadedData) => {
        if (!string.IsNullOrEmpty(loadedData)) { 
            string[] Data = loadedData.Split(','); 
            Level = Convert.ToInt32(Data[0]); 
            CurrentXp = Convert.ToInt32(Data[1]); 
            currentHealth = Convert.ToInt32(Data[2]); 
            maxHealth = Convert.ToInt32(Data[3]); 
            Vector3 LoadedPos = new Vector3(Convert.ToSingle(Data[4]), Convert.ToSingle(Data[5]), Convert.ToSingle(Data[6])); 
            transform.position = LoadedPos; 
        } 
    });
}

这样点击一次按钮,就能在请求完成后自动执行数据赋值了。

方案2:将loadData改为协程

如果习惯用协程的方式等待异步操作,可以把loadData改成协程,直接等待LoadCall完成:

// 修改loadData为协程
public IEnumerator loadData() { 
    var savingLoading = GetComponent<SavingLoading>();
    string username = GameObject.Find("LoginSystem").GetComponent<LoginSystem>().Username;
    
    // 等待LoadCall协程执行完毕
    yield return savingLoading.LoadCall(username);

    if (!string.IsNullOrEmpty(savingLoading.LoadedData)) { 
        string[] Data = savingLoading.LoadedData.Split(','); 
        Level = Convert.ToInt32(Data[0]); 
        CurrentXp = Convert.ToInt32(Data[1]); 
        currentHealth = Convert.ToInt32(Data[2]); 
        maxHealth = Convert.ToInt32(Data[3]); 
        Vector3 LoadedPos = new Vector3(Convert.ToSingle(Data[4]), Convert.ToSingle(Data[5]), Convert.ToSingle(Data[6])); 
        transform.position = LoadedPos; 
    } 
}

注意:此时按钮的点击事件不能直接调用loadData,需要改成启动协程:

// 在按钮绑定的方法中写
StartCoroutine(loadData());

额外建议

  • 尽量避免频繁调用GetComponent和GameObject.Find,可以提前缓存这些引用,提升性能。
  • 对分割后的数组做长度检查,避免因返回数据格式错误导致索引越界崩溃。

内容的提问来源于stack exchange,提问作者pvtctrlalt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:28:52