c# - 将相机统一连接到可编写脚本的对象
问题描述
我是 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
现在我想将主相机分配给检查器中的那个相机变量。但是,选择菜单只显示“无”,但没有摄像头。
如何将相机分配给可编写脚本对象中的相机变量?
解决方案
您不能直接将场景引用附加到ScriptableObject
s 或实际上任何资产。
但是你可以反过来:给相机提供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
}
ETC
或者
(这就是为什么我为所有事情都添加了一个二传手)你可以让它全部由一个经理来处理
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);
}
}
推荐阅读
- python - python解释中的具体语法
- android - 主题插件在 Andriod 工作室中不起作用
- python - 试图将变量存储在python的文本文件中
- python - 从文本文件中提取特定开始/结束模式之间的行
- python-3.x - 我们如何使用 Gerrit rest 按特定修订列出审稿人
- django - Django Dict 过滤多个 AND OR 条件
- mysql - 如何使用连接从 mysql 中的单个表中获取唯一数据?
- java - 从 Java 创建 .exe 供人们使用
- javascript - javascript中未定义执行回调函数后的变量
- android - Android Studio Artic Fox 未无线连接多个设备且未附加调试器