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

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);
}

为什么这个方案好用?

  1. 解决参数不定的问题:Lambda表达式可以捕获外部的任意变量,不管你后续要执行的函数是1个参数还是5个参数,都能直接在Lambda里调用,不需要定义各种不同参数的委托。
  2. 消除冗余代码:以后任何地方需要“请求权限+执行函数”的逻辑,只需要调用RequestAuthorityWithCallback,传入目标NetworkIdentity和对应的Lambda回调就行,不用再写重复的协程和等待逻辑。
  3. 更可靠的权限等待:替换原来的WaitForSeconds(0.1f)为监听hasAuthority状态,避免因为网络延迟导致权限还没移交就执行代码的问题,同时加了超时逻辑防止无限等待。

额外注意点

  • 确保NetworkIDRequest的单例正确初始化(我用Awake实现了标准单例,你可以替换成你原来的逻辑)。
  • 只有本地玩家能发起权限请求,所以加了!isLocalPlayer的判断,避免非本地玩家调用出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:28:21