我是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
现在我想将主摄像机分配给检查器中的“摄像机”变量。 但是,选择菜单仅显示“无”,而没有照相机。
如何将摄像机分配给可编写脚本的对象中的camera变量?
答案 0 :(得分:2)
您可以不直接将场景引用附加到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);
}
}
现在,您可以为{/ {1}}中存在的每种所需类型/继承实现,如
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
}