Unity网络项目优化:权限移交后执行带不定参数的委托函数
解决方案:用Action+Lambda封装权限请求与动态回调
你的核心需求是把「请求权限+执行后续函数」的逻辑封装起来,支持任意参数的后续函数,原来的固定参数委托确实没法满足,不过咱们可以用Action结合Lambda表达式的闭包特性来解决,同时还能替换掉不可靠的WaitForSeconds,改用监听权限状态的方式。
第一步:重构NetworkIDRequest类
首先咱们把你的NetworkIDRequest改写成通用的权限请求工具,去掉原来的固定委托,改成接受Action回调,同时用更可靠的方式等待权限移交:
using System; using System.Collections; using UnityEngine; using Mirror; public class NetworkIDRequest : NetworkBehaviour { public static NetworkIDRequest instance; private void Awake() { // 初始化单例(替换你原来的Start里的单例逻辑) if (instance == null) instance = this; else Destroy(gameObject); } /// <summary> /// 请求目标对象的网络权限,获得权限后执行回调 /// </summary> /// <param name="identity">要请求权限的NetworkIdentity</param> /// <param name="onAuthorityGained">获得权限后执行的回调</param> public void RequestAuthorityWithCallback(NetworkIdentity identity, Action onAuthorityGained) { // 只有本地玩家能发起权限请求,避免错误调用 if (!isLocalPlayer) return; StartCoroutine(WaitForAuthorityCoroutine(identity, onAuthorityGained)); } private IEnumerator WaitForAuthorityCoroutine(NetworkIdentity identity, Action onAuthorityGained) { // 发送权限请求命令 CmdRequestNetworkAuthority(identity); // 等待权限移交,同时加超时防止无限等待 float timeout = 2f; float startTime = Time.time; while (!identity.hasAuthority && Time.time - startTime < timeout) { yield return null; // 每帧检查一次权限状态 } if (identity.hasAuthority) { // 权限到手,执行回调 onAuthorityGained?.Invoke(); } else { Debug.LogWarning($"超时:未能获取{identity.name}的网络权限"); } } [Command] private void CmdRequestNetworkAuthority(NetworkIdentity identity) { identity.AssignClientAuthority(connectionToClient); } }
第二步:简化你的CornerSpawnRequest调用
现在你原来的CornerSpawnRequest可以简化成一行代码,用Lambda表达式把需要的参数“打包”进回调里,不管后续函数有多少参数都能搞定:
public void CornerSpawnRequest(Vector3 spawnPosition, GameObject joinToObject) { NetworkIdentity targetIdentity = GetComponent<NetworkIdentity>(); // 直接调用封装好的方法,用Lambda捕获参数并执行后续逻辑 NetworkIDRequest.instance.RequestAuthorityWithCallback(targetIdentity, () => { NetworkCornerSpawn(spawnPosition, joinToObject); }); } [Command] private void NetworkCornerSpawn(Vector3 spawnPosition, GameObject joinToObject) { CornerSpawnExecution(spawnPosition, joinToObject); }
为什么这个方案好用?
- 解决参数不定的问题:Lambda表达式可以捕获外部的任意变量,不管你后续要执行的函数是1个参数还是5个参数,都能直接在Lambda里调用,不需要定义各种不同参数的委托。
- 消除冗余代码:以后任何地方需要“请求权限+执行函数”的逻辑,只需要调用
RequestAuthorityWithCallback,传入目标NetworkIdentity和对应的Lambda回调就行,不用再写重复的协程和等待逻辑。 - 更可靠的权限等待:替换原来的
WaitForSeconds(0.1f)为监听hasAuthority状态,避免因为网络延迟导致权限还没移交就执行代码的问题,同时加了超时逻辑防止无限等待。
额外注意点
- 确保
NetworkIDRequest的单例正确初始化(我用Awake实现了标准单例,你可以替换成你原来的逻辑)。 - 只有本地玩家能发起权限请求,所以加了
!isLocalPlayer的判断,避免非本地玩家调用出错。
内容的提问来源于stack exchange,提问作者BjornGit
相关产品推荐
相关产品推荐

