在游戲開發(fā)中,如何移動物體?是我們需要思考的事情。
Unity 引擎也提供了眾多的方法,每個開發(fā)者的使用習(xí)慣也各不相同,所以往往不是很清楚在這種場景下哪種方式最好的或者最有效的。
那么,這篇文章,我想分享一下移動物體的一些方法和優(yōu)缺點。
項目地址
倉庫地址
如何優(yōu)雅地移動物體?8個方法
向某個方向移動
Transform.Position
眾所周知,我們可以給對象的Transform
組件賦予一個坐標(biāo)來決定其位置。
transform.position = new Vector3(2, 1, 0);
當(dāng)我們每一幀給對象賦予一個新的坐標(biāo),那么看起來,這個物體就是在運動的。
void Update()
{
var dir = new Vector3(0.02f, 0, 0);
transform.position += dir;
}
效果如下:
Transform.Translate()
由于直接改變 Position 屬性看起來不太優(yōu)雅。所以 Transform
組件提供了一個更友好的方法:Transform.Translate()
。
void Update()
{
var dir = new Vector3(0.02f, 0, 0);
transform.Translate(dir);
}
其實,他的內(nèi)部與 Transform.Position
無異。
public void Translate(Vector3 translation, [DefaultValue("Space.Self")] Space relativeTo)
{
if (relativeTo == Space.World)
this.position += translation;
else
this.position += this.TransformDirection(translation);
}
效果與 Transform.Position 一致
但是這種方法產(chǎn)生了一個問題。由于設(shè)備之間的差異或者動態(tài)數(shù)據(jù)的變化會導(dǎo)致每一幀之間的間隔是不相等的,因此,如果以幀數(shù)來控制物體移動,物體的移動距離就沒辦法準(zhǔn)確把握。
效果如下
所以我們需要在原來的基礎(chǔ)上乘以 Time.deltaTime
屬性的值,從而保證每秒移動的距離是一致的。
void Update()
{
var dir = new Vector3(2f, 0, 0)*time;
transform.Translate(dir);
}
這樣不同的幀數(shù)移動距離都會一致。
效果如下:
但這還不夠優(yōu)雅。在游戲中,我們經(jīng)常需要改變物體的速度。為了方便實現(xiàn),我們通常會使用單位向量來確定方向,增加一個浮點值來控制速度。
public float speed = 2;
void Update()
{
var dir = new Vector3(2,0,0)
transform.Translate(dir.normalized * speed * Time.deltaTime);
}
移動到指定位置
移動到指定位置,大概有兩種方式。
- 速度:物體通過特定速度向目標(biāo)移動。
- 時間:物體在時間內(nèi)到達(dá)目標(biāo)。
Vector3.MoveTowards():固定速度
以固定的速度移動到目標(biāo)位置
public Vector3 targetPosition;
public float speed=10;
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
}
效果:
Vector3.SmoothDamp():平滑移動
又或者,我們可以用平滑的方式到達(dá)目標(biāo)位置。(平滑:到達(dá)位置前提前減速)
public Vector3 targetPosition;
public float smoothTime = 0.5f;
public float speed = 10;
Vector3 velocity ;
void Update()
{
transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, smoothTime, speed);
}
效果:
Vector3.Lerp():線性時間移動
該方法的意思是在調(diào)用方法期間,已經(jīng)過的時間除以總持續(xù)時間,得到當(dāng)前的位移目標(biāo)。
// 終點
public Vector3 targetPosition;
// 開始位置
public Vector3 startPosition;
// 持續(xù)時間
public float lerpDuration = 4;
// 記錄運行時間
private float _timeElapsed = 0;
void Start()
{
startPosition = transform.position;
}
void Update()
{
// 記錄下一個位置
Vector3 valueToLerp;
_timeElapsed += Time.deltaTime;
if (_timeElapsed < lerpDuration)
{
valueToLerp = Vector3.Lerp(startPosition, targetPosition, _timeElapsed / lerpDuration);
}
else
{
valueToLerp = targetPosition;
}
transform.position = valueToLerp;
}
效果如下:
以上的這些方法足以讓我們準(zhǔn)確且隨心的操縱物體移動。
但有一些場景,我們并不希望如此精確或始終如一的運動軌跡,我們想物體的移動受 Unity 的物理引擎影響或者其他物體影響。
同時如果用以上方法移動,在 Unity 的物理引擎下會出現(xiàn)抖動,穿過剛體等奇怪的現(xiàn)象。
那么接下來,我們就需要用到一些涉及到物理引擎的移動方式。
物理引擎移動
Rigidbody.AddForce()
使用這個方法給物體添加一個方向力。在力的作用下,物體將會移動。那么移動速度和位移就會與物理特效有關(guān),比如物體質(zhì)量,阻力,甚至還有重力。
一般會有兩種使用方式。
在初始時給物體一個力,讓其順著物理規(guī)律下運動。使用場景一般時跳躍或者碰撞。
// 賦予200的力
public float force = 200;
private Rigidbody2D _rigidbody2D;
// 移動方向
private Vector3 dir = Vector3.right;
void Start()
{
_rigidbody2D = GetComponent<Rigidbody2D>();
_rigidbody2D.AddForce(Vector2.right * force);
}
為了更好演示剛體的運動,我還給剛體的線性阻力改為1,這樣沒有持續(xù)施加外力的情況下,物體會因為摩擦力的存在而停下。
效果如下:
可以看到物體很快就停下了
第二種,會在每一幀持續(xù)給物體施加力,使物體可以持續(xù)運動。
// 賦予2的力
public float force = 2;
private Rigidbody2D _rigidbody2D;
// 移動方向
private Vector3 dir = Vector3.right;
void Start()
{
_rigidbody2D = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
_rigidbody2D.AddForce(Vector2.right * force);
}
效果如下:
從效果可以看到,在持續(xù)給外力的作用下,物體移送越來越快,但在阻擋物前會停下。
Rigidbody.Velocity
直接賦予 Velocity 屬性一個向量,可以立即改變物體的速度。一般情況下,我們不需要直接修改速度,除非你非常明確需要立即改變物體的速度。
public float speed = 10;
private Rigidbody2D _rigidbody2D;
// 移動方向
private Vector3 dir = Vector3.right;
void Start()
{
_rigidbody2D = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
_rigidbody2D.velocity = dir * speed;
}
效果如下:
看到物體一開始就已經(jīng)有速度,而通過AddForce
方法添加力的物體,速度時慢慢提高的。
Rigidbody.MovePosition()
該方法有比較局限的使用場景,當(dāng)物體的剛體類型是 Kinematic 時,使用Rigidbody.MovePosition()
方法進(jìn)行移動。
因為 Kinematic 類型下,不會受到重力和AddForce、AddTorque等力相關(guān)的函數(shù)的影響?。?!
public float speed = 10;
private Rigidbody2D _rigidbody2D;
// 移動方向
private Vector3 dir = Vector3.right;
void Start()
{
_rigidbody2D = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
var positon = dir * (speed * Time.deltaTime);
_rigidbody2D.MovePosition(transform.position + positon);
}
效果如下:
剛體類型是 Kinematic 時 ,會對剛體類型為 Dynamic 施加力,而無視 static 類型。文章來源:http://www.zghlxwxcb.cn/news/detail-406754.html
在文末,歡迎在評論區(qū)發(fā)表你的見解。如果覺得寫的不錯,可以給我點贊,鼓勵一下,謝謝。文章來源地址http://www.zghlxwxcb.cn/news/detail-406754.html
到了這里,關(guān)于【Unity】如何優(yōu)雅地移動物體-8個方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!