Open7

Godot4.4の自分用メモ書き

白樺バイオーム白樺バイオーム

ボタンの中心で拡縮するだけのシェーダー
CC0

shader_type canvas_item;

uniform float scale : hint_range(0.1, 10.0, 0.1) = 1.0;
uniform vec2 pivot_point = vec2(0.5, 0.5);
uniform vec2 size = vec2(0,0);

void vertex() {

    vec2 pivot_pixel = size * pivot_point;

    VERTEX = VERTEX - pivot_pixel;
	VERTEX = vec2((VERTEX.x * scale) + pivot_pixel.x,((VERTEX.y) * scale) + pivot_pixel.y);
}

使い方

拡縮する前にnode.sizeをシェーダーのsizeに渡す。

拡縮する際はscaleを好きなようにいじる。Tweenとかで。

白樺バイオーム白樺バイオーム

Godot4以降でShoeBoxで作ったfntファイルを読み込む時は

common lineHeight=96 base=26 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0

のalphaChnlを0にしないと色が読み込まれない。なんてこった。

参考 : https://github.com/godotengine/godot/issues/68458

なのでこういうスクリプトを作りました
エディタプラグインでボタン押すと自動的にいい感じにしてくれるようになんかこうしといてください

	var dir : DirAccess = DirAccess.open("res://UI/Fonts/Bitmap/")
	if dir:
		for file_name in dir.get_files():
			if file_name.ends_with(".fnt"):
				var file : FileAccess = FileAccess.open("res://UI/Fonts/Bitmap/" + file_name,FileAccess.READ_WRITE)
				var clean_file : String = ""
				while file.get_position() < file.get_length():
					var line : String = file.get_line()
					# カラー対応させる
					line = line.replace("alphaChnl=1","alphaChnl=0")
					# ファイル名を相対パスにする
					if line.ends_with('.png"'):
						var regex : RegEx = RegEx.new()
						regex.compile('(.*)(file=")(.*)')
						line = regex.sub(line,"$1") + regex.sub(line,"$2") + regex.sub(line,"$3").get_file()
					clean_file += line + "\n"
				file.store_line(clean_file)
				file.close()
				var new_file : FileAccess = FileAccess.open("res://UI/Fonts/Bitmap/" + file_name,FileAccess.WRITE)
				new_file.store_string(clean_file)
				new_file.close()
				await get_tree().process_frame
				# 再インポートする
				EditorInterface.get_resource_filesystem().reimport_files(["res://UI/Fonts/Bitmap/" + file_name])
白樺バイオーム白樺バイオーム

乗算に関するあれこれ

  • 乗算に設定したノードはmodulateでアルファをいじっても反応しないが、RGBを上げることで擬似的に薄くすることができる。
  • アルファがカットアウトされているので、ぼかした丸とかを影として使いたい時は背景を白にするとよい。
白樺バイオーム白樺バイオーム

なんかこう、いい感じにスプライトシートを切り出してSpriteFramesのリソースに変換するやつ
フォルダ構成は

  • IMGs
    • CharacterSprite
      • After
      • Before
      • Resouce

ファイル名は

  • 32_うんたらかんたら.png

または

  • 32x48_うんたらかんたら.png

になってて、Beforeに画像を入れてなんかこう、いい感じにエディタ内で実行するとResourceに.tresを吐き出してAfterに画像を移動させてくれる。
いい感じにエディタアドオンにしといてください。CC0です。
空フレームは追加されないようになってたり……なんなり……

func dir_png_find(path:String):
	var dir : DirAccess = DirAccess.open(path)
	if dir:
		dir.list_dir_begin()
		var file_name : String = dir.get_next()
		while file_name != "":
			if dir.current_is_dir():
				dir_png_find(path + file_name + "/")
			elif file_name.get_extension() == "png":
				png_to_spriteframe(path + file_name)
			elif file_name.get_extension() == "tres":
				not_use_spriteframe_remove(path + file_name)
			file_name = dir.get_next()

