Unet Syncing вес слоя аниматора Unity 3D

Сейчас я работаю над многопользовательским fps, чтобы изучить UNET и Unity. в этом проекте я использую компонент Network Animator для синхронизации анимации.
У меня есть один слой, который выполняет обычные состояния, такие как ходьба и прыжки, а другой - просто контролирует верхнюю часть тела для определения объема. Этот слой активируется при наведении.

Параметры синхронизации прекрасны, но не вес слоя. Скрипт, который контролирует вес слоя, отключается на удаленном плеере, поскольку он является частью того же скрипта, который заботится о стрельбе, и мы не хотим стрелять с удаленного плеера. Поэтому я поместил этот код в другой скрипт и сделал Layerweight Syncvar, но результатов все равно не было.

это фрагмент, который устанавливает вес и уменьшает его.

    if (isScoped)
    {
        animator.SetLayerWeight(1, 1);
        layerWeight = 1;
    }
    else
    {
        layerWeight = Mathf.Lerp(layerWeight, 0, 0.1f);
        animator.SetLayerWeight(1, layerWeight);
    }

    animator.SetBool("Scoped", isScoped);

как я могу синхронизировать переменную, которая обновляется в отключенном скрипте? И какие различные настраиваемые атрибуты, такие как [Command] и [ClientRpc], я должен использовать, чтобы это работало?
Я читал документацию и руководства по UNET, но с трудом справляюсь с этой относительно простой задачей, так как у меня Трудно понять разницу этих звонков.


person Tarek Auf der Strasse    schedule 04.03.2020    source источник
comment
Почему бы вам вместо отключения всего сценария отключить только метод Shoot с помощью флага? (if(!IsLocalAuthority) return;)   -  person derHugo    schedule 06.03.2020


Ответы (1)


Как правило, основная проблема с [SyncVar] заключается в том, что они

синхронизировано с сервера на клиентов

так что не наоборот!


потом

[Command] - это метод, который вызывается любым клиент, но выполняется только на сервере

[ClientRpc] - это нечто противоположное, это вызывается сервером, а затем выполняется на всех клиентах

так что я бы сделал метод установки для веса слоя, например

private void SetLayerWeight(float value)
{
    // only player with authority may do so
    if(!isLocalPlayer) return;

    // Tell the server to update the value
    CmdSetLayerWeight(value);
}

[Command]
private void CmdSetLayerWeight(float value)
{
    // Server may now tell it to all clients
    RpcSetLayerWeight(value);
}

[ClientRpc]
private void RpcSetLayerWeight(float value)
{
    // called on all clients including server
    layerweight = value;
    animator.SetLayerWeight(1, layerweight);
}

и назовите это как

if (isScoped)
{
    SetLayerWeight(1);
}
else
{
    SetLayerWeight(Mathf.Lerp(layerWeight, 0, 0.1f));
}

Однако обратите внимание, что передача этого между сервером и клиентом вызовет некоторую сверхъестественную задержку!

Возможно, вам лучше вместо этого синхронизировать isScoped bool и присвоить значение непосредственно вызывающему клиенту:

private void SetScoped(bool value)
{
    // only player with authority may do so
    if(!isLocalPlayer) return;

    // for yourself already apply the value directly so you don't have
    // to wait until it comes back from the server
    scoped = value;

    // Tell the server to update the value and who you are
    CmdSetLayerWeight(value);
}

// Executed only on the server
[Command]
private void CmdSetLayerWeight(bool value)
{
    // Server may now tell it to all clients
    RpcSetLayerWeight(value);
}

// Executed on all clients
[ClientRpc]
private void RpcSetLayerWeight(bool value)
{
    // called on all clients including server
    // since setting a bool is not expensive it doesn't matter
    // if this is done again also on the client who originally initialized this
    scoped = value;
}
person derHugo    schedule 06.03.2020