Я пытаюсь уничтожить конкретный объект одним щелчком мыши. Я использую Unity MLAPI 0.1.0. Когда я создаю объект (SpawnPuzzlePieceServerRpc), я сохраняю его сетевой идентификатор в NetworkVariable. Затем объект следует за курсором мыши (MakeActivePuzzlePieceFollowMouseServerRpc). После этого, если я нажму 1 кнопку мыши, я хочу, чтобы этот порожденный объект был уничтожен. Метод (DeleteActivePuzzlePieceServerRpc) уничтожает объект как на хосте, так и на клиенте, однако метод продолжает вызываться по какой-то причине и выдает исключение KeyNotFoundException: данный ключ отсутствует в словаре. NetworkVariable (activePuzzlePieceNetId) кажется обновленным до 0 (из-за постоянно генерируемой ошибки), поэтому метод не следует вызывать снова из-за условия в Update (). Похоже, что NetworkVariable здесь не синхронизируется правильно. В чем может быть проблема и что я делаю не так?

Заранее спасибо,

using UnityEngine;
using MLAPI;
using MLAPI.Messaging;
using MLAPI.Spawning;
using MLAPI.NetworkVariable;

public class PlayerTest : NetworkBehaviour
{
    [SerializeField] Transform[] puzzlePiecePrefabs;
    NetworkVariable<ulong> activePuzzlePieceNetId = new NetworkVariable<ulong>(0);

    void Start()
    {
        activePuzzlePieceNetId.Settings.ReadPermission = NetworkVariablePermission.Everyone;
        activePuzzlePieceNetId.Settings.WritePermission = NetworkVariablePermission.Everyone;
    }

    void Update()
    {
        if (!IsLocalPlayer) return;

        if (!activePuzzlePieceNetId.Value.Equals(0))
        {
            if (Input.GetMouseButtonDown(1))
            {
                DeleteActivePuzzlePieceServerRpc();
            }
            else
            {
                MakeActivePuzzlePieceFollowMouseServerRpc();
            }
        }
    }

    [ServerRpc]
    void DeleteActivePuzzlePieceServerRpc()
    {
        NetworkObject puzzlePiece = NetworkSpawnManager.SpawnedObjects[activePuzzlePieceNetId.Value];
        Destroy(puzzlePiece.gameObject);
        activePuzzlePieceNetId.Value = 0;
    }

    [ServerRpc]
    public void SpawnPuzzlePieceServerRpc(int puzzlePieceId)
    {
        Transform puzzlePiece = Instantiate(puzzlePiecePrefabs[puzzlePieceId]);
        puzzlePiece.GetComponent<NetworkObject>().SpawnWithOwnership(OwnerClientId);
        activePuzzlePieceNetId.Value = puzzlePiece.GetComponent<NetworkObject>().NetworkObjectId;
        SpawnPuzzlePieceClientRpc();
    }

    [ClientRpc]
    void SpawnPuzzlePieceClientRpc()
    {
    }

    [ServerRpc]
    void MakeActivePuzzlePieceFollowMouseServerRpc()
    {      
        MakeActivePuzzlePieceFollowMouseClientRpc();
    }

    [ClientRpc]
    void MakeActivePuzzlePieceFollowMouseClientRpc()
    {
        NetworkObject puzzlePiece = NetworkSpawnManager.SpawnedObjects[activePuzzlePieceNetId.Value];
        puzzlePiece.transform.position = GetMousePositionInWorld();
    }

    Vector3 GetMousePositionInWorld()
    {
        var mousePos = Input.mousePosition;
        mousePos.z = 19;
        return Camera.main.ScreenToWorldPoint(mousePos);
    }
}
-1
Paulius Petrauskas 22 Окт 2021 в 19:25
Что ж, MakeActivePuzzlePieceFollowMouseServerRpc() вызывается в каждом кадре, где !activePuzzlePieceNetId.Value.Equals(0) и !Input.GetMouseButtonDown(1) ... Вы пробовали отладку, если ваше значение установлено правильно? Также обратите внимание, что в любом случае будет некоторая задержка до тех пор, пока 0 не вернет вас ... тем временем каждый клиент рассылает серверу спам с MakeActivePuzzlePieceFollowMouseServerRpc() в каждом кадре ...
 – 
derHugo
22 Окт 2021 в 20:11
Это может быть задержка, потому что при отладке отображается правильное значение, поэтому этого не должно происходить. Я исправил это сейчас, просто добавив блок try / catch и таким образом выйдя из функции. Но я не думаю, что это нормально.
 – 
Paulius Petrauskas
22 Окт 2021 в 21:01
В общем, отправлять RPC каждый кадр - это совсем не хорошо.
 – 
derHugo
22 Окт 2021 в 21:38

1 ответ

Лучший ответ

Я не думаю, что вы можете использовать NetworkVariable в скрипте, унаследованном от MonoBehaviour. Вы должны использовать его в скрипте, унаследованном от NetworkBehaviour, и добавить компонент NetworkObject к игровому объекту, которому принадлежит скрипт. Вы должны сначала убедиться, что этот сетевой объект порождается по сети, чтобы использовать внутри него NetworkVariable.

На самом деле, вам не нужно использовать NetworkVariable для создания и уничтожения объектов в сети.

Если вы хотите создать префаб, вы можете использовать серверный RPC, чтобы создать его на стороне сервера.

// Keep a reference to the prefab instance so you can destroy it later.
private NetworkObject m_PrefabInstance;

[ServerRpc]
private void SpawnPrefabServerRpc() 
{
    m_PrefabInstance = Instantiate(yourPrefab);
    prefabInstance.SpawnWithOwnership(OwnerClientId);
}

И когда вы хотите уничтожить префаб, вам нужно только уничтожить его на стороне сервера, и он будет автоматически уничтожен на всех клиентах.

[ServerRpc]
private void DestroyPrefabServerRpc()
{
    Destroy(m_PrefabInstance);
}
0
yuchen 1 Ноя 2021 в 10:59