func png_to_spriteframe(path:String):
	var img : CompressedTexture2D = load(path)
	if img:
		var file_name_Array : Array = Array(path.get_file().split("_"))
		var cell_size_array : Array = file_name_Array.pop_front().split("x")
		var clean_file_name_regex : RegEx = RegEx.new()
		clean_file_name_regex.compile("[0-9]*x[0-9]*_(.*)")
				
		# なんかもっとスマートな方法がほしい
		var file_path_array : Array = Array(path.split("/"))
		var ext : String = file_path_array.back().get_extension()
		var file_name : String = file_path_array.pop_back().get_file().get_basename()
		var folder_path : String = str("/".join(file_path_array)).replace("res://IMGs/CharacterSprite/Before","")
		var exp_dir_path : String = "res://IMGs/CharacterSprite/Resource" + folder_path + "/"
		var after_dir_path : String = "res://IMGs/CharacterSprite/After" + folder_path
		var exp_dir : DirAccess = DirAccess.open("res://IMGs/")
		var exp_file_name = file_name
		while clean_file_name_regex.search(exp_file_name):
			exp_file_name = clean_file_name_regex.sub(exp_file_name,"$1$2")
		print(exp_file_name)
		
		
		if cell_size_array.size() > 0:
			# シートサイズの計算
			var sprite_sheet : Vector2 = Vector2(1,1)
			var sprite_sheet_size : String = file_name_Array.pop_front()
			
			# 一コマ横x一コマ縦_シート横数xシート縦数の場合は代入して色々計算する
			var sprite_sheet_regex : RegEx = RegEx.new()
			sprite_sheet_regex.compile("[0-9]*x[0-9]")
			if sprite_sheet_regex.search(sprite_sheet_size):
				var sprite_sheet_array : Array = Array(sprite_sheet_size.split("x"))
				sprite_sheet.x = int(sprite_sheet_array.pop_front())
				sprite_sheet.y = int(sprite_sheet_array.pop_front())
			var sheet_size : Rect2i = Rect2i(0,0,img.get_width() / sprite_sheet.x,img.get_height() / sprite_sheet.y)
			
			var cell_size : Vector2 = Vector2(0,0)
			if cell_size_array.size() == 1: # 32_うんたらかんたらの場合はVector2(32,32)で作成
				cell_size = Vector2(1,1) * float(cell_size_array.front())
			elif cell_size_array.size() == 2: # 32x48_うんたらかんたらの場合はVector2(32,48)で作成
				cell_size = Vector2(float(cell_size_array.front()),float(cell_size_array.back()))
			
			if cell_size != Vector2(0,0):
				var sheet_id : int = 1
				for sheet_y : int in sprite_sheet.y:
					for sheet_x: int in sprite_sheet.x:
						var sprite_frame : SpriteFrames = SpriteFrames.new()
						sprite_frame.remove_animation("default")
						#var sheet : AtlasTexture = ImageTexture.create_from_image( img.get_image().get_region(Rect2i(Vector2i(sheet_size.size.x * sheet_x,sheet_size.size.y * sheet_y),sheet_size.size)))
						var sheet : AtlasTexture = AtlasTexture.new()
						sheet.atlas = img
						sheet.region = Rect2i(Vector2i(sheet_size.size.x * sheet_x,sheet_size.size.y * sheet_y),sheet_size.size)
						await get_tree().process_frame
						# 空シートは追加しない
						if sheet.get_image().get_used_rect() != Rect2i(0,0,0,0):
							for y : int in sheet.get_height() / cell_size.y:
								var anim_name : String = str(y)
								sprite_frame.add_animation(anim_name)
								for x : int in img.get_width() / cell_size.x:
									# 切り抜き
									var atlas_texture : AtlasTexture = AtlasTexture.new()
									atlas_texture.atlas = sheet
									atlas_texture.region = Rect2(Vector2(cell_size.x * x,cell_size.y * y),cell_size)
									#print(atlas_texture.get_size())
									
									# 空セルは追加しない
									if atlas_texture.get_image().get_used_rect() != Rect2i(0,0,0,0):
										sprite_frame.add_frame(anim_name,atlas_texture,1.0,-1)
							
							exp_dir.make_dir_recursive_absolute(exp_dir_path)
							exp_dir.make_dir_recursive_absolute(after_dir_path)
							
							var save_file_path : String = exp_dir_path + exp_file_name + "_" + str(sheet_id) + ".tres"
							#すでに存在したら削除
							if exp_dir.file_exists(save_file_path):
								exp_dir.remove_absolute(save_file_path)
							
							#sprite_frame.take_over_path(save_file_path)
							ResourceSaver.save(sprite_frame,save_file_path)
							await get_tree().process_frame
							#not_use_spriteframe_remove(save_file_path)
						sheet_id += 1
			
			# 変換後はAfterフォルダに移動
			if exp_dir.file_exists(after_dir_path + "/" + file_name + "." + ext):
				exp_dir.remove_absolute(after_dir_path + "/" + file_name + "." + ext)
			exp_dir.rename_absolute(path,after_dir_path + "/" + file_name + "." + ext)
	# リロード
	EditorInterface.get_resource_filesystem().scan_sources()

#Afterフォルダに画像がないリソースを削除します。pngだけにしてるけどwebp使うならそっちでも良いと思います。
func not_use_spriteframe_remove(path:String):
	var file : FileAccess = FileAccess.open(path,FileAccess.READ)
	if file.get_as_text().find("/Before/"):
		var dir : DirAccess = DirAccess.open("res://")
		var is_finished = false
		var path_regex : RegEx = RegEx.new()
		path_regex.compile('.*path="(.*\\.(png|webp))".*')
		while is_finished == false:
			var line : String = file.get_line()
			if line.begins_with("[ext_resource"):
				var img_path : String = path_regex.sub(line,"$1").replace("/Before/","/After/")
				if dir.file_exists(img_path):
					pass
				else:
					print("ないよ")
					print(img_path)
					file.close()
					dir.remove_absolute(path)
					await get_tree().process_frame
					EditorInterface.get_resource_filesystem().scan_sources()
					is_finished = true
			if line.begins_with("[sub_resource"):
				print("finished")
				is_finished = true
		if file.is_open():
			var clean_txt : String = file.get_as_text().replace("/Before/","/After/")
			file.close()
			var clean_file : FileAccess = FileAccess.open(path,FileAccess.WRITE)
			clean_file.store_string(clean_txt)
			dir.remove_absolute(path)
			if not EditorInterface.get_resource_filesystem().is_scanning():
				EditorInterface.get_resource_filesystem().scan_sources()

気力が湧いたら記事にします。

白樺バイオーム白樺バイオーム

画像が空かどうか判定するには

Image.get_used_rect()

で色がある範囲を取得できるので、

if Image.get_used_rect() == Rect2i(0,0,0,0):
    print("画像が空")

で判定できる

白樺バイオーム白樺バイオーム

Controlノードをドラッグアンドドロップで移動させるスクリプト

extends Control

var is_grab : bool = false
var offset : Vector2

func _on_gui_input(event: InputEvent) -> void:
	if is_grab:
		if event is InputEventMouseButton:
			if event.pressed == false and event.button_index == 1:
				is_grab = false
		elif event is InputEventMouseMotion:
			self.global_position = get_global_mouse_position() - offset
	else :
		if event is InputEventMouseButton:
			if event.pressed and event.button_index == 1:
				is_grab = true
		elif event is InputEventMouseMotion:
			offset = event.position

参考: https://www.youtube.com/watch?v=uhgswVkYp0o