2016-03-22 6 views
1

У меня странная проблема с DontDestroyOnLoad. У меня есть карта как стартовая сцена. Оттуда пользователь может щелкнуть по определенным объектам карты, а новый уровень будет загружен Application.LoadLevel() Когда уровень будет завершен, карта будет загружена снова. Но объекты с прикрепленным DontDestroyOnLoad дублируются при втором загрузке.Дубликаты из-за DontDestroyOnLoad()

Текущий сценарий:

void Awake() 
{ 
    DontDestroyOnLoad(transform.gameObject); 
} 

Я искал в Интернете и нашел возможное решение для удаления дубликатов:

public class NoDestroy : MonoBehaviour { 

    public static NoDestroy instance; 

    void Awake() 
    { 
     if (instance == null) 
     { 
      instance = this; 
     } 
     else 
     { 
      Destroy(this.gameObject); 
      return; 
     } 

     DontDestroyOnLoad(this.gameObject); 

    } 
    } 

выше сценарий просто не работает. Как я могу исправить проблему?

+0

Никогда, никогда не применяйте статику в Единстве. *** это не система OO, это ECS. *** никогда не используйте «это» ключевое слово в Unity, если вы это делаете, вы делаете что-то совершенно неправильное. *** это не система OO, это ECS. *** http://stackoverflow.com/a/35723305/294884 – Fattie

+0

(хех) Обратите внимание, что «технически абсолютно невозможно» «удалить дубликаты» (по крайней мере, не внутри, так что это конец) - вы часто видите нелепые примеры кода в Интернете, где люди пытаются «удалить дубликаты», чтобы сделать ситуацию, как в OO, где у вас «что-то вроде одиночного». ECS совершенно иная. – Fattie

ответ

1

Поскольку вышеуказанный скрипт использует static экземпляра, он будет работать, только если `одного GameObject прилагается еще это - еще хуже, он будет удалять других объектов, которые пытаются использовать такое же поведение.

Самая большая проблема заключается в том, что всякий раз, когда вы загружаете сцену, все объекты в этой сцене загружаются. Если они не были выгружены (спасибо DontDestroyOnLoad), они будут дублированы, так как сцена не знает, что они «уже существуют»

Приведенный выше сценарий может работать лучше, если вы попытаетесь поместить ваши постоянные объекты под зонтик, и только зонтичный объект (обычно называемый Toolbox) не разрушается. Однако это в основном подходит для сценариев администратора.

Если вы знаете объекты, которые не предназначены для уничтожения, попробуйте загрузить их через сцену «Загрузка». Поскольку это перемещает постоянные объекты из вашей сцены карты, они не будут дублироваться при перезагрузке сцены карты. Бонус к этому шаблону, поскольку он упрощает реализацию занавеса.

Если вы хотите реализовать это в качестве простого поведенческого сценария, рассмотрите возможность добавления идентификатора, как так

public class NoDestory : MonoBehaviour 
{ 
    private static Dictionary<string, GameObject> _instances = new Dictionary<string, GameObject>(); 
    public string ID; // HACK: This ID can be pretty much anything, as long as you can set it from the inspector 

    void Awake() 
    { 
     if(_instances.ContainsKey(ID)) 
     { 
      var existing = _instances[ID]; 

      // A null result indicates the other object was destoryed for some reason 
      if(existing != null) 
      { 
       if(ReferenceEquals(gameObject, existing) 
        return; 

       Destroy(gameObject); 

       // Return to skip the following registration code 
       return; 
      } 
     } 

     // The following code registers this GameObject regardless of whether it's new or replacing 
     _instances[ID] = gameObject; 

     DontDestroyOnLoad(gameObject); 
    } 
} 

Это позволит предотвратить дублирование объекта с тем же ID значение, как тот, который уже существует, а как разрешение на отдых, если указанный объект был Destory - в другом месте. Это можно дополнительно уточнить, добавив специальный скрипт редактора для передачи нового ID каждый раз, когда скрипт будет реализован.

+0

Спасибо за ваш ответ, но ваш скрипт просто разрушает объект, когда я переключаюсь на новый уровень. Почему вы не используете 'DontDestroyOnLoad (transform.gameObject);' где-нибудь в коде? –

+0

Отредактировано - это должно помешать системе увидеть себя как столкновение, которое может возникнуть, если вызов «Awake» вызывается дважды – David

+0

Обратите внимание на TODO в конце - я не ввел его, так как предположил, что вы будете использовать это вместе с вашим существующим сценарием 'DontDestroyOnLoad'. Если это не так, замените строку 'TODO ~ на вызов в вашем примере – David

Смежные вопросы