さくさく理解する Godot 入門(ただし2Dに限る)応用編 お絵かきパズル【第13回】
目次
- 問題パネル
- 描画処理
- プロパティ設定関数
- クリック処理
問題パネル
■描画処理
問題パネルにはサムネイル、難易度、タイトルなどが表示され、押下することでその問題を解くことができる。 QuestPanel はそのためのシーンだ。
ノードツリーは下図のようになっている。
QuestPanel のクラスは ReferenceRect
アプリ実行時のパネル外観は下図のようになっており、これは _draw() をオーバライドすることで実現している。
func _draw(): # 外枠 var style_box = StyleBoxFlat.new() style_box.set_corner_radius_all(RADIUS) style_box.bg_color = Color.darkslategray if !mouse_pushed else Color.gray style_box.border_color = Color.green if !mouse_pushed else Color.darkslategray style_box.set_border_width_all(2) style_box.shadow_offset = Vector2(4, 4) if !mouse_pushed else Vector2(0, 0) style_box.shadow_size = 8 # if !mouse_pushed else 4 draw_style_box(style_box, Rect2(POSITION, SIZE))
StyleBoxFlat クラスを使って、影・枠付きラウンド矩形を描画している。 その方法は簡単で、上記のようにインスタンスを生成し、各種パラメータを設定し、draw_style_box() をコールするだけだ。
問題サムネイルの表示部分のコードを下記に示す。
func _draw(): ..... # サムネイル var col = Color.lightgray if ans_iamge.empty() else Color("#ffffef") if time >= 0 else Color("#ffffc0") #.lightyellow draw_rect(Rect2(THUMBNAIL_X-2, THUMBNAIL_POS-2, THUMBNAIL_WIDTH+4, THUMBNAIL_WIDTH+4), col) if !ans_iamge.empty(): for y in range(IMG_HEIGHT): var py = y * TNCELLWD + THUMBNAIL_POS var mask = 1 << IMG_WIDTH for x in range(IMG_WIDTH): mask >>= 1 if (ans_iamge[y] & mask) != 0: var px = x * TNCELLWD + THUMBNAIL_X draw_rect(Rect2(px, py, TNCELLWD, TNCELLWD), Color.black)
問題がクリア済みかどうか、途中経過かどうかで背景色を決め、draw_rect() でサムネイル領域を塗りつぶしている。
次に、問題がクリア済みの場合は、サムネイル表示を行っている。 解答のイメージは ans_iamge[] にビットマップとして格納されているので、 ビットマスクをシフトしながら当該ビットが1かどうかをチェックして、1であれば draw_rect() でその部分のドットを描画している。
■プロパティ設定関数
問題パネルは、問題番号、難易度などのプロパティを持ち、それを設定する関数を用意している。
それらの実装を下記に示す。
var number :int = 0 func set_number(n : int): number = n $number.text = "#%d" % n func set_difficulty(n : int): $difficulty.text = "Difficulty: %d" % n $jDiffi.text = "難易度 %d" % n
内容は簡単で、引数で渡されたものをメンバ変数に保存し、ラベルテキストを変更するだけだ。
■クリック処理
ボタンクリック処理のコードを下記に示す。
signal pressed(num) func _input(event): if event is InputEventMouseButton: if event.is_action_pressed("click"): # left mouse button if get_global_rect().has_point(event.position): # mouse_pushed = true; saved_pos = get_global_rect() update() elif event.is_action_released("click") && mouse_pushed: if get_global_rect() == saved_pos: if get_global_rect().has_point(event.position): # print("pressed: ", $number.text) emit_signal("pressed", number) # pressed シグナル発行 mouse_pushed = false; update() elif event is InputEventMouseMotion && mouse_pushed: # mouse Moved if get_global_rect() != saved_pos || !get_global_rect().has_point(event.position): # mouse_pushed = false; update()
問題パネル上にマウスカーソルがあるときにマウスボタンが押下されると、_event() がコールされる。 ので、その中で押下アクションかどうかを判定し、押下されたことを記録しておく。
そしてリリースアクションの場合は、マウスカーソルが押下されたパネル上でリリースされた場合は、 クリックされたとみなし、pressed() シグナルを発行している。
押下状態でマウスが移動され、押下されたボタンから外れた場合は mouse_pushed フラグをオフにし、 update() を呼ぶことで再描画を行う。
TechProjin Godot入門 関連連載リンク
Godotで学ぶゲーム制作
さくさく理解するGodot入門 連載目次
標準C++ライブラリの活用でコーディング力UP!
「競技プログラミング風」標準C++ライブラリ 連載目次