ガイスターアプリ開発(5) 駒の移動・ターン交代

Python でつくるガイスター、連載第 5 回です。

は初期盤面を生成して描画しました。

今回は駒の移動とターン交代の画面を用意します。

ガイスターでは相手の駒が見えてはいけないので、

ターン交代のたびに引継ぎのための画面を表示します。


駒の移動

駒をクリックしたときに行先を表示し、それをクリックするとその場所に移動するようにします。

まずは行先を表す円を描画します。

draw.py
1
...
2
def dest(screen, pos, board):
3
'''
4
駒の行先を円で表示する
5
6
screen : pygame.display.set_mode
7
pos : tuple <- (int, int)
8
駒の位置
9
board : dict <- {(int, int): Piece}
10
駒の位置とオブジェクト
11
'''
12
for _pos in board[pos].covering_squares(pos):
13
# 自分の駒を除外
14
if not (tuple(_pos) in board and board[tuple(_pos)].side == board[pos].side):
15
_coord = np.asarray(_pos)*SQUARE_SIZE + MARGIN + SQUARE_SIZE/2
16
pygame.draw.circle(screen, LAWNGREEN, [int(c) for c in _coord], int(PIECE_SIZE/2))
17
...

LAWNGREENは色の定数で、定数をまとめてある別モジュールに定義してあります。

pygame.draw.circleの引数には中心の座標と半径を指定します。


これを、駒をクリックしたときに表示します。

main.py
1
...
2
def main(screen, font, font_small, orders, move_snd):
3
# ボード描画に渡すパラメータ
4
# 0 - 先攻, 1 - 後攻, 2 - 終了後
5
_turn = 0
6
# マウス選択中の駒の位置
7
_selecting_pos = None
8
# 動かし終わった
9
_move_finished = False
10
...
11
12
while True:
13
screen.fill(IVORY)
14
# 盤面
15
draw.board(screen, _board, _turn)
16
if _selecting_pos is not None:
17
# 行先
18
draw.dest(screen, _selecting_pos, _board)
19
pygame.display.update()
20
21
# イベントハンドリング
22
for event in pygame.event.get():
23
...
24
# マウスクリック
25
if event.type == MOUSEBUTTONDOWN:
26
# 左
27
if event.button == 1:
28
_mouse_pos = event.pos
29
_square_pos = tuple(mouse.chcoord(_mouse_pos))
30
if _move_finished: continue
31
if _square_pos in _board and _board[_square_pos].side == _turn:
32
# 駒を選択したとき
33
_selecting_pos = _square_pos
34
else:
35
# 行先を選択したとき
36
if (_selecting_pos in _board
37
and _square_pos in _board[_selecting_pos].covering_squares(_selecting_pos)):
38
# 駒の移動
39
move_snd.play()
40
_board[_square_pos] = _board[_selecting_pos]
41
del _board[_selecting_pos]
42
# 移動完了
43
_move_finished = True
44
_selecting_pos = None
45
...

ターン交代

次にターン交代の画面を用意します。

まずは引継ぎ画面を描画する関数を定義します。

draw.py
1
...
2
def confirmation(screen, font, font_small, turn):
3
'''
4
手番交代の確認画面を表示する
5
6
screen : pygame.display.set_mode
7
font, font_small : pygame.font.SysFont
8
フォント
9
turn : int <- 0 | 1
10
0 - 次は先攻, 1 - 次は後攻
11
'''
12
assert turn == 0 or turn == 1, 'draw.confirmation の引数 turn は 0, 1 の値を取ります'
13
screen.fill(WHITE, (*MARGIN, 6*SQUARE_SIZE, 6*SQUARE_SIZE))
14
_str1 = ('先' if turn == 0 else '後') + '攻のターンだよ'
15
_str2 = '画面をクリックしてね'
16
_str3 = '動かし終わったらスペースキーを押してね'
17
_text1 = font.render(_str1, True, BLACK)
18
_text2 = font.render(_str2, True, BLACK)
19
_text3 = font_small.render(_str3, True, BLACK)
20
screen.blit(_text1, DISP_SIZE/2-(len(_str1)*32/2, 32))
21
screen.blit(_text2, DISP_SIZE/2-(len(_str2)*32/2, -32))
22
screen.blit(_text3, DISP_SIZE/2-(len(_str3)*16/2, -32*4))
23
...

盤面を白い矩形で覆い隠し、その上にテキストを描いています。

プレイヤーは駒を動かし終わったらスペースキーを押してこの画面を表示し、

もう一方のプレイヤーが画面をクリックするとそのプレイヤーに交代することになります。

game.py
1
...
2
def main(screen, font, font_small, orders, move_snd, chturn_snd):
3
# ボード描画に渡すパラメータ
4
# 0 - 先攻, 1 - 後攻, 2 - 終了後
5
_turn = 0
6
# 次の番を確認する画面を表示するときに渡すパラメータ
7
# 0 - 先攻, 1 - 後攻, 2 - なし
8
_next = 0
9
...
10
11
while True:
12
...
13
if _next == 0 or _next == 1:
14
# 交代確認画面
15
draw.confirmation(screen, font, font_small, _next)
16
...
17
18
# イベントハンドリング
19
for event in pygame.event.get():
20
...
21
# マウスクリック
22
if event.type == MOUSEBUTTONDOWN:
23
# 左
24
if event.button == 1:
25
_mouse_pos = event.pos
26
_square_pos = tuple(mouse.chcoord(_mouse_pos))
27
# 確認画面のクリック
28
if _next == 0 or _next == 1:
29
_next = 2
30
continue
31
...
32
# キー
33
if event.type == KEYDOWN:
34
...
35
# Space キー
36
if event.key == K_SPACE:
37
if _move_finished:
38
# ターン交代
39
chturn_snd.play()
40
_turn = (_turn+1)%2
41
_next = _turn
42
_move_finished = False
43
...

ゲーム開始直後も確認画面を表示するために、_next = 0としています。


は勝利条件を判定して、勝者を表示するところまでやりたいと思います。

読んでくださってありがとうございました。

では👋