【问题标题】:Best way to move my Gameobject smoothly?平稳移动我的游戏对象的最佳方法?
【发布时间】:2016-04-15 03:54:28
【问题描述】:

我在尝试平稳移动游戏对象时遇到问题。

我每秒通过 TCP 协议收到一个位置,我的游戏对象必须移动到该位置。所以我有了我的开始位置,我的结束位置,我可以计算出两个位置之间的距离,我知道我的游戏对象必须移动在 1 秒内匀速到达终点。

我尝试了 3 种解决方案:Learp、MoveToward 和 SmoothDamp,但它们都不起作用,我的游戏对象只是从 A 点传送每次都去B点。

这是我在代码中尝试的内容(我的游戏对象在字典中被引用,我的游戏对象是平面):

// Distance between my 2 points
float step = Vector3.Distance(planeId_Object_Dictionnary[newPlane.Flight].transform.position, new Vector3((float)newPlane.X, (float)newPlane.Afl / (3.2808f * 1852f), (float)newPlane.Y));
//Use of Lerp
//planeId_Object_Dictionnary[newPlane.Flight].transform.position = Vector3.Lerp(planeId_Object_Dictionnary[newPlane.Flight].transform.position, new Vector3((float)newPlane.X, (float)newPlane.Afl / (3.2808f * 1852f), (float)newPlane.Y), step);
//Use of MoveTowards
planeId_Object_Dictionnary[newPlane.Flight].transform.position = Vector3.MoveTowards(planeId_Object_Dictionnary[newPlane.Flight].transform.position, new Vector3((float)newPlane.X, (float)newPlane.Afl / (3.2808f * 1852f), (float)newPlane.Y), step);
//Use of SmoothDamp
//planeId_Object_Dictionnary[newPlane.Flight].transform.position = Vector3.SmoothDamp(planeId_Object_Dictionnary[newPlane.Flight].transform.position, new Vector3((float)newPlane.X, (float)newPlane.Afl / (3.2808f * 1852f), (float)newPlane.Y), ref newPlane.GroundSpeed, 1);

代码是在我的更新中以这种方式调用的函数:

void Update () {
        lock (threadLock)
        {
            // Message receive from my TCP Protocol
            while (q_orders.Count > 0)
            {
                switch (q_orders.Dequeue())
                {
                    case OrderType.trackmovedevent:
                        aircraftMajInfos(q_args.Dequeue()); // My function to move my Object
                        break;
                }
            }
        }
    }

【问题讨论】:

  • 您是在 Update() 或任何其他循环中调用 MoveTowards 吗?
  • 是的,我在我的更新中调用它。
  • 对 Lerp 和 SmoothDamp 的最后一个参数使用较低的值。 Lerp 的工作方式是获取点 A 和点 B,然后查看最终参数中的值 S 并返回点 C。基本上 S 表示 A 和 B 之间的归一化值,即 S=0 返回 A,S=1 返回 B , S=0.5 返回 A 和 B 之间的中点,依此类推......换句话说,距离(A,C)和距离(B,C)的比率等于 S 和(1 - S)的比率。因此,在您的情况下,制作 S 1 将始终返回目的地点,从而导致“传送”。使该值小于 1。
  • 另外,为了使 Lerp 帧速率独立,你可以将 S 值与 Time.deltaTime 相乘。所以以 60fps 播放的人不会比以 30fps 播放的人有更快的过渡。
  • 有了这个解决方案,我怎么能确定我会在 1 秒内从 A 点到 B 点?我尝试将第三个参数设置为 0.1*Time.deltaTime,它的移动非常缓慢且不顺畅:(

标签: c# unity3d unityscript unity5


【解决方案1】:

最好使用补间引擎,例如http://dotween.demigiant.com/。

如果你安装了 Dotween,那么你可以简单地使用

transform.DOMove(new vector3(1 ,0 , 1) , duration);

您还可以为补间设置轻松。或使用 Oncomplete 函数;

transform.DOMove(new vector3(1 ,0 , 1) , duration)
    .SetEase(Ease.OutCubic)
    .OnCompelete(() => { shouldClose = true; }); 

【讨论】:

  • 哇,这简直是火大人!解决我所有的框架问题!但是我不确定速度是否恒定,似乎不是,每个点之间都有加速和减速。
  • 您可以将缓动类型设置为线性
【解决方案2】:

我必须说你完全错误地理解了所有三个函数。它们应该在多次更新中被调用,而不仅仅是一次。

在这种情况下,我推荐MoveTowards。因为SmoothDamp不会匀速移动物体,而要使用Lerp,需要计算两点之间的比率(注意,如果将数量加到t参数中,可以不断移动物体每次固定更新)。

这是我为你的游戏对象的 MonoBehaviour 编写的代码 sn-p

const float moveTime = 1;
Vector3 target, step;

void Update () {
    transform.position = Vector3.MoveTowards(transform.position, target,
        step / moveTime * Time.deltaTime);
}
// Call this method to set the new target (the currently received position from network)
public void SetTarget (Vector3 positon) {
    target =  positon;
    step = Vector3.Distance(transform.position, target);
}

Time.deltaTime 是更新之间的间隔(调用Update () 函数的地方)

【讨论】:

  • 好的,现在我明白了为什么我的对象传送,这是因为我只调用它一次,当我应该多次调用它时,谢谢,但是要调用我的函数,我在更新中使用了布尔值,所以除了仅在 1 帧期间调用它之外,我没有任何其他解决方案,有没有办法执行 MoveTowards ?如果不清楚,我会更新我的代码。
  • @EvansBelloeil 所以你找到了解决问题的方法;但是下次你问问题的时候,记得把太长的代码行截掉,那些代码很难阅读。
【解决方案3】:

我建议如下:

  • 创建一个新脚本“ObjectMover”(可能不是最好的名称)并将其应用于您希望能够移动的游戏对象。
  • 在脚本中创建一个公共方法:MoveToNewPos(Vector3 newPos),用于存储您使用此对象瞄准的新位置。

在“ObjectMover”的 Update 方法中,使用 lerp 或使用 step / moveTime * Time.deltaTime 自己计算步进以移动到想要的新位置,并且只将速度调整到您想要的外观和感觉。

从您的“主”脚本中执行 ObjectIWantToMove.GetComponent().MoveToNewPos(newPos);它会顺利移动到那里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多