關於 web service, unity, blogger 等軟體工程筆記

Unity Platformer 2D: Moving Platform

Edit icon 沒有留言
Unity

持續前幾篇的練習。

關於平台移動

製作移動式的平台來增加遊戲性,移動式平台可以使用 Animator 去製作,或者是寫 Scripts 來達成。但不管使用哪種一方式,應該都在物理更新時,才重新計算平台的位置。Animator 可以設定 Update ModeAnimate Physicals,則 Scripts 將計算 transform 新位置的程式碼從 Update 改寫到 FixedUpdate 中。

可是,移動式平台沒有辦法這麼簡單就完成,如此這樣做的平台實際遊戲結果,可以參考以下兩個示意動畫,很明顯得平台並不會帶著角色移動。角色站在水平移動平台上,看起來就是懸空在空中。在垂直移動平台下降時,反而角色會一直處於下落 (Landing) 的情況,演出不正確的動畫。

水平移動的平台

垂直移動的平台

讓平台帶著角色移動

簡單的解決方案是,當角色移動到移動式平台後,使得角色物件變成該平台的子物件 (to child transform)。如果一來可以像以下兩張示意動畫,平台移動時會帶著角色一起移動,上下移動的平台也不會造成角色處於下落的奇怪狀態。

水平移動的平台修正後

垂直移動的平台修正後

因此需要寫一段程式來達到這功能,當 OnCollisionEnter2D 發生時判斷設定子物件,OnCollisionExit2D 則將角色設定原本的父物件 (original transform parent)。邏輯上有兩條路可以選:

  • 在角色物件上加入 Script,當移動到任意平台時,設定角色的 transform parent
  • 在每一個移動平台上加入 Script,當角色移動在此平台時,設定角色的 transform parent

最後不選實作方法一的理由為,避免持續切換角色 transform parent 所可能發生的 bugs,且在靜態平台上並不需要設定 transform parent,不必要的 transform parent 修改會造成一些記憶體負擔。

此外若平台物件的 transform lossyScale 在 X 軸上為負值的話 (<0),若角色成為該平台的子物件時,會使得之前為角色移動所做的 Flip() 功能錯誤……。

因此實作方法二,在每一個移動平台物件上加入此組件 (Component):

using UnityEngine;

public class MovingPlatform : MonoBehaviour
{
void OnCollisionEnter2D(Collision2D c)
{
if (c.gameObject.tag == "Player")
{
var target = c.gameObject.transform;
target.SetParent(this.transform);
}
}

void OnCollisionExit2D(Collision2D c)
{
if (c.gameObject.tag == "Player")
{
var target = c.gameObject.transform;
var original = target.GetComponent<TransformState>().OriginalParent;
target.SetParent(original);
}
}
}

判斷 Collision2D.gameObject,若為角色物件,則設定角色物件成為該移動平台的子物件。反之則設定為該角色物件原始的 transform parent。

另外還得在角色物件上加入 TransformState 組件,用來記錄原始角色物件的 transform parent,以提供移動平台 MovingPlatform 重新設定角色 transform parent,其程式碼:

using UnityEngine;

public class TransformState : MonoBehaviour
{
public Transform OriginalParent
{
get;
set;
}

void Awake()
{
this.OriginalParent = this.transform.parent;
}
}

Done, it’s works。

Source Code

Github

Series

Reference

沒有留言: