【问题标题】:Unity Networking | Authority issue - players can move but not shoot independently统一网络 |权限问题 - 玩家可以移动但不能独立射击
【发布时间】:2019-12-16 18:45:15
【问题描述】:

我正在使用 Unet 制作多人游戏。目前,玩家可以独立移动(即,如果用户一按 d,则角色一将向右移动,如果用户二按 d,则角色二将向右移动) - 但是,两个玩家都“穿过”主机。

我的移动代码在 PlayerUnit 脚本中。它在顶部有一个!isLocalPlayer 检查,在Update() 方法中。此检查在脚本检测到用户输入(即 w、s、mouse1 等)之前执行。

当按下正确的键时,一切正常;执行了适当的操作。 例如:

if (Input.GetKeyDown(up))
    Jump();

拍摄的工作方式略有不同,因为它涉及不同的脚本。

当 mouse1 被按下时,PlayerUnit 中的Shoot() 方法被调用。这反过来又在 PlayerUnit 脚本中使用 Command 在单独的 WeaponMaster 脚本中调用 ClientRpc,该脚本调用 Fire() 协程。

在 PlayerUnit 中:

private void Shoot ()
{   
    //WeaponMaster.wM.Shoot();
    CmdShoot();

}

[Command]
void CmdShoot ()
{
    WeaponMaster.wM.RpcShoot();
}

在武器大师中:

[ClientRpc]
public void RpcShoot ()
{
    if (ammo != 0)
    {
        if (isAutomatic == true)
        {
            keepFiring = true;
            StartCoroutine(Fire());
        }

        if (isAutomatic == false && noQuickFire == true)
           StartCoroutine(Fire());
    }
}

WeaponMaster 也有一个 !isLocalPlayer 检查,同样是在 Update() 方法中。

调试时,我知道playerTwo的(客户端)Shoot()方法正在被调用,但是playerOne的RpcShoot正在被执行。当playerOne 射击时一切正常 - 因此两个玩家都“穿过”主机射击的问题。

所有脚本都在同一个对象上,带有一个NetworkIdentity 组件。

我确信问题只是缺少权限检查 - 但我尝试在各种方法中添加 !isLocalPlayer 测试无济于事。

【问题讨论】:

  • 您可以为上下文添加更多代码吗?就像你描述的你在哪里以及如何使用isLocalPlayer 等等。还有Fire 到底在做什么?
  • WeaponMaster.wM.RpcShoot(); 看起来也很像单例模式,所以我猜你只是将错误的引用分配给 wM 字段?
  • 或者换句话说,因为你通过服务器..不会总是拍摄相同的对象,因为在服务器上它总是在wM..中的相同引用?跨度>
  • @derHugo 你所说的关于单例的说法是有道理的。所以,我只需要以不同的方式致电RpcShoot - 即使用GetComponent<>?我回家后会添加更多上下文,我现在不在电脑旁。
  • 是的,绝对可以在PlayerUnit 中使用GetComponent 或直接使用[SerializeField] private WeaponMaster weaponMaster;,并在那里引用相应的own WeaponMaster 组件。然后,我通常会将每个 ClientRPC 留在也调用它的类中,以便更好地查找和维护

标签: c# unity3d networking


【解决方案1】:

正如我所说的,我的猜测是 WeaponMaster.wM 中的单例模式在这里不是一个好方法,因为你得到了错误的引用,并且因为无论谁调用 CmdShoot,一切都通过服务器可能总是得到相同的引用。


您应该存储每个玩家自己的 WeaponMaster 参考并像在PlayerUnit 中一样浏览它

// Already reference this via the inspector (drag&drop)
[SerializeField] private WeaponMaster weaponMaster;

// or as fallback get it on runtime
private void Awake()
{
    if(!weaponMaster) weaponMaster = GetComponent<WeaponMaster>();
}

public void Shoot ()
{  
    if(!isLocalPlayer) return;

    CmdShoot();
}

[Command]
private void CmdShoot ()
{
    RpcShoot();
}

// Personally in general I would leave any RPC
// as close to the method calling it
// as possible for better maintainability
[ClientRpc]
private void RpcShoot ()
{
    weaponMaster.Shoot();
}

相应地在WeaponMaster

public void Shoot()
{
    if (ammo == 0) return;

    if (isAutomatic)
    {
        keepFiring = true;
        StartCoroutine(Fire());
    }
    else if (!isAutomatic && noQuickFire)
        StartCoroutine(Fire());
}

【讨论】:

  • 太棒了——我什至没有意识到我在使用单例,所以我做了一些阅读,现在对所有问题的理解都更加深刻了。谢谢大佬,祝你好运。
猜你喜欢
  • 2023-01-02
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多