将摄像机统一附加到可脚本编写的对象

时间:2019-01-17 06:41:05

标签: c# unity3d

我是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变量?

1 个答案:

答案 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
}