使用 Mirror 在 Unity 中的网络播放器上停止和播放粒子系统

Stop and Play Particle System on Networked Player in Unity using Mirror

我正在尝试播放和停止播放器预制件的子粒子系统。到目前为止,我已经获得了主机客户端的推力粒子效果,可以在所有客户端上进行更新,但我还没有弄清楚非主机客户端。我希望每次玩家按下推进器按钮时,游戏都会在所有客户端上显示推进器效果,当他们停止时粒子系统停止,其他客户端也会看到它。

目前我的代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;

public class PlayerMovement : NetworkBehaviour
{
    public float thrustPower = 300f;
    Rigidbody2D m_playerRb;
    bool m_thrustOn = false;
    public ParticleSystem m_playerPs;

    [SyncVar(hook = nameof(SetThrusters))]
    bool m_thrusterState = false;

    private void Start()
    {
        m_playerRb = GetComponent<Rigidbody2D>();
        m_playerPs.Stop();

    }

    private void Update()
    {
        if (isLocalPlayer)
        {
            MovePlayer();
            m_thrusterState = m_thrustOn;
        }
    }

    private void FixedUpdate()
    {
        if (m_thrustOn)
        {
            m_playerRb.AddForce(gameObject.transform.up * thrustPower * Time.fixedDeltaTime, ForceMode2D.Force);
        }
    }

    private void SetThrusters(bool oldVal, bool newVal)
    {
        if (newVal) m_playerPs.Play();
        else if (newVal == false) m_playerPs.Stop();
    }

    

    private void MovePlayer()
    {
        m_thrustOn = Input.GetKey(KeyCode.W) ? true : false;

        float horizontalInput = Input.GetAxisRaw("Horizontal");

        transform.Rotate(new Vector3(0, 0, horizontalInput * -180 * Time.deltaTime));
    }
}

在粒子系统方面,我真的无法在网上找到任何关于 Mirror 的信息。如果您需要更多信息,请告诉我。

谢谢!

SyncVar 总是只往 HOST -> CLIENT 方向走!


相反,您需要使用 Command

例如

[Command]
void CmdSetSetThrusters(bool newVal)
{
    // the hook would not be executed on the host => do it manually now
    SetThrusters(m_thrusterState, newVal);

    // set it on the host -> now via synVar automatically forwarded to others
    m_thrusterState = newVal;
}

然后您必须添加一个检查您是否是主持人,例如

if (isLocalPlayer)
{
    MovePlayer();

    if(isServer)
    {
        // afaik this you still have to call manually for yourself
        // not sure here how SyncVar Hooks are handled on the host itself
        SetThrusters(m_thrusterState, m_thrustOn);

        // this is now synced to others
        m_thrusterState = m_thrustOn;
    }
    else
    {
        // if your not Host send the command
        CmdSetSetThrusters(m_thrustOn);
    }
}

就我个人而言,出于这个原因,SyncVar 与 Hooks 总是有点令人困惑和怀疑。

您也可以自己简单地实现这两个方向,例如

[Command]
void CmdSetSetThrusters(bool newVal)
{
    // set the value on yourself 
    SetThrusters(newVal);

    // Then directly forward it to all clients
    RpcSetThrusters(newVal);
}

[ClientRpc]
private void RpcSetThrusters(bool newValue)
{
    // set the value on all clients
    SetThrusters(newVal);
}

private void SetThrusters(bool newVal)
{
    if (newVal)
    {
        m_playerPs.Play();
    }
    else 
    {
        m_playerPs.Stop();
    }

    // if you are the HOST forward to all clients
    if(isServer)
    {
        RpcSetThrusters(newVal);
    }
}

然后

if (isLocalPlayer)
{
    MovePlayer();

    if(isServer)
    {
        SetThrusters(m_thrusterState);
    }
    else
    {
        // if your not Host send the command
        CmdSetSetThrusters(m_thrustOn);
    }
}