Прикрепите камеру к объекту сценария в единстве - PullRequest
0 голосов
/ 17 января 2019

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

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

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/MainCamera", 
order = 1)]
public class MainCamera : ScriptableObject
{
    public Camera Camera;
}

Затем я создал объект сценариев из него в моей папке Assets, как описано здесь: https://docs.unity3d.com/Manual/class-ScriptableObject.html

А теперь я хочу назначить основную камеру этой переменной камеры в инспекторе. Однако в меню выбора отображается только «нет», но нет камеры.

Как мне назначить камеру для переменной камеры в моем объекте сценария?

1 Ответ

0 голосов
/ 17 января 2019

Вы можете , а не напрямую прикреплять ссылки на сцену к ScriptableObject с или фактически к любым активам.

Но вы можете пойти по другому пути: дайте камере ссылку ScriptableObject и заставьте ее указать свою собственную ссылку на это ScriptableObject:

// This attribute makes this classes messages be executed also in editmode
// (= also of not in playmode)
[ExecuteInEditModo]

// Assure there is a Camera component
[RequireComponent(typeof(Camera))]
public class CameraSetter : MonoBehaviour
{
    [SerializeField] private MainCamera mainCameraAsset;

    // Called on initialize
    // With [ExecuteInEditModo] also called on recompile
    private void Awake ()
    {
        mainCameraAsset.Camera = GetComponent<Camera>();
    }
}

И ссылка на ваш MainCamera экземпляр в mainCameraAsset.


Есть ли причина, по которой вы не используете Camera.main вместо ScriptableObject?


Карта для различных сцен

В случае, если вы хотите заархивировать что-то вроде «актива менеджера», хранящего различные ссылки Camera для каждой сцены, как это было запрошено в комментариях (надеюсь, я вас правильно понял), я бы изменил ваш MainCamera на что-то вроде

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

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/MainCamera", 
order = 1)]
public class MainCamera : ScriptableObject
{
    public List<SceneCameraPair> SceneCameraPairs = new List<SceneCameraPair>();

    public Dictionary<string, Camera> sceneToCamera = new Dictionary<string, Camera>();

    public void AddPair(SceneCameraPair pair)
    {
        if(SceneCameraPairs.Contains(pair)) return;

        SceneCameraPairs.Add(pair);
        sceneToCamera[pair.scene.path] = pair.camera;
    }

    public void ResetPairs()
    {
        SceneCameraPairs.Clear();
        sceneToCamera.Clear();
    }
}

[System.Serializable]
public class SceneCameraPair
{
    public Scene scene;
    public Camera camera;
}

и в установщике используйте SceneManager.GetActiveScene

// This attribute makes this classes messages be executed also in editmode
// (= also of not in playmode)
[ExecuteInEditModo]

// Assure there is a Camera component
[RequireComponent(typeof(Camera))]
public class CameraSetter : MonoBehaviour
{
    [SerializeField] private MainCamera mainCameraAsset;

    // Called on initialize
    // With [ExecuteInEditModo] also called on recompile
    private void Awake ()
    {
        mainCameraAsset.AddPair(SceneManager.GetActiveScene,  GetComponent<Camera>();
    }
}

Чем позже в сцене вы можете использовать список с FirstOrDefault (который не выдает исключение, но возвращает null, если элемент не найден) и Scene.path (поскольку имя сцены может быть одинаковым, и вы не можете сравнивать scene напрямую, поскольку его экземпляр не совпадает с указанным), например,

var camera = mainCameraReference.SceneCameraPairs.FirstOrDefault(pair => pair.scene.path == ScaneManager.GetActiveScene().path);

или словарь типа

 var camera = mainCameraReference.sceneToCamera[ScaneManager.GetActiveScene().path];

Различные типы

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

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/Data", order = 1)]
public class References : ScriptableObject
{
    public Camera mainCamera;
    public CharacterController controller;
    public Transform transform;

    // fix for the generic methods
    // a bit dirty maybe but should work
    public void Set(Component component)
    {
        if(component.GetType() == typeof(Camera))
        {
            mainCamera = (Camera) component;
        } 
        else if(component.GetType() == typeof(CharacterController))
        {
            controller = (CharacterController) component;
        }
        else if(component.GetType() == typeof(Transform))
        {
            transform = (Transform) component;
        }
    }

    public void Set(Camera camera)
    {
        mainCamera = camera;
    }

    public void Set(CharacterController characterController )
    {
        controller = characterController ;
    }

    public void Set(Transform characterTransform)
    {
        transform = characterTransform;
    }

    // or simply all at once
    public void Set(Camera camera, CharacterController characterController, Transform characterTransform)
    {
        mainCamera = camera;
        controller = characterController;
        transform = characterTransform;
    }

    // etc
}

Чем у вас может быть один базовый класс сеттера, например

public abstract class SetterBase<T> : MonoBehaviour where T : Component
{
    // unfortunately you can not serialize generics in 
    // the inspector so for now we stick with only one single ScriptableObject
    public References references;

    privtae void Awake()
    {
        SetReference<T>();
    }

    private void SetReference<T>() where T : Component
    {
        var component = GetComponent<T>();
        references.Set(component);
    }
}

Теперь вы можете наследовать реализации для каждого нужного вам типа / который присутствует в References как

public CameraSetter : SetterBase<Camera>
{
    // doesn't have to do anything else ... but could
}

и

public TransformSetter : SetterBase<Transform>
{
    // doesn't have to do anything else ... but could
}

и т.д.

Или, альтернативно,
(и именно поэтому я добавил один установщик для всего), вы можете разрешить обрабатывать его всем одним менеджером

public class ReferenceSetter : MonoBehaviour
{
    public References references;

    // Reference those in the inspector as usual
    public Camera camera;
    public Transform transform;
    public CharacterController controller;

    private void Awake()
    {
        references.Set(camera, controller, transform);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...