Вы можете , а не напрямую прикреплять ссылки на сцену к 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);
}
}