【问题标题】:Unity Destroy and other code not working?Unity Destroy 和其他代码不起作用?
【发布时间】:2020-04-03 18:29:17
【问题描述】:

我正在尝试制作 Snake 游戏,并且正在尝试让 Apple 功能正常工作。这个脚本的目的是,每当我的蛇越过苹果时,苹果就会消失并重新出现在屏幕上的随机位置。但它什么也没做,知道为什么吗?

P.S:相机尺寸为 10,纵横比为 16:9,这就是为什么我有一些奇怪的 Random.Range 值。此外,我在 Update 中使用 Debug.Log 来确保变量有效,是的,每当我的蛇移动时,它的坐标就会显示出来。

public class Apple_RandomSpawn : MonoBehaviour
{
    private Vector2 foodPos;
    private Snake_Move snakeMove;

    void Start()
    {
        SpawnApple();
    }

    public void Update()
    {
        transform.position = new Vector2(foodPos.x, foodPos.y);
        SnakeAte();
    }

    public void SpawnApple()
    {
        foodPos = new Vector2(Random.Range(-17, 17), Random.Range(-9, 9));
    }

    public void SnakeAte()
    {
        if (Mathf.Approximately(foodPos.x, snakeMove.pos.x) && Mathf.Approximately(foodPos.y, snakeMove.pos.y))
        {
            SpawnApple();
        }
    }
}

【问题讨论】:

  • Vector2 的xyfloat。我的猜测是foodPos.x 就像0.121snakeMove.pos.x 就像0.1213 之类的。我建议使用调试器单步执行。
  • 我应该添加某种舍入组件吗?导致蛇每 1/60 秒在 x 值中移动 0.1,这使得蛇的移动成为浮动。不知道我将如何解决 xD
  • 如果这是问题所在,我可能会检查它们之间的距离是否小于某个数字。另请注意,浮点数无法准确表示所有小数值,就像我们无法准确表示以 10 为底的 1/3。有关更多信息,请参阅 Is floating point math broken?
  • @John 我将 Debug.Log 更改为显示 foodPos - snakeMove.pos 并且我得到的值非常小,只有 0.1 秒,所以是的,我认为你是对的。

标签: c# unity3d


【解决方案1】:

首先,它与您的问题没有直接关系,但不要将GetComponent()GameObject.Find() 放在Update() 函数中。这两个,尤其是GameObject.Find()函数是超重,所以建议你应该在Start()Awake()内部调用这类函数,或者在类的初始化时调用。它会直接并严重影响游戏的性能,因此我的建议如下:

[SerializeField]
private Snake_Move snakeMove;

然后通过 Inspector 拖动您的游戏对象(已附加 Snake_Head 组件)。您应该始终首先考虑这种方式,而不是使用GameObject.Find()GetComponent()

第二,不建议Float直接通过=比较相等,因为一定有舍入误差。 Unity 中有一个关于比较两个浮点值的帮助功能,例如Mathf.Approximately(float a, float b)。通过= 直接比较两个float 值几乎总是不会像您想象的那样工作。

第三,您的代码中似乎没有Instantiate() 函数,但是您尝试使用一个苹果对象,并且每次使用它时,只需更改它的位置即可。那为什么Object.Destroy(gameObject) 存在呢?你正在做的是,当你第一次得到它时就摧毁它。我觉得你得去掉Destroy()函数,SpawnApple()改变苹果的目标坐标,位置会在Update()函数中更新。

并且不需要间接设置目标位置,并在Update()函数中更新。可以直接设置苹果的位置,比如:

// assuming you followed my suggestio aboven about snakeMove.

public void Update()
    {
        SnakeAte();

        Debug.Log(snakeMove.pos);
    }

public void SpawnApple()
    {
        transform.position = new Vector2(Random.Range(-17, 17), Random.Range(-9, 9));
    }

public void SnakeAte()
    {
        if (foodPos == snakeMove.pos)
        {
            SpawnApple();
        }
    }

【讨论】:

  • 我的天哪,我能一直把它叫做变量吗?!!?!我花了大约 30 分钟试图从不同的类中调用一个变量 lmao 那么 GameObject.Find 有什么意义呢?
  • @CodingMike 是的,你所做的是,扫描整个场景,找到名称为“SnakeHead”的游戏对象,并尝试获取组件Snake_Move。这不是什么大问题,但是当你尝试这样做 每秒 60 次时,它就会成为问题。
  • 我把 if 语句改成了; Mathf.Approximately(foodPos.x, snakeMove.pos.x) && Mathf.Approximately(foodPos.y, snakeMove.pos.y 还是不行。是我做错了吗?哈哈
  • 嗯,它仍然无法正常工作,并且我收到一个控制台错误,上面写着“对象引用未设置为对象的实例”。我将编辑我的帖子,以便更新代码。
  • 您确定您已通过inspector 提供了对snakeMove 字段的引用吗? docs.unity3d.com/Manual/script-Serialization-BuiltInUse.html
【解决方案2】:

首先,您最后一条评论中的 null ref 来自: 私有 Snake_Move snakeMove; 它是一个私有变量,并且从未分配过。您要么需要将其设为 public/[SerialistField] 并在检查中分配它,要么需要某种初始化函数来为其赋值。

对于命中检测,如果您想检查 2 个浮点数是否完全相同,Mathf.Approximately 会很好。如果您正在检查移动物体的 2 个位置,那么它们完全相同的机会非常低,并且可能取决于帧速率等。保持您的实施,您可以检查两个位置之间的最小距离。您可以调整 DISTANCE_THRESHOLD 以获得更适合您的值。

public class Apple_RandomSpawn : MonoBehaviour
        {
            private const float DISTANCE_THRESHOLD = 0.1f;
            private Vector2 foodPos;
            private Snake_Move snakeMove;

            void Start()
            {
                SpawnApple();
            }

            public void Update()
            {                   
                SnakeAte();
            }

            public void SpawnApple()
            {
                foodPos = new Vector2(Random.Range(-17, 17), Random.Range(-9, 9));
                transform.position = new Vector2(foodPos.x, foodPos.y);
            }

            public void SnakeAte()
            {
                if (Vector3.Distance(foodPos, snakeMove) < DISTANCE_THRESHOLD)
                {
                    SpawnApple();
                }
            }
        }

现在请记住,由于您将苹果传送到一个纯粹随机的位置,它可能会立即传送回您的蛇顶部 :)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    相关资源
    最近更新 更多