Unity: Как уничтожить игровой объект через сеть? - PullRequest
0 голосов
/ 06 ноября 2018

Мы строим стратегическую игру в реальном времени на Unity и пытаемся уничтожить игровые объекты на сервере и клиентах по сети. В настоящее время игрок всегда может уничтожить свои собственные объекты, а сервер может уничтожить все объекты. Но когда клиент пытается уничтожить объекты сервера (или других клиентов), он уничтожается только на этом клиенте. (Так как клиент не имеет ни Authority, ни объекта isLocalPlayer)

Мы пробовали разные подходы:

1. Использование Destroy (gameObject)

Это, очевидно, не сработает, поскольку уничтожается только локально.

2. Использование NetworkServer.Destroy (gameObject)

Это терпит неудачу, поскольку у нас нет полномочий.

3. Использование команды для уничтожения объекта

В тот момент, когда мы пытаемся вызвать на сервере команду, в которой мы уничтожаем объект, также происходит сбой. В связи с проверкой полномочий:

Попытка отправить команду для объекта без полномочий.

4. Первое назначение полномочий

Мы пытались назначить полномочия через GetComponent<NetworkIdentity>().AssignClientAuthority(connectionToClient); но получите сообщение об ошибке:

AssignClientAuthority можно вызывать на сервере только для порожденных объектов.

Попытка сделать это в Команде потерпит неудачу из-за пункта 3.

Существуют ли другие возможности уничтожения игровых объектов? Как можно уничтожить игровые объекты?

Редактировать: Мы породили большинство объектов во время выполнения (в команде) через NetworkServer.SpawnWithClientAuthority или NetworkServer.Spawn

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Несмотря на то, что UNet скоро закончится (как уже упоминалось в Draco18s), пока я бы сделал это:

  1. Добавьте NetworkIdentity к GameObject, который вы хотите уничтожить / идентифицировать по сети.

  2. Если это префаб, который вы породили, убедитесь, что он добавлен в порождаемые префабы в NetworkManager

  3. Поскольку объект локального игрока всегда имеет полномочия над собой, и компоненты, прикрепленные к нему, добавляют вызов [Command] к компоненту для объекта локального игрока (не для целевых объектов GameObjects) и используйте NetworkServer.Destroy например что-то вроде

    public class NetworkObjectDestroyer : NetworkBehaviour
    {
        // Called by the Player
        [Client]
        public void TellServerToDestroyObject(GameObject obj)
        {
            CmdDestroyObject(obj);
        }
    
        // Executed only on the server
        [Command]
        private void CmdDestroyObject(GameObject obj)
        {
            // It is very unlikely but due to the network delay
            // possisble that the other player also tries to
            // destroy exactly the same object beofre the server
            // can tell him that this object was already destroyed.
            // So in that case just do nothing.
            if(!obj) return;
    
            NetworkServer.Destroy(obj);
        }
    }
    

    Подсказка: вы также можете добавить это для более легкого доступа, поскольку вы уверены, что вам нужен только доступ только к одному из этих компонентов (а именно к вашему локальному проигрывателю):

    public static NetworkObjectDestroyer Instance;
    
    private void Awake()
    {
        // skip if not the local player
        if(!isLocalPlayer) return;
    
        // set the static instance
        Instance = this;
    }
    
  4. Чем позже где-нибудь в вашем другом скрипте, который должен выполнить уничтожение, вы делаете что-то вроде

    // that you would have to get somewhere if not anyway 
    // calling from a component of the local player object
    GameObject playerObject;
    
    // wherever you get your target object from
    GameObject targetObject;
    
    playerObject.GetComponent<NetworkObjectDestroyer>().TellServerToDestroyObject(targetObject);
    

    Будет проще, если вы ранее добавили статический экземпляр. Чем вы можете просто использовать

    NetworkObjectDestroyer.Instance.TellServerToDestroyObject(targetObject);
    

    без необходимости сначала получать ссылки.

0 голосов
/ 09 ноября 2018

прямо из документов Unity:

Местная власть Локальные полномочия (иногда называемые полномочиями клиента) означают, что локальный клиент имеет полномочный контроль над конкретным сетевым GameObject. Это отличается от состояния по умолчанию, которое заключается в том, что сервер обладает полномочным контролем над сетевыми объектами GameObjects.

В дополнение к isLocalPlayer **** вы можете выбрать, чтобы игрок GameObjects имел «местные полномочия». Это означает, что игрок GameObject на клиенте своего владельца несет ответственность (или имеет полномочия) за себя. Это особенно полезно для управления движением; это означает, что каждый клиент имеет полномочия по контролю над собственным игроком GameObject.

Чтобы включить полномочия локального игрока для GameObject, отметьте компонент Network Identity. Флажок Local Authority Authority. Компонент Network Transform использует этот параметр «полномочия» и отправляет информацию о перемещении от клиента другим клиентам, если этот параметр установлен.

См. Справочную документацию по API сценариев для NetworkIdentity. и localPlayerAuthority для получения информации о реализации полномочий локального игрока с помощью сценария.

см. Здесь

вам просто нужно настроить несколько вещей, и вам будет хорошо!

0 голосов
/ 06 ноября 2018

Как насчет использования (1) и настройки каждого клиента на управление своими игровыми объектами? Тогда все, что вам нужно, - это чтобы каждый клиент был уведомлен сервером о конкретных событиях.

Здесь - это более открытый вопрос о мультиплеере, который описывает, как он будет работать вручную. заставляя клиентов слушать серверные сообщения / RPC.

...