如何在不使用 public 的情况下编写脚本?

How can I write my script without using public?

所以我目前正在尝试将我的播放器对象及其脚本添加到为相机对象编写的相机脚本中。

using UnityEngine;

public class CameraController : MonoBehaviour
{
    public Transform target;
    private Vector3 offset;
    private float damping = 0.2f;

    public bool canMove = true;
    public PlayerMovement player;

    private void Start()
    {
        player = gameObject.GetComponent<PlayerMovement>();
    }

    void FixedUpdate()
    {
        if (player.faceRight)
        {

            offset = new Vector3(1f, 0.5f, -10f);
            transform.position = Vector3.Lerp(transform.position, target.position, damping) + offset;

        }

        else if (!player.faceRight)
        {

            offset = new Vector3(-1f, 0.5f, -10f);
            transform.position = Vector3.Lerp(transform.position, target.position, damping) + offset;

        }
    
    }
}

我的问题是我不能写 player = gameObject.Find("Player"); 因为 unity 会说“那些是不同类型的元素”但是如果我写 public PlayerMovement player; 并且它可以拖动我的播放器对象作品。问题是我想学习如何在不拖动我的对象的情况下使用它。

我添加了 GameObject 和 PlayerMovement 属性。先写gameObject,称为“Player”。然后通过使用我的 GameObject,我与名为 PlayerMovement 的脚本进行了交互。

using UnityEngine;

public class CameraController : MonoBehaviour
{
    public Transform target;
    private Vector3 offset;
    private float damping = 0.2f;

    public bool canMove = true;

    private GameObject playerObject;
    private PlayerMovement playerMovementScript;
    
    private void Start()
    {
        player = GameObject.Find("Player");
        player = gameObject.GetComponent<PlayerMovement>();
    }

    void FixedUpdate()
    {
        if (player.faceRight)
        {

            offset = new Vector3(1f, 0.5f, -10f);
            transform.position = Vector3.Lerp(transform.position, target.position, damping) + offset;

        }

        else if (!player.faceRight)
        {

            offset = new Vector3(-1f, 0.5f, -10f);
            transform.position = Vector3.Lerp(transform.position, target.position, damping) + offset;

        }
    
    }
}

我在这里写那个问题的时候解决了那个问题。所以我为自己感到骄傲,但我也想分享我的解决方案,这样如果有人遇到这样的问题,他们就可以解决他们的问题。如果有人有更好的解决方案,请分享。

首先,您 可以 通过检查器公开和分配 private(和 protected)字段通过使用属性 [SerializeField] 而不必像

那样被迫将它们设为 public
[SerializeField] private PlayerMovement player;

private void Awake()
{
    // if it's not referenced via the Inspector
    // get it from this object on runtime as fallback
    if(!player) player = GetComponent<PlayerMovement>();
}

然后,好吧,你的字段 playerPlayerMovement 类型,而 Find returns 是 GameObject → 不是同一类型。

现在如果你想从这个脚本附加到的同一个对象中获取那个组件.. 那么你为什么要使用昂贵的 Find 呢?!你已经知道这个对象了!仅使用 GetComponent 将组件附加到与此脚本相同的对象(就像上面的代码一样)。

如果你真的想使用 Find 那么你想在结果上使用 GetComponent,而不是在 gameObject 上,这是对脚本 own 的引用 GameObject。你宁愿

[SerializeField] private PlayerMovement player;

private void Awake()
{
    if(!player) player = GameObject.Find("player").GetComponent<PlayerMovement>();
}

或者如果场景中只有一个该类型的实例,您也可以简单地使用 FindObjectOfType

[SerializeField] private PlayerMovement player;

private void Awake()
{
    if(!player) player = FindObjectOfType<PlayerMovement>();
}

总的来说:如果您可以通过检查器引用某些内容,那么这样做总是更好。它的效率更高,因为引用将被序列化到您的场景或预制资产中,因此在加载它时您已经“知道”目标引用。使用 Find 非常昂贵,即使它在以后的版本中进行了很多优化,您也可以避免使用 GetComponent ;)