🤖

Godot 4 触ってみた(主にGDScript2.0)

2021/09/08に公開

Godot4を待ちわびているんですが、なかなかリリースされません。
新機能としてVulkan APIを採用したグラフィック強化が注目されており、弱点とされていた3Dが強化されUnityやUnreal Engineの競合として台頭するのではないかと噂されております。

目玉としてはVulkanがよく取り上げられてますが、個人的にはGDScript2.0と題される新しいスクリプト機能に注目してます。

lambda式(無名関数)の導入、Callableオブジェクトなど、関数をファーストクラスの値として導入する試みが採用されており、Godot特有のsignalシステムなどにも統合されています。

ということで待ちきれずGodot4のnightly buildを落としてきて触ってみることにしました。

Godot4を入手する

Godot4はまだ正式リリースされてないので、入手する方法は以下の2通り

  • Godotのgithubリポジトリからcloneしてビルドする
  • 非公式ビルドを配布しているサイトからダウンロードする

自前でビルドは結構難しそうなので、今回は非公式ビルドをDLします。
https://hugo.pro/projects/godot-builds/
配布サイトのメンテナンス費用をpatreonで募っているそうなので、この記事を見てる人で役に立ったという人は寄付してあげましょう。

インストール

macOSなので、dmgファイルをDLしてインストールする。

プロジェクト作成

おなじみの起動画面
プロジェクトを作成しようとすると、Rendererは Vulkan ClusteredVulkan Mobileが選べます。

前者がデスクトップ用の高品質、後者がモバイル用の高効率というところですかね?
今回はClusteredを選びます。

3Dシーンを作成してみる

若干のAPIの更新が見られます。

例えば、Godot3.x系では、3DシーンのノードはRigidBody, KinematicBodyのような名前でしたが、Godot4では 3Dというsufixがついていたり、KinematicBodyCharacterBodyという名称に変わったりしています。

2Dシーンのノードは3.xの頃からRigidBody2Dのように2Dsufixがついていたので、統一されていてよりわかりやすいと思います。

多分3.x系とだいたい同じ感じで使えるでしょう。

GDScript 2.0

Godot の公式サイトのNewsとかを見て、色々と魅力的な新機能が追加されているのは知っていたんですが、百聞は一見にしかず。触っていきます。

Callable

extends Node

func hello():
  print("hello, godot4!")

func exec_callable(f: Callable):
  f.call()

func _ready():
  exec_callable(hello)

宣言したメソッドは、Callableオブジェクトの値として使えます。
これにより、高階関数(関数を引数として受け取る関数)などのテクニックを利用できます。
代表的な高階関数(メソッド)である mapfilter と、次に紹介するラムダ式を組み合わせるとスッキリしたコードを書くことが出来ます。

ラムダ式(無名関数)

GDScript2.0では、名前無しのfunc宣言を書くことで、それをCallableオブジェクトとして使うことが出来ます。

# Arrayから3より小さい値を取り出すコード

func _ready():
  # ラムダ式 + 高階関数
  var result1 = [1, 2, 3, 4, 5].filter(func (x: int): return x < 3)
  
  # Godot3.x系での同じ結果になるコード
  var result2 = []
  for item in [1, 2, 3, 4 ,5]:
    if item < 3:
      result2.push_back(item)
      
  print(result1) # [1, 2]
  print(result2) # [1, 2]

例えばArrayの要素をフィルタリングするコードは、ラムダ式とfilterメソッドを使うことでコードの合成は関数を用いたものになり、filterに渡す関数を変えることでfilterの挙動をかんたんに変更することが出来ます。
コードブロックのネストも浅いです。

3.x系以前はfor loopを使った手続き的な処理になり、コードブロックのネストが深く複雑な見た目になります。

Signal Object

GDScript2.0では、Signalはclass定義されたオブジェクトとなり、signal宣言をするとsignalがそのノードのメンバ変数として使えるようになります。

signal.connect()signal.emit()というメソッドが使える様になり、以前よりも格段に使いやすくなっています。

extends Node

signal my_singal(String)

func _ready():
  # Godot4
  self.my_singal.connect(func(msg: String): print(msg))
  self.my_singal.emit("hello, signal!")
	
  # Godot3.x以前(Godot4ではエラーになる)
  self.connect("my_signal", "on_my_signal_func")
  self.emit_signal("my_signal", "hello, signal!")
	
func on_my_signal_func(msg):
  print(msg)

connectメソッドの引数の型はCallableになっています。
当然、lambda式を渡すこともでき、ちょっとしたデバッグや関数を作るほどでもない処理をsignalに登録するのはすごく簡単です。

Godot3.x以前のsignalの仕様には前から気に入らないと思ってた所がありまして、それは何かというとconnect, emit_signalメソッドの引数にシグナルや関数名をStringで渡さなければならないというところです。

コンパイルエラーは出ず、プログラマーが名前を間違えないように気をつける以外に防止する方法はなかったのですが、CallableやSignalがオブジェクトとして引数に渡せるようになったことでより型に守られてプログラミングできるようになったと言えるでしょう

まとめ

  • Vulkanばかり注目されてるけど、GDSCript2.0もかなりいい新機能盛りだくさんだよ
  • lambda式, Callable によって関数がファーストクラスの値に
  • signalの取り扱いがより簡単に
  • はよGodot4リリースして

眠いのでここまで

Discussion

ログインするとコメントできます