【Day7】蛇足:UIフレームワーク作ります

昨日さんざん作ってわかったんですが、ちゃんとフレームワークを作ったほうが良さそう。
今後のためにも。

GodotのFocusのシステムは結構曲者で、マウスを基準として結構自由にフォーカスができるし、状態管理もしっかりしてるとは思う。
でも、キー操作(コントローラー操作)においては、表示されてるフォーカスできる要素を容赦なく際限なくフォーカスしていってしまう。
例えば、ウィンドウが2個重なっていたとして、裏のウィンドウ内の要素もフォーカスしに行ってしまう。

この辺の制御をするのが面倒で、内部にカウンターを持たせて作るパターンもあるんだけど、今度はマウスとの整合性を取るのに少し手間がある。

なので、Godot Meetup Tokyoで公開用にVellum UIというコンポーネントライブラリ&フレームワークを作ります。

今着手してるプロジェクトにそのまま入れて作っていくので、進捗的にも大きくは問題はないし、正直今後プロジェクトが大きくなった時に、確実にUIを作ったりシーンの遷移だけで大幅に時間を使うであろうことが予測されるので、今のうちに片付けておこうねってこと。

作り始めて、昨日まで作ったUIのシステムを剥がしていってるけど、アドオンとしての手応えがあるんで、4月のMeetupに向け公開していくぜ。

【Day5-6】大変だった‥‥‥

UIのシステムを組んでました。
これ毎回作ってるからいい加減モジュール化というかライブラリ化というかしたい‥‥‥

タイトルも丸々出てますが。
背景画像はダミーだけど、いい感じだね。

ゲーム的には2Dだけど、結構ふんだんに3Dを使ってます。
実際どれくらい負荷がかかるもんなのかとか、ワークフローをちゃんと組んでみたいとか、楽しいね。

さて、あらかたUIはシステム化できたと思うので、いい加減アクション部分を作りこんでいこう。

絵を作らないと正直モチベがキープできないんだけど、絵を作ると時間がかかるので、また数日跨ぎの更新になりそう。

【Day4】掛け合いができるゾ

わるくないスライムを置いて掛け合いをしてみた。
うんうん、簡単であるな。

少しだけStateMachineの整理をした。

というのも、おそらく強制的にキャラをポーズさせるより、イベント用のステートに移行させたほうが都合がよいと思われる。
今後タイムライン上からキャラのステートを切り替えたり、値を渡すことで、タイムライン上から人形劇ができるようになるはず。
そのためにはイベント用の汎用的なステートを用意するのが良さそう。

表情差分なんかはDialogic2のイベントを入れるようにしたほうがいいかなぁ。
まぁでも、一旦会話劇の仕組みはこんなもんにしておこう。

【Day3】結局吹き出しは独自スタイルに。

Day2で発見した仕様を独自のものに変えようと思ったけど複雑になりそうだったので、独自のスタイルを作成した。
結構シンプルにできたし十分かな。

イベントエリアの接触でキャラクターのステートを強制で止めたりして無理やりなところはあるんだけど、かなりシンプルだしカスタマイズ可能な状態にしてあるし良い感じ。

今日は出社だったので遅い時間から開始したし、あんまり進まなかったけど仕方ないね。

明日は攻撃ステートでも作ろうかな。
ついでにステート周りを綺麗にするのもありだな‥‥‥ちょっと冗長でしんどいからな。

ではまた。

【Day2】Dialogic2導入はできたが‥‥‥

Dialogic2には組み込みのスタイルがいくつか用意されていて、バブルスタイル(つまり吹き出し)がある。
これは2Dか3Dのノードに、Dialogicのキャラクターを設定しておくことによって、そのノードから吹き出しが出る仕組みっぽい。

ただ、微妙に使いづらい。

キャラクターリソース(dchファイル)を、Playerに設定することはできた。これはまぁ普通にロードして設定しておくだけなので。

で、現在のレイアウトを読み込もうとするとNullが返ってくる。
これはまぁ、Dialogicの仕組み上、毎回会話を表示するレイヤーのノードを消すため、会話が始まらない限りレイアウトは存在しないってのが正しい。

なので、Dialogicの設定としてLayout Node behaviourの中にOn Timeline Endって項目のがあるので、これをHide Layout Nodeに変更。
これによって一度レイアウトが作られたら以降は表示・非表示を切り替えるだけになるはず。

で、コードとして‥‥‥

GDScript
func _setup_dialogic_character() -> void:
	if dialogic_character_resource_path == "":
		return

	var character_resource: Resource = load(dialogic_character_resource_path)

	if character_resource and character_resource is DialogicCharacter:
		var dialogic_character: DialogicCharacter = character_resource as DialogicCharacter
		var layout := Dialogic.Styles.get_layout_node()
		if layout == null:
			layout = Dialogic.Styles.load_style("default_layout") # バブルスタイル
		if layout and layout.has_method("register_character"):
			layout.register_character(dialogic_character, self)

ログでわかる通り、まずCurrent LayoutはNullが返る。先ほどと同じだが、1度でもセリフを表示しないと(つまりタイムラインが実行されないと)レイアウトが生成されない。

なので、強制的にdefault_layoutをロード‥‥‥あ。

俺が作ったスタイルの名前は「default_style」なのに、ロードしようとしてるのは「default_layout」になってしまってる。
なるほど、フォールバックして別のスタイルが作られる理由がわかった。

記事を書いてよかった。

だが、新たな問題が‥‥‥

どうやら、Dialogicの組み込みのBubbleのパーツ(吹き出し自体)の位置情報を計算するロジックが結構限定的っぽい。
実際のコードを抜き出してみる。

GDScript
func get_speaker_canvas_position() -> Vector2:
	if is_instance_valid(node_to_point_at):
		if node_to_point_at is Node3D:
			base_position = get_viewport().get_camera_3d().unproject_position(
				(node_to_point_at as Node3D).global_position)
		if node_to_point_at is CanvasItem:
			base_position = (node_to_point_at as CanvasItem).get_global_transform_with_canvas().origin
	return base_position

base_positionが読みに行ってるのはget_vieport()になってる。
つまり、現在この吹き出しが存在するViewportの中の3Dカメラを見に行ってる。

逆に言うと、専用で別のViewport内で動かしてるカメラの取得に失敗する。

これは改善の余地ありですな。
おそらくカスタムスタイルでレイアウトを作成し、このパーツをインスタンス化している根っこのtext_bubble_layerを継承してパーツも継承したものを一部改変・オーバーライドして使う感じになりそうですな。

いやいや、Saitos氏、なかなかやりますな。
方針が決まっただけだいぶ前進でござるよ。Aheadでござるよ。

さ、深夜のテンションになってきたんで、明日やります。

キャラクターを指定しない状態であれば、座標を見に行かないでフォールバックしてダミーシーンが表示されるので、ポジションさえ指定できるようにオーバーライドすればいけるだろう。

そしたらまた明日。しーゆー。

読み込み中...

ゲーム開発を応援していただけたら幸いです

Buy Me a Coffee