目次
- 全消去
- 上下左右移動
■全消去
何の絵を問題にするかなって考えてるときは、これいいじゃね?と思い、描き始めるのだが、 思った以上にドット絵にするのが難しく、途中で諦めてしまうことは少なくない。 そんなときは全消去を行い、新たな気持で別の絵に挑戦だ。
というわけで、全消去機能を説明する。
Undo/Redo 同様に、TextureButton を設置し、pressed シグナルを _on_ClearButton_pressed() に接続する。
_on_ClearButton_pressed() の実装は、下記の通りで、clear_all() をコールするだけだ。
func _on_ClearButton_pressed():
clear_all()
下記に clear_all() のコードを示す。
func clear_all():
var item = [CLEAR_ALL]
for y in range(N_IMG_CELL_VERT):
item.push_back(get_h_data(y))
push_to_undo_stack(item)
clear_all_basic()
func clear_all_basic():
for y in range(N_TOTAL_CELL_VERT): # キャンパス部分消去
for x in range(N_TOTAL_CELL_HORZ):
if $BoardBG/TileMap.get_cell(x, y) == TILE_BLACK:
setup_fallingBlack(xyToPos(x, y))
$BoardBG/TileMap.set_cell(x, y, TILE_NONE) # 盤面状態・手がかり数字消去
$BoardBG/MiniTileMap.set_cell(x, y, TILE_NONE) # 盤面背景消去
if mode == MODE_EDIT_PICT:
for y in range(N_TOTAL_CELL_VERT): # 左側手がかり数字消去
for x in range(N_CLUES_CELL_HORZ):
$BoardBG/TileMap.set_cell(-x-1, y, TILE_NONE)
for x in range(N_TOTAL_CELL_HORZ): # 上側手がかり数字消去
for y in range(N_CLUES_CELL_VERT):
$BoardBG/TileMap.set_cell(x, -y-1, TILE_NONE)
for y in range(N_IMG_CELL_VERT): # 盤面背景消去
h_clues[y] = [0]
for x in range(N_CLUES_CELL_HORZ):
$BoardBG/TileMapBG.set_cell(-x-1, y, TILE_NONE)
for x in range(N_IMG_CELL_HORZ): # 盤面背景消去
v_clues[x] = [0]
for y in range(N_CLUES_CELL_VERT):
$BoardBG/TileMapBG.set_cell(x, -y-1, TILE_NONE)
else:
for y in range(N_IMG_CELL_VERT): # 盤面背景消去
for x in range(N_CLUES_CELL_HORZ):
$BoardBG/TileMapBG.set_cell(-x-1, y, TILE_NONE)
for x in range(N_IMG_CELL_HORZ): # 盤面背景消去
for y in range(N_CLUES_CELL_VERT):
$BoardBG/TileMapBG.set_cell(x, -y-1, TILE_NONE)
Undo を可能にするため、キャンパスのその時の状態を get_h_data(y) で行ごとに数値化し、 それらを配列にして Undo スタックに積んでおく。
キャンパスの状態を実際に全消去するのは clear_all_basic() だ。これは Redo 処理の場合にもコールされる関数だ。
_on_UndoButton_pressed() での Undo 処理コードは下記のようになる。
func _on_UndoButton_pressed():
.....
elif item[0] == CLEAR_ALL:
for y in range(N_IMG_CELL_VERT):
var d = item[y+1]
var mask = 1 << (N_IMG_CELL_HORZ - 1)
for x in range(N_IMG_CELL_HORZ):
set_cell_basic(x, y, (TILE_BLACK if (d&mask) != 0 else TILE_NONE))
mask >>= 1
.....
update_undo_redo()
全消去前の状態は、行ごとに Undo スタックに積まれている配列に入っているので、 それらを順に取り出して、ビットごとに set_cell_basic(x, y, v) をコールして状態を設定していく。
■上下左右移動
問題絵を描いていると、全体を上下左右に移動したいと思うことがままある。 ので、全体を上下左右に移動する機能を実装する。
実装手順は、例によって上下左右移動アイコンを画面下部に設置し、コマンドハンドラと接続する、という順番だ。。
左移動のコマンドハンドラは _on_LeftButton_pressed() で、コードは下記のようになる。
func _on_LeftButton_pressed():
push_to_undo_stack([ROT_LEFT])
rotate_left_basic()
Undo/Redo のために [ROT_LEFT] を Undo スタックに積み、rotate_left_basic() をコールする。
rotate_left_basic() の実装は下記のとおりだ。
rotate_left_basic() は Undo/Redo にも呼ばれる関数で、実際に画像データを左にローテイトする。
func rotate_left_basic():
var ar = [] # 退避用配列
for y in range(N_IMG_CELL_VERT): # 一番左の状態を配列に退避
ar.push_back($BoardBG/TileMap.get_cell(0, y)) # may be -1 or +1
for x in range(N_IMG_CELL_HORZ-1): # 状態をひとつ左にシフト
for y in range(N_IMG_CELL_VERT):
$BoardBG/TileMap.set_cell(x, y, $BoardBG/TileMap.get_cell(x+1, y))
for y in range(N_IMG_CELL_VERT): # 退避した状態配列を元に、一番右の状態を設定
$BoardBG/TileMap.set_cell(N_IMG_CELL_HORZ-1, y, ar[y])
update_all_clues() # 手がかり数字再計算
update_miniTileMap() # ミニマップ更新
最初に一番左の列の状態を ar に退避し。ついで、全体を1ドット左に移動する。 最後に退避した状態配列を使って、一番右の状態を設定する。
update_all_clues() の実装は下記の通り。
for 文で回しながら、以前(第3回)に実装した update_h_clues(), update_v_clues() をコールしているだけだ。
func update_all_clues():
for y in range(N_IMG_CELL_VERT):
update_h_clues(y)
for x in range(N_IMG_CELL_HORZ):
update_v_clues(x)
update_miniTileMap() の実装は下記の通り。
for 文で回しながら、セルの状態を参照し、それをミニマップに反映させている。
func update_miniTileMap():
for y in range(N_IMG_CELL_VERT):
for x in range(N_IMG_CELL_HORZ):
var img = 0 if $BoardBG/TileMap.get_cell(x, y) == TILE_BLACK else TILE_NONE
$BoardBG/MiniTileMap.set_cell(x, y, img)
TechProjin Godot入門 関連連載リンク
Godotで学ぶゲーム制作
さくさく理解するGodot入門 連載目次
標準C++ライブラリの活用でコーディング力UP!
「競技プログラミング風」標準C++ライブラリ 連載目次