网上对于网络同步的说法排雷

之前一的时候,要实现帧同步,需要一个ECS框架(非必须)

然后除了ECS,还缺平滑移动,(就算有了幀同步框架)

网上说的平滑移动很不准确,还有某大神的“同步框架”,“开源项目‘,居然有这样的代码

o.transform.position = Vector3.Lerp(o.transform.position, o.transform.position + dir.normalized, 0.33f * _speed);

如此做法,连在Unity或者任何一个游戏引擎里,“好好”移动都做不到,只是纸上谈兵

网上狠多人也说,要用Lerp,要用Vector3.Lerp还是Mathf.Lerp??

然后又会扯出一大堆,lerp的理论,。。。。。 1+1==2 确实需要研究其理论的,这我同意

但其实要在Unity下实现平滑移动,

其实 “Lerp” 和 “Time.deltaTime” 应该是要配合使用的

(和官方的gravity, setVelocity等很不同,但有兴趣的同学可以深挖一下其官方实现的代码原理)

官方实现原理比对

官方的很多封装的方法都很“好用”

transform.Translate(0, 0, speed*Time.deltaTime);

又例如:

navAgent.velocity = v.normalized*MoveSpeed;

效果实现起来,是挺“平滑”的,但我们一般程序员容易用错啊

感觉UNITY公司内部人员都是牛人,但是他们好像也不愿意分享其中原理,或者他们很多知识点觉得理所当然吧

也导致很多Unity新手自创很多方法。。。。(99%是暴雷)

下面这个代码好像对,但又极其雷

(很多时候你做的游戏看上去还好,只是因为你一直没发布到不同的手机,一个小小的适配改变就各种显示异常,类似地,网络同步更加容易异常)

currentCornerMoved += MoveSpeed * Time.deltaTime;

transform.position = Vector3.Lerp(currentPathCorners[currentPathCornerIndex], currentPathCorners[currentPathCornerIndex + 1], currentCornerMoved / currentCornerDist);
transform.forward = Vector3.RotateTowards(transform.forward, currentPathCorners[currentPathCornerIndex + 1] - currentPathCorners[currentPathCornerIndex], 15.0f * Time.deltaTime, 0);

通用移动测试代码

所以,这里分享一个测试代码,随便一个空场景,挂脚本,填写预制体,增加一个Plane(要在0点)做点击触发,即可使用

先保证平滑移动,没卡顿,再说网络多人!!!

先保证平滑移动,没卡顿,再说网络多人!!!

先保证平滑移动,没卡顿,再说网络多人!!!

操作(使用)方法:

鼠标右键,新增GameObject

键盘X键,移动GameObject

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 一个平滑移动例子
/// </summary>
public class TouchAndMove : MonoBehaviour
{
    List<GameObject> objs = new List<GameObject>();
    public GameObject _prefab;
    Vector3 _destination;
    Vector3 _frm;
    public float _speed = 5;
    // Start is called before the first frame update
    Vector3 _deftinationDef = Vector3.zero;
    void Start()
    {
        //操作方法:鼠标右键,新增GameObject; 键盘X键,移动GameObject
    }

    // Update is called once per frame
    void Update()
    {
        if(UnityEngine.Input.GetMouseButtonUp(1))
        {
            objs.Add(GameObject.Instantiate(_prefab));
        }

        if (UnityEngine.Input.GetKeyUp(KeyCode.X))
        {
            Vector2 vec2 = GetWorldPos(UnityEngine.Input.mousePosition);
            _destination = new Vector3(vec2.x, 0, vec2.y);
            if (objs.Count > 0)
            {
                _frm = objs[0].transform.position;
            }
        }
        //可调用方法还有,OnDestinationDef(),OnDestination()等,请看说明,不一定”好用“
        //使用前,需要配置_prefab
        ///当然,可以通过调整_speed,观察移动效果。。。
        OnDestination3(); 
    }
    /// <summary>
    /// 弹簧式步进
    /// </summary>
    void OnDestinationDef()
    {
        foreach (var o in objs)
        {
            if ((o.transform.position - _destination).magnitude > 1)
            {
                o.transform.position = Vector3.Lerp(o.transform.position, _destination, Time.deltaTime * _speed);
            }
            else
            {
                _frm = objs[0].transform.position;
                //_destination = _deftinationDef;
            }
        }
    }
    /// <summary>
    /// 只移动一小段
    /// </summary>
    void OnDestination()
    {
        if (_destination == null) return;
        foreach (var o in objs)
        {
            if ((o.transform.position - _destination).magnitude > 1)
            {
                o.transform.position = Vector3.Lerp(_frm, _destination, Time.deltaTime * _speed);
            }
            else
            {
                _frm = objs[0].transform.position;
                //_destination = _deftinationDef;
            }
        }
    }
    /// <summary>
    /// 特喵了,根本无法正常移动
    /// </summary>
    void OnDestination2()
    {
        if (_destination == null) return;
        foreach (var o in objs)
        {
            if ((o.transform.position - _destination).magnitude > 1)
            {
                Vector3 dir = _destination - _frm;
                o.transform.position = Vector3.Lerp(o.transform.position, dir.normalized, Time.deltaTime * _speed);
            }
            else
            {
                _frm = objs[0].transform.position;
                //_destination = _deftinationDef;
            }
        }
    }
    /// <summary>
    /// 看上去,这个是真正的完全移动了,但如果把速度调快,则也是有明显”卡帧“,所以高速运动还是有跳帧现象
    /// </summary>
    void OnDestination3()
    {
        if (_destination == null) return;
        foreach (var o in objs)
        {
            if ((o.transform.position - _destination).magnitude > 1)
            {
                Vector3 dir = _destination - _frm;
                o.transform.position = Vector3.Lerp(o.transform.position, o.transform.position +dir.normalized, Time.deltaTime * _speed);
            }
            else
            {
                _frm = objs[0].transform.position;
                //_destination = _deftinationDef;
            }
        }
    }
    /// <summary>
    /// 不平滑移动
    /// </summary>
    void OnDestination4() {
        if (_destination == null) return;
        foreach (var o in objs)
        {
            if ((o.transform.position - _destination).magnitude > 1)
            {
                Vector3 dir = _destination - _frm;
                o.transform.position = Vector3.Lerp(o.transform.position, o.transform.position + dir.normalized, 0.33f * _speed);
            }
            else
            {
                _frm = objs[0].transform.position;
                //_destination = _deftinationDef;
            }
        }
    }

    Vector2 GetWorldPos(Vector2 screenPos)
    {
        var ray = Camera.main.ScreenPointToRay(screenPos);
        if (Physics.Raycast(ray, out var hit))
        {

            return new Vector2(hit.point.x, hit.point.z);

        }

        var hitPoint = ray.origin - ray.direction * (ray.origin.y / ray.direction.y);
        return new Vector2(hitPoint.x, hitPoint.z);
    }
}