[C#/Unity] 《Endless End》中的升降機實現總結

        由於《Endless End》需要體現「一層一層往上走」這個印象,因此,一些允許玩家垂直移動的道具就成為了必要場景物品。對於這一點,我做了兩個東西讓玩家「垂直移動」,一個是玩家可以上下攀爬的梯子,而另一個就是這一篇總結中要說的升降機。

        那這個自動升降的升降機有甚麼需求呢?

  1. (核心需求)自動升降。當玩家站上去一段短暫的時間後,升降機需要載著玩家移動到上/下一層。
  2. 由於每一層都通往另一層的道路都是唯一的,同時,玩家每次進入遊戲都會生成在最後激活的檢查點上,因此,電梯的初始化也必須盡量靠近玩家最後激活的檢查點。比如玩家最後激活的檢查點為三樓,有一電梯運行在一樓與二樓之間,那電梯必須初始化在二樓,否則玩家將沒有途徑前往一樓。

        要做一個這樣的自動升降機,我們首先要做一個升降機槽。這個升降機槽包括:

  1. 升降機本身(Elevator)
  2. 升降機的下層終點(LowerFloor)
  3. 升降機的上層終點(UpperFloor)
  4. (Optional) 機槽裡的燈光(ShaftLights)

        然後就是升降機本身:

  1. 升降機需要「載著」玩家移動,因此它本身需要與玩家產生碰撞,因此升降機需要一個碰撞體。
  2. 需要有一個腳本,得到上下層終點的引用,控制升降機的初始化位置以及控制升降機的升降行為。
    • 相關字段

        升降機的具體實現不像梯子,梯子只作為一個被玩家檢測的對象,加上自身幾乎沒有任何行動,主要的移動和檢測代碼都依賴在角色控制器上。而升降機與玩家的關係不同,升降機本身一方面需要被玩家檢測,並進行啟動升降機的倒計時,因此,檢測的代碼在於角色控制器中;另一方面,升降機的移動以及「載著」玩家行動的代碼又在於升降機本身。

        所以,實現升降機需要分別在角色控制器(檢測與觸發)以及升降機控制器(移動)方面著手。

        1. 角色控制器(檢測與觸發)

    • 角色向下發射一道射線,檢測電梯的LayerMask
    • 如果能檢測到電梯
      • 先拿到電梯控制器的引用
      • 判斷電梯當前是否已經在移動過程中
        • 如果不是,則開始倒計時,計算角色站在這個靜止的電梯上的時間。當時間到了,就通過剛才得到的電梯控制器引用來啟動電梯,並將角色自身的位置信息傳遞過去,讓「電梯控制角色的y軸值移動」。
        • 啟動電梯後,重置倒計時,消除角色重力
    • 如果檢測不到,恢復重力為默認值,同時重置倒計時
    • 代碼:

        2. 電梯控制器(移動)

    • 在電梯啟動後,先將玩家位置的x軸值與電梯自身的x軸值同步,以免玩家站在電梯邊緣啟動電梯,然後在移動過程中引發與其他環境不必要的碰撞
    • 開啟一個協程,讓電梯從當前所在樓層移動至目標樓層
      • 告知玩家,電梯已經啟動,現處於「正在移動」的狀態(isElevatorMoving),讓玩家不會去開始啟動電梯的倒計時
      • 根據當前電梯所在的樓層得知目標樓層是上層還是下層
      • 在這個協程中,包含了一個while判斷,判斷電梯當前位置與目標樓層位置的距離,如果大於偏差值,則繼續移動
      • 在這個while裡面,還需要判斷玩家當前有沒有打開暫停菜單(PlayerController.instance.isInGameMenu)。當玩家打開暫停菜單時,電梯也需要暫停移動
      • 否則,就讓玩家傳遞過來的自身位置信息與電梯自身的位置信息中的y軸值以同樣的幅度上升/下降
    • 到達目標樓層後,告知玩家電梯已經停止,更新當前所在樓層
    • 代碼:

        3. 最後,正如本文開篇所言,由於每一層前往其他樓層的路徑都是唯一的,加上電梯本身沒有「呼叫」功能,讓它從另一層移動到玩家所在層,因此,每次遊戲開始時,電梯的初始樓層就必須在靠近玩家復活點的那一層上。

    • 而玩家的復活點(最後激活的檢查點)是在枚舉類型來記錄的,因此,我可以將其轉成int,然後讓電梯的上層對應檢查點與玩家復活點之間的int進行比較。
      • 如果玩家復活點 >= 上層對應檢查點,代表玩家必然是在電梯上層或以上樓層復活。
      • 如果玩家復活點 < 上層對應檢查點,代表玩家必然是在電梯的下層或以下樓層復活。
    • 根據這個結果,決定電梯的初始化樓層是上層還是下層。
    • 代碼:

        電梯總體而言還是比較好實現,不過我還是想盡量把電梯和角色之間的控制分開,現在還是有一種互相引用的情況。電梯的啟動倒計時在角色腳本中進行;而角色的移動又是由電梯來控制。

        然後移動有的時候又會發生抖動,雖然沒把角色給卡出去,但是觀感還是有點不好,可能是因為將移動代碼放了在IEnumerator中。做一個bool標志符象徵電梯啟動與否,然後把移動代碼移到FixedUpdate中或許會更好。

1 thought on “[C#/Unity] 《Endless End》中的升降機實現總結”

  1. Pingback: [C#/Unity] 《Endless End》中的梯子實現總結 - LoneliNerd's Study Log

Comments are closed.