【问题标题】:How can I write my script without using public?如何在不使用 public 的情况下编写脚本?
【发布时间】:2021-04-26 15:11:39
【问题描述】:

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

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");,因为统一说的是“那些是不同类型的元素”,但如果我写public PlayerMovement player;,我可以拖动我的播放器对象并且它有效。问题是我想学习如何在不拖动对象的情况下使用它。

【问题讨论】:

    标签: unity3d game-development


    【解决方案1】:

    首先,您可以使用属性[SerializeField],通过检查器公开和分配private(和protected)字段,而无需强制执行他们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 返回 GameObject → 不是同一类型。

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

    如果你真的想使用Find,那么你想在结果上使用GetComponent,而不是gameObject,这是对脚本的引用拥有 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>();
    }
    

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

    【讨论】:

    • 我真的很喜欢你的解释,但有一个问题。我正在尝试将播放器对象的脚本元素添加到相机对象的脚本中。这意味着我在播放器对象的脚本中有一些属性,我想在我的相机对象的脚本中使用它们。所以相机和播放器是两个不同的对象。这就是我使用“查找”的原因。
    • 是的,但如果您只是通过 Inspector 引用它们,则根本不需要 Find。如果您需要它(例如,因为您稍后将玩家生成到场景中),然后使用第二个或第三个代码 sn-p 我告诉您如何在您的情况下正确使用 Find
    【解决方案2】:

    我添加了我的 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;
    
            }
        
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      • 2022-06-23
      相关资源
      最近更新 更多