controlについての覚書です。
コントロールはユーザーインターフェースに使われます。
UI
シーンへの追加
UIのシーンを作成して、基準のシーンへ追加します。
基準のシーンとしてL012のEnemyA1を使用しています。
- 1UIシーンの作成
UIにあたるシーンを作成します。 - 2追加したい基準のシーンへ追加
シーンの追加 追加コード
#UIの設定 var UI = preload("res://UI/hud.tscn") ---------------------------------------------------- var addUI = UI.instantiate() add_child(addUI)
追加したシーンの操作
add_childで追加したHUDのシーン内にあるLabelのテキストをstageにします。
追加されたHUDシーンの子であるLabelを$$HUD/VBox/Labelで指定します。
プロパティであるtextを"stage"に書き換えます。

$HUD/VBox/Label.text = "stage"
github
Label
テキストを表示します。
RichTextLabel
BBCodeを用いて様々な表現が行えます。
Godotのデモ rich_text_bbcode よりリッチテキストの例を確認します。
文字をゆらしたりできます。(Text effects)

bbcode_enabledにすると反映されます。

[pulse]Pulse[/pulse]
[wave]Wave[/wave]
[tornado]Tornado[/tornado]
[shake]Shake[/shake]
[fade start=75 length=7]Fade[/fade]
[rainbow]Rainbow[/rainbow]
パラメーター付き
[pulse freq=1.0 color=#ffffff40 ease=-2.0]{text}[/pulse]
[wave amp=50.0 freq=5.0 connected=1]{text}[/wave]
[tornado radius=10.0 freq=1.0 connected=1]{text}[/tornado]
[shake rate=20.0 level=5 connected=1]{text}[/shake]
[fade start=4 length=14]{text}[/fade]
[rainbow freq=1.0 sat=0.8 val=0.8]{text}[/rainbow]
tree
ツリー状のリストを作成します。

Godotのデモ「ControlGallery」を参照します。
@tool
extends Tree
# Called when the node enters the scene tree for the first time.
func _ready():
var root: TreeItem = create_item()
root.set_text(0, "Tree - Root")
var child1: TreeItem = create_item(root)
child1.set_text(0, "Tree - Child 1")
var child2: TreeItem = create_item(root)
child2.set_text(0, "Tree - Child 2")
var subchild1: TreeItem = create_item(child1)
subchild1.set_text(0, "Tree - Subchild 1")
サンプル
実際に使用する処理を追加しました。
使用フォント:MPLUSRounded1c-Bold

右上のtextEditに項目を入力してボタンを押すと、ツリーに項目を追加(layerAdd)、または、要素を追加・削除(add・sub)します。ツリーの項目を選択してボタン(layersub)を押すと、項目が削除されます。

extends Control
@onready var tree = $VBoxContainer2/ScrollContainer/Tree
@onready var scroll_container = $VBoxContainer2/ScrollContainer
@onready var display_text_edit = $VBoxContainer/VSplitContainer/DisplayTextEdit # 表示専用
@onready var input_text_edit = $VBoxContainer/VSplitContainer/InputTextEdit # 書き込み用
@onready var add_button = $VBoxContainer2/HBoxContainer/add
@onready var sub_button = $VBoxContainer2/HBoxContainer/sub
@onready var layerAdd_button = $VBoxContainer2/HBoxContainer2/layerAdd
@onready var layersub_button = $VBoxContainer2/HBoxContainer2/layersub
var resizing: bool = false
var last_mouse_x: int = 0
var layers_data = {
"グループA": {
"レイヤー1": ["りんご", "みかん", "ばなな"],
"レイヤー2": ["ひまわり", "チューリップ"]
},
"グループB": {
"レイヤー3": ["パイナップル", "ぶどう"],
"レイヤー4": ["桜", "バラ"]
}
}
func _ready():
scroll_container.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO
scroll_container.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO
setup_tree()
tree.allow_rmb_select = true # 右クリック選択を有効化
tree.connect("item_selected", Callable(self, "_on_item_selected"))
tree.connect("item_activated", Callable(self, "_on_item_activated")) # ダブルクリック時のイベント
tree.connect("item_edited", Callable(self, "_on_item_edited"))
add_button.pressed.connect(_on_add_button_pressed)
sub_button.pressed.connect(_on_sub_button_pressed)
#separator.gui_input.connect(_on_separator_gui_input) # 追加: スプリッターのドラッグ処理
# 表示専用にする
display_text_edit.editable = false
#tree.allow_rmb_select = true # 右クリック選択を有効化
#tree.connect("gui_input", Callable(self, "_on_tree_gui_input")) # 右クリックイベント
layerAdd_button.pressed.connect(_on_layer_add_button_pressed) # レイヤー追加ボタンの接続
tree.connect("item_selected", Callable(self, "_on_item_selected")) # 選択時のシグナルを追加
layersub_button.pressed.connect(_on_layer_sub_button_pressed) # layersubボタンの接続
func setup_tree():
tree.clear()
var root = tree.create_item()
for group_name in layers_data.keys():
var group_item = tree.create_item(root)
group_item.set_text(0, group_name)
group_item.set_editable(0, false) # 初期状態では編集不可
for layer_name in layers_data[group_name].keys():
var layer_item = tree.create_item(group_item)
layer_item.set_text(0, layer_name)
layer_item.set_metadata(0, layers_data[group_name][layer_name]) # 配列を保存
layer_item.set_editable(0, false) # 初期状態では編集不可
root.set_text(0, "Root Name")
func _on_item_activated():
var selected_item = tree.get_selected()
if selected_item:
selected_item.set_editable(0, true) # ダブルクリックで編集可能にする
tree.edit_selected() # 編集モードに入る
func _on_item_edited():
var selected_item = tree.get_edited()
if selected_item:
var new_name = selected_item.get_text(0)
var parent_item = selected_item.get_parent()
if parent_item == null:
return # ルートアイテムは変更しない
for group_name in layers_data.keys():
if layers_data[group_name].has(selected_item.get_text(0)):
var old_name = selected_item.get_text(0)
var value = layers_data[group_name][old_name]
layers_data[group_name].erase(old_name) # 削除
layers_data[group_name][new_name] = value # 新しいキーで追加
return
for layer_name in layers_data[group_name].keys():
if layers_data[group_name][layer_name] == selected_item.get_metadata(0):
var value = layers_data[group_name][layer_name]
layers_data[group_name].erase(layer_name) # 削除
layers_data[group_name][new_name] = value # 新しいキーで追加
return
selected_item.set_editable(0, false) # 編集後は再び編集不可にする
func _on_add_button_pressed():
var selected_item = tree.get_selected()
if selected_item == null:
print("レイヤーが選択されていません")
return
var new_text = input_text_edit.text.strip_edges() # 前後の空白を除去
if new_text == "":
print("追加するテキストがありません")
return
var new_items = new_text.split("\n", false) # 改行で分割
var layer_data = selected_item.get_metadata(0)
if layer_data is Array:
layer_data.append_array(new_items) # 複数行をリストに追加
selected_item.set_metadata(0, layer_data)
display_text_edit.text = "\n".join(layer_data)
print("追加後のデータ:", layer_data)
input_text_edit.clear() # 入力欄をクリア
func _on_sub_button_pressed():
var selected_item = tree.get_selected()
if selected_item == null:
print("レイヤーが選択されていません")
return
var remove_text = input_text_edit.text.strip_edges() # 前後の空白を除去
if remove_text == "":
print("削除するテキストがありません")
return
var remove_items = remove_text.split("\n", false) # 改行で分割
var layer_data = selected_item.get_metadata(0)
if layer_data is Array:
for item in remove_items:
if item in layer_data:
layer_data.erase(item) # 指定された項目を削除
selected_item.set_metadata(0, layer_data)
display_text_edit.text = "\n".join(layer_data)
print("削除後のデータ:", layer_data)
input_text_edit.clear() # 入力欄をクリア
func _on_separator_gui_input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
resizing = event.pressed
last_mouse_x = event.position.x
elif event is InputEventMouseMotion and resizing:
var delta_x = event.position.x - last_mouse_x
tree.custom_minimum_size.x += delta_x
last_mouse_x = event.position.x
func _on_layer_add_button_pressed():
var selected_item = tree.get_selected()
if selected_item == null:
print("グループまたはレイヤーが選択されていません")
return
var parent_item = selected_item.get_parent()
var new_layer_name = input_text_edit.text.strip_edges()
if new_layer_name == "":
print("グループ名またはレイヤー名を入力してください")
return
if parent_item == null: # ルートノードが選択されている場合
layers_data[new_layer_name] = {} # 新しいグループを追加
setup_tree()
input_text_edit.clear()
print("グループを追加:", new_layer_name)
else: #グループまたはレイヤーが選択されている場合
var group_name = ""
if parent_item.get_parent() == null: #グループが選択されている場合
group_name = selected_item.get_text(0)
else: #レイヤーが選択されている場合
group_name = parent_item.get_text(0)
if layers_data.has(group_name):
if layers_data[group_name].has(new_layer_name):
print("すでにレイヤーが存在します")
return
layers_data[group_name][new_layer_name] = []
setup_tree()
input_text_edit.clear()
print("レイヤーを追加:", new_layer_name)
else:
print("グループが存在しません")
func _on_item_selected():
var selected_item = tree.get_selected()
if selected_item:
print("選択されたアイテム:", selected_item.get_text(0)) # 選択されたアイテムの名前をprint出力
var layer_data = selected_item.get_metadata(0)
if layer_data is Array:
display_text_edit.text = "\n".join(layer_data)
else:
display_text_edit.text = ""
func _on_layer_sub_button_pressed():
var selected_item = tree.get_selected()
if selected_item == null:
print("グループまたはレイヤーが選択されていません")
return
var parent_item = selected_item.get_parent()
if parent_item == null: #ルートノードが選択されている場合
var group_name = selected_item.get_text(0)
layers_data.erase(group_name)
print("グループを削除:", group_name)
elif parent_item.get_parent() == null: #グループが選択されている場合
var group_name = selected_item.get_text(0)
layers_data.erase(group_name)
print("グループを削除:", group_name)
else: #レイヤーが選択されている場合
var group_name = parent_item.get_text(0)
var layer_name = selected_item.get_text(0)
layers_data[group_name].erase(layer_name)
print("レイヤーを削除:", layer_name)
if layers_data[group_name].is_empty(): #グループが空になったらグループごと削除
layers_data.erase(group_name)
print("グループを削除:", group_name)
setup_tree()
input_text_edit.clear()
TextureProgressBar
ゲージを表示します。

画像をゲージに設定します。
barはunderとProgressに設定します。
枠のような形状はOverに設定します。
画像 bar

画像 bar w

(画像はPixeloramaで作成しました。)
時間経過で減少します。
マウスの左クリックでゲージが増加、
右クリックで減少します。
作業
下記のスクリプトとmainにセットします。時間経過でゲージが減少するようにしています。
extends Node2D
var hp:float = 100
var maxhp:float = 100 # 最大HP
func _ready():
$"sample".max_value =maxhp
$"sample/Label".text = "Hp:" + str(hp)
func _process(delta):
#時間経過でhpを減らす
if hp >= 0:
hp -= delta
# HPバー更新
var hpbar:TextureProgressBar = $"sample"
var hpPer = _hpPer()
hpbar.value = maxhp * hpPer
# HPバー更新
hpbar.tint_progress = lerp(Color.YELLOW, Color.YELLOW, hpPer)
hpbar.tint_under = lerp(Color.RED, Color.RED, hpPer)
#hpbar.tint_over = lerp(Color.WHITE, Color.WHITE, hpPer)
$"sample/Label".text = "Hp:" +"%4.0f" % hp
if hp <= 0:
$"sample/Label".text = "Hp:0"
func _hpPer():
return 1.0 * hp / maxhp;
ゲームの進行で最大値が変化する場合には、$"sample".max_value =maxhpを更新する必要があります。
Godot 4 の lerp() 関数について
Lerp() 関数は、2 つの値の間を線形補間する関数です。つまり、2 つの値と補間率 (0 から 1 の範囲) を指定すると、その補間率に応じて 2 つの値の間の値を返します。
Godot 4 では、lerp() 関数は以下の 2 種類が用意されています。
- lerp(): 2 つの数値間の補間を行います。
- Vector2.lerp(): 2 つの Vector2 型の値間の補間を行います。
- Vector3.lerp(): 2 つの Vector3 型の値間の補間を行います。
lerp() 関数の使い方
lerp() 関数の使い方は以下の通りです。
GDScript
var value = lerp(start_value, end_value, amount)
value
: 補間された値
start_value
: 開始値end_value
: 終了値amount
: 補間率
github
ボタン
Buttonのカラー設定
インスペクターからtheme_override_styles/normalにStyleBoxFlatを設定して変更。
コメント