Создание префаба без наследования монобихиорации - PullRequest
2 голосов
/ 15 мая 2019

Я пытаюсь сделать основной сценарий для игры, которую я делаю в Unity 3D.

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

class Main
{
    public GameObject ship;

    [RuntimeInitializeOnLoadMethod]
    static void OnRuntimeMethodLoad()
    {
        GameObject player = Object.Instantiate (ship, transform.position, Quaternion.identity) as GameObject;
    }
}

Однако, это дает мне ошибку: An Object Reference is Required for non-static field, method, or property 'Main.Ship' Можно ли создать экземпляр объекта без наследования MonoBehaviour?

Ответы [ 2 ]

2 голосов
/ 15 мая 2019

Как объяснялось в предыдущих ответах, вы смешиваете экземплярную область и классовую (статическую) область.

Хотя было упомянуто несколько методов, которые могут привести к тому, что этот скрипт будет работать так, как вы его запустили (вы можете использовать статический класс Resources для поиска ресурсов по имени файла), я хотел бы предложить сделать это наоборот. и сделать ваш класс MonoBehaviour. Хотя это может показаться нелогичным для людей, которые закодировали в c и предпочитают иметь четкую точку входа в свой код, во многих случаях очень полезно привыкнуть к тому, что вам нужно добавить GameObject, который будет содержать ваш основной сценарий где-то.

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

class ShipInstanceCreator: MonoBehaviour
{
    public GameObject ship;

    void Start()
    {
       GameObject player = Object.Instantiate (ship, transform.position,   transform.rotation) as GameObject;
   }

Каковы преимущества? Первое и главное преимущество заключается в том, что все, что унаследовано от MonoBehaviour, получает полную поддержку от UnityEditor - так что вы получаете бесплатные окна «Инспектор», где вы можете перетаскивать вещи, иметь ползунки и т. Д. Бесплатно, вы получаете флажок «включить / отключить» , вы получаете обратные вызовы при изменении состояния включения / выключения, вы получаете локальный компонент преобразования (который часто удивительно полезен), вы получаете коллизии и т. д.

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

Такой сценарий может также создавать экземпляры вражеских кораблей и астероидов (в своей собственной позиции и ориентации трансформации), и поскольку функциональные различия между ними могут (и должны) быть реализованы как поведения, характерные для данного префаба, для вашего экземпляра нет необходимости класс, чтобы узнать что-либо еще о том, что он создает, кроме того, который должен быть GameObject

Наконец, в хорошо написанном проекте Unity редко встречается «основной» класс. Лучше всего, если вы разделите ответвления на отдельные компоненты, с минимально возможными зависимостями между ними (зависимость от UnityEngine - это нормально). Вместо «написания основного сценария» вы должны написать «InstantiatePlayerScript», и вполне возможно, что это почти сделано, и вы можете перейти к написанию другого сценария, который определит другое поведение. Вот почему их называют поведением. Инстанцирование игрока - это поведение, которое изменяет сцену, и оно должно жить на сцене как другие объекты, а не пытаться «сидеть на облаке» как божественный объект, контролируя все сверху и снизу. Хотя написать такую ​​игру абсолютно возможно, этот путь становится все сложнее по мере роста сложности.

Есть некоторые части игры, которые можно сделать глобальными (например, MusicManager - есть только одна музыка, которую вы должны играть одновременно), но для таких вещей, как проигрыватель - что если однажды вы захотите сделать игровой мультиплеер? Хотя Singleton Pattern (он же где-то пишет основной класс) хорошо работает для многих вещей в Unity, его очень легко переусердствовать.

2 голосов
/ 15 мая 2019

Вы используете нестатическое значение в статическом методе, и это недопустимо.

Вы должны либо удалить статическое значение из метода:

void OnRuntimeMethodLoad()

, либо добавить статическое вполе:

public static GameObject ship;

СООБРАЖЕНИЯ

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

Вам нужно будет либо внедрить их с помощью другого скрипта, либо собрать их из ресурсов, либо создать их внутри класса Main.

INJECTION

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

Это можно сделать с помощью методов Scriptable Object OnDisable или OnEnable.

OnEnable() { Main.ship = something }

В любом случае, я бы посоветовал против этого, потому что вы не знаете, когда будет вызван скрипт.
С RuntimeInitializeOnLoadMethod - Unity

Примечание.EXEПорядок следования методов, помеченных [RuntimeInitializeOnLoadMethod], не гарантируется.

СБОР ИЗ РЕСУРСОВ

Это, вероятно, самое простое решение.

Вы можете собрать префаб из Папка ресурсов

//Load a gamobject file (Assets/Resources/GameObjects/ship.prefab)
ship = Resources.Load<GameObject>("GameObjects/ship");

СОЗДАТЬ В ГЛАВНОМ КЛАССЕ

Наконец, вы можете напрямую создать корабль в главном классе.

Код будет выглядеть следующим образом:

void CreateShip()
{
   ship = new GameObject();
   var shipComponent = ship.AddComponent<ComponentToAdd>();
   shipComponent.Setup();
   //add any other components
}

ЗАКЛЮЧЕНИЕ

Вы всегда можете вернуться и вернуться с помощью другого более простого решения, например, вызова кода внутри MonoBehaviour.

Если вам нужен менеджер, выможет использовать синглтон , такой как этот .

Если вы подтвердите, что хотите использовать RuntimeInitializeOnLoadMethodit, я бы предложил продолжить с решением для ресурсов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...