之前一的時候,要實現幀同步,需要一個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);
}
}