Your first 2D game 練習,3.x->4.3变化

Godot 是一個年紀很輕的開源遊戲引擎,最近試著接觸看看,查詢資料時發現前幾個月 Godot 做了一次大版本更新 Godot 4,整個引擎重寫過。

但原本打算做為 LTS 版本的 3.X 版,可能因為使用者眾多,聽說後續又從 4.X 移植了些新功能回去,變成了雙版本同時發展。

以上資訊沒有經過很嚴謹的查核 XD

因為初學想練習,不疑有它就選了 4 版,
引擎本體非常精巧,只有一個 113 MB 的 .exe 執行檔,免安裝!

不過在按照官網文件《您的第一個 2D 遊戲》實作時,遇到了一些語法、build-in 物件找不到的問題,後來發現是 3.X 版與 4.X 版的語法有落差。

比對了一下官網教學文件,zh-TW / zh-CN 版沒更新,en 版則有註明已更新至 for Godot 4.1。

所以這篇是稍微記錄一下,如果一步步照著中文教學走可能會卡住的地方。

Setting up the project

  • Project Setting
    • 要調整畫面寬高,到 Display => Window
      • 3版參數名稱 Size: Width / Height
      • 4版參數名稱 Size: Viewport Width / Viewport Height
    • Stretch 調整畫面拉伸設定
      • 3版 Mode 選項下拉選單要選 2d
      • 4版 Mode 選項下拉選單要選 canvas_items

Creating the player scene

  • 對 Player Node 新增子 Node AnimatedSprite (3版) => AnimatedSprite2D (4版)
  • AnimatedSprite2D 的 Inspector (屬性檢視器) 找到 Frames (3版) => Sprite Frames (4版)

Coding the player

  • 要將 script 中的變數「匯出」(能在 inspector 面板設定) 的語法有差異
    • export var speed = 400 (3版)
    • @export var speed = 400 (4版)
  • 在 inspector 面板設定 Player 被敵人碰撞的 Signal
    • body_entered(body: Node) (3版)
    • body_entered(body: Node2D) (4版)
  • 在 body_entered 內要觸發 hit Signal 的語法有變,但 3 版寫法也還能用
    • emit_signal("hit") (3版, 但4版也可用)
    • hit.emit() (4版)

Creating the enemy

  • 新增 Mob 的子 Node VisibilityNotifier2D (3版) => VisibleOnScreenNotifier2D (4版)
  • 設定 Mob 移動動畫隨機三選一播放的語法不同 (要取得 sprite 的所有 frames name 後播放)
    • 3版

      $AnimatedSprite.playing = true
      var mob_types = $AnimatedSprite.frames.get_animation_names()
      $AnimatedSprite.animation = mob_types[randi() % mob_types.size()]
      
    • 4版

      var mob_types = $AnimatedSprite2D.sprite_frames.get_animation_names()
      $AnimatedSprite2D.play(mob_types[randi() % mob_types.size()])
      

The main game scene

  • 在 Main 場景下新增子 Node Position2D (3版) => Marker2D (4版)
  • 在 Main 場景的 script 頂部要 export Mob 場景的語法不同
    • export(PackedScene) var mob_scene (3版)
    • @export var mob_scene: PackedScene (4版)
  • 在 _on_mob_timer_timeout 事件中 new 一個 Mob,要在 MobPath(Path2D) 指定隨機出生點的語法不同
    • mob_spawn_location.offset = randi() (3版)
    • mob_spawn_location.progress_ratio = randf() (4版)
  • TIP 中說在計算角度時,如果需要在弧度 radians 跟角度 degrees 做轉換,方法名稱不同
    • deg2rad()、rad2deg() (3版)
    • deg_to_rad()、rad_to_deg() (4版)
  • 3版在 Main._ready() 時有加上 randomize(),說才能確保每次 random 產生的隨機值都不同,但4版文件沒提醒要加這句了

Heads up display

  • 要更換 Label 的字體,在 Inspector 的 Theme Overrides 區塊內
    • FontsNew DynamicFont 後再對 Font DataLoad 再選擇字型檔 (3版)
    • FontsLoad 再選擇字型檔 (4版)
  • 設定好 Fonts 後,3版有教學可以在 Font 下拉選單選 copy,再直接到另一個 Control 的 Font 屬性選 paste。4版教學沒提到這點
  • 設定 Layout 時 3/4版介面不同 (4版: Anchors Preset)
  • Label 的文字對齊 (align) 3版只能設定 Align=Center,4版再細分成 Horizontal AlignmentVertical Alignment
  • 文字換行 Autowrap 3版只能選啟用,4版有更多 mode 可選: Off, Arbitrary, Word, Word(Smart)
  • yield 語法在 4版已被 await 取代
    • yield($MessageTimer, "timeout") (3版)
    • await $MessageTimer.timeout (4版)

Finishing up

  • 加入音效檔,3版沒有這段補充,4版有:
    • audio 檔在 import 時預設 Loop 都是 disabled 的,想要不間斷持續播放,在 Stream 下拉選單點選 Make Unique,然後再點一次 Stream 檔、勾選 Loop