等待TestName不等于"NoName"的协程未生效问题排查
问题分析与解决方案
核心问题
- 协程启动后不会阻塞主线程:调用
StartCoroutine(StartTask())后,代码立刻执行Leaders += (TestName + "\n"),此时TestName还未被服务器返回值更新,仍为"NoName"。 - 全局变量
TestName存在竞态条件:循环下一次迭代会立刻将TestName重置为"NoName",导致之前启动的协程要么永远等不到有效名称,要么拿到错误的玩家名称。
修复方案
重构代码,让每个玩家的名称获取逻辑独立,并在循环中等待当前玩家的名称返回后再处理下一个,避免全局变量冲突和异步时序问题。
步骤1:改造GetPlayerProfile,添加回调参数
确保GetPlayerProfile能在获取到名称后通知调用方(适配PlayFab的异步回调模式):
void GetPlayerProfile(string playFabId, Action<string> onNameReceived) { var request = new GetPlayerProfileRequest { PlayFabId = playFabId, ProfileConstraints = new PlayerProfileViewConstraints { ShowDisplayName = true // 明确请求获取玩家昵称 } }; PlayFabClientAPI.GetPlayerProfile(request, result => { // 成功获取昵称后触发回调 onNameReceived(result.PlayerProfile.DisplayName); }, error => { // 请求失败时返回默认名称并打印错误 Debug.LogError($"获取玩家 {playFabId} 昵称失败: {error.ErrorMessage}"); onNameReceived("NoName"); }); }
步骤2:将OnLeaderboardGet改为协程,逐个处理玩家
把同步循环改成异步协程,确保每个玩家的名称返回后再拼接进Leaders:
private string Leaders = ""; IEnumerator OnLeaderboardGet(GetLeaderboardResult result) { Leaders = string.Empty; // 清空原有内容 foreach (var item in result.Leaderboard) { string currentPlayerName = "NoName"; bool isNameFetched = false; // 发起昵称请求,拿到结果后更新局部变量 GetPlayerProfile(item.PlayFabId, name => { currentPlayerName = name; isNameFetched = true; }); // 等待当前玩家的昵称返回 yield return new WaitUntil(() => isNameFetched); // 昵称就绪后添加到结果字符串 Leaders += $"{currentPlayerName}\n"; } // 所有玩家处理完成后再打印完整结果 Debug.Log(Leaders); }
方案有效性说明
- 用局部变量存储每个玩家的昵称和请求状态,避免全局变量的竞态问题,每个玩家的请求互不干扰。
- 协程的
yield return会暂停当前循环迭代,直到昵称获取完成,确保Leaders拼接的是已更新的有效名称。 - 所有玩家处理完成后才打印
Leaders,保证输出的是完整的排行榜数据。
内容的提问来源于stack exchange,提问作者Ilya
相关产品推荐
相关产品推荐

