如何在 Unity 中让 GameObjects 在屏幕上平滑平移?

Posted

技术标签:

【中文标题】如何在 Unity 中让 GameObjects 在屏幕上平滑平移?【英文标题】:How can I make GameObjects translate across the screen smoothly in Unity? 【发布时间】:2018-09-27 21:49:57 【问题描述】:

基本上,我有一个游戏,门票出现在屏幕顶部。当一张票完成后,它会被销毁,如果剩余票之间有间隙,票会向下滑动以填补间隙。我实际上让它工作得很好,但他们只是跳到位置上,看起来不太漂亮。

如何将对象顺利移动到目标位置?我试过搞乱LerpSmoothdamp,但这两个似乎都产生了奇怪的结果(票到处都是。这是我正在使用的相关代码:

    public void SlideRail()
    
        ticketList.RemoveAll(x => x == null);
        int count = ticketList.Count;

        for (int i = destroyedIndex; i < ticketList.Count; i++)
        
            if (ticketList[i] != null)
            
                ticketList[i].transform.Translate(Vector3.left * 35);
                ticketList[i].GetComponent<Ticket>().index--;
            
        
        indexer = railPosition.IndexOf(ticketList.Last().GetComponent<Ticket>().item_pos);
        up = false;
    

DestroyedIndex 是被销毁对象的索引(所以我们只在列表中移动它之后的对象) Up 是一个激活 SlideRail() 的标志,当它设置为 false 时,方法结束,下一个方法继续。

然后在 Update() 方法中调用 SlideRail:

    void Update()
    
        if (up && ticketList.Count > 2)
            SlideRail();


        if (Time.time > nextTicket)
        
            nextTicket = Time.time + timeBetweenTickets;
            StartCoroutine(WaitToPrint());
            CreateTicket();
            UpdatePosition();
        
    

我觉得我应该可以使用 Translate 来做到这一点,但我一定错过了一些东西。

【问题讨论】:

【参考方案1】:

对于这样的移动,您通常应该包含Time.deltaTime(作为转换的一个因素)以将移动绑定到帧速率。 [编辑:将这句话翻译成与帧速率无关,这就是我的意思。]

现在,实际上,看起来你只在一帧内完成了移动,因此你得到了这个跳转(你总是在 SlideRail 的末尾将 up 设置为 false)。

这样做的一种可能方法是在触发时指定目标位置(任务完成,需要推过去),然后为每个对象继续调用ticketList[i].transform.position = Vector3.MoveTowards(ticketList[i].transform.position, targetPosition, speed * Time.deltaTime);(由“到达目标位置”检查框定,例如使用@ 987654325@. 您可以在此添加一个 else 以在阈值范围内直接设置位置(使阈值变小使其不可见,例如 0.1f),尽管您通常只需要对像 lerp 这样减慢的非线性函数使用它最后并且可以停止。[编辑:由于浮点不精确,实际上使用阈值通常总是一个好主意。]

【讨论】:

这是迄今为止我得到的最好的建议,尽管我仍然不确定如何实现它。为了测试,我制作了一个随机方形预制件,并将您建议的代码放在更新函数中,看看它是否可以工作。果然,它做到了。这是因为,我假设 Update() 正在检查每一帧的 if 条件。但是在更新期间会调用 SlideRail(),但并不是每帧都以相同的方式检查条件。我这样想对吗?如果是这样,我如何检查列表中每个元素的 if 条件?我将条件放在了一个while循环中,但这会使Unity崩溃。 you should usually include Time.deltaTime (as a factor in translate) to bind the movement to the frame rate. 其实解绑吧。您希望移动帧速率独立,这就是使用 deltaTime 的好处。 @Draco18s 是的,我就是这个意思。 @Matt 好吧,Update 已经是一个循环,所以你不需要额外的循环(当然,除了对所有元素都这样做)。在Update 中检查if(up == true),现在,在SlideRail 的末尾,您将其设置为false,没有任何条件,因此,使用提供的代码,您只会进入SlideRail 一次。相反,您希望将 up = false 置于一个条件中,询问对象(或可能所有对象,是否需要一些计数器或类似物)到达目标位置,然后设置 up = false 另一种选择是使用协程而不是像 ATHellboy 的答案中那样更新。那确实需要while循环来做与更新相同的事情。【参考方案2】:

使用iTween,可以简化为一行调用:

iTween.MoveTo(someGameObject, iTween.Hash("y", targetY, 
             "islocal", true,"easetype", iTween.EaseType.spring, 
            "time", 0.2f));

【讨论】:

所以,我很感兴趣。我最近开始使用 C# 进行编码,将我的 Flash 游戏改造成 Unity。重新回到游戏中。请解释“someGameObject”和“targetY”。虽然这是一个很好的例子。我不知道如何应用这个。当我终于认识到它实际上在导入时,VSCode 现在“看到”了它......我正在将我的 someGameObject 移动到我知道的位置;我实际上知道 x/y 坐标。但这不是这个函数想要的。所以我创建了一个对象来“寻找”并将它放在舞台上。将 someGameObject 移动到这个 targetY 对象?我试过了,也没用。 似乎只适用于 3D 对象?如果是这样,有没有办法使用 2D 游戏对象将此扩展程序/插件用于 2D 游戏?【参考方案3】:

这段代码我以前自己写过,也许对你有帮助。

using System;
using System.Collections;
using UnityEngine;

public class MoveController : MonoBehaviour

    public float moveTime;
    public AnimationCurve moveSpeedCurve;
    public AnimationCurve movePositionCurve;

    public void StartMoving(Vector2 destination, Action action = null)
    
        StartCoroutine(Move(destination, action));
    

    IEnumerator Move(Vector3 destination, Action action = null)
    
        float currentTime = 0;
        float perc = 0;
        Vector3 currentPos = transform.localPosition;

        while (perc != 1)
        
            currentTime += Time.deltaTime;
            if (currentTime > moveTime)
            
                currentTime = moveTime;
            
            perc = moveSpeedCurve.Evaluate(currentTime / moveTime);
            transform.localPosition = Vector2.LerpUnclamped(currentPos, destination, movePositionCurve.Evaluate(perc));
            yield return null;
        

        if (action != null)
            action();
    

【讨论】:

以上是关于如何在 Unity 中让 GameObjects 在屏幕上平滑平移?的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历用于 AutoSpawn 的 Unity GameObjects 数组

Unity Netcode for GameObjects多人联机(源文件)

有没有一种方法将GameObjects放置在网格模式中(类似于tilemap)?

开源项目MLAPI正式加入Unity

Unity用代码实现Remove Missing Script

Unity2.7 检视器(Inspector)