こんにちは。
「Pythonでつくる ゲーム開発 入門講座」の
Chapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。
前回は町の人々が少し長いことを話せる(表示ページを更新する)ようにしました。
今回は町の人々と会話するようにします。
具体的には町の人々の質問に対して「はい」「いいえ」を返します。
目次
人物シート
町の人々の質問に対して
「はい」か「いいえ」かで
答えるようにします。

スプレッドシートの人物シートで
言葉を以下の赤枠のようにします。

変更後
*「ようこそ 旅の宿に。
*「ひと晩 10ゴールドですが
お泊まりに なりますか?
#yesno
#yes
*「それでは ごゆっくり
おやすみください。
#no
*「さようなら 旅の人。
お気をつけて 旅を
つづけられますように。
#end
※会話の内容はこちらを
参考にさせて頂きました。
前回、「#page」や「#end」を
追加しましたが、
今回も新しく
「#yesno」「#yes」「#no」
を追加します。
#yesno:質問が始まる
#yes:質問に対して「はい」を返した時
#no:質問に対して「いいえ」を返した時
として使います。
「#yesno」「#yes」「#no」は
画面に表示させません。
人物シートは以上です。
moveの変更
move.pyを変更します。
今回の変更もmove.pyのみです。
まずグローバル変数を追加します。
talk_flag = False # 会話中か(会話中は動かない)
talk_end = False # 会話の最後か(aを押したら会話が終わりか)
talk_mes = []
talk_line = 0 # セリフの行数(talk_mesの何行目か)
talk_start = 0 # セリフを表示する最初の行数(会話の途中の場合は会話の途中の行数)
talk_yesno = False # yesnoクエスチョン中か
talk_yesno_i = 0 # yesnoクエスチョンの位置 0:はい、1:いいえ
talk_yesno = False # yesnoクエスチョン中か
talk_yesno_i = 0 # yesnoクエスチョンの位置 0:はい、1:いいえ
を追加しています。
「talk_yesno」がTrueの時に
「はい」「いいえ」を
画面に表示して
どちらかを選択できるようにします。
「talk_yesno_i」は
「はい」を選択したら0
「いいえ」を選択したら1
を格納します。
次に「はい」「いいえ」を
表示します。
def draw_message(bg, fnt):
global talk_line, talk_end, talk_yesno # talk_yesnoを追加
x_i = bg.get_width()*0.1/2 # x座標の開始位置
x_w = bg.get_width()*0.9 # 横幅
y_i = bg.get_height()*0.6 # y座標の開始位置
y_h = bg.get_height()*0.4-10 # 高さ
x_i_t = x_i + 30 # テキストのx座標の開始位置
y_i_t = y_i + 30 # テキストのy座標の開始位置
pygame.draw.rect(bg, BLACK, [x_i, y_i, x_w, y_h], 0, 5) # 枠
pygame.draw.rect(bg, col, [x_i, y_i, x_w, y_h], 2, 5) # 枠
#####追加「はい」いいえ」#####
x_yesno_i = bg.get_width()*0.7 # x座標の開始位置
x_yesno_w = bg.get_width()*0.2 # 横幅
y_yesno_i = bg.get_height()*0.1 # y座標の開始位置
y_yesno_h = bg.get_height()*0.15 # 高さ
x_yesno_i_t = x_yesno_i + 60 # テキストのx座標の開始位置
y_yesno_i_t = y_yesno_i + 30 # テキストのy座標の開始位置
#####追加「はい」いいえ」#####
x_yesno_i = bg.get_width()*0.7 # x座標の開始位置
x_yesno_w = bg.get_width()*0.2 # 横幅
y_yesno_i = bg.get_height()*0.1 # y座標の開始位置
y_yesno_h = bg.get_height()*0.15 # 高さ
x_yesno_i_t = x_yesno_i + 60 # テキストのx座標の開始位置
y_yesno_i_t = y_yesno_i + 30 # テキストのy座標の開始位置
横幅や高さなど
「はい」「いいえ」を
表示するのに必要な
変数を追加します。

追加した変数を使って
「はい」「いいえ」を
表示します。
def draw_message(bg, fnt):
(省略)
i = 0
talk_line = talk_start
while True:
draw_text(bg, "{}".format(talk_mes[talk_line]), x_i_t, y_i_t+30*i, fnt, col)
i += 1
talk_line += 1
if talk_mes[talk_line] == "#end": # 会話の最後を表示している
(省略)
elif talk_mes[talk_line] == "#page": # 会話の途中を表示している(会話の続きがある)
(省略)
elif talk_mes[talk_line] == "#yesno": # 会話の途中を表示している(会話の続きがある)、yesnoの後には必ず#pageか#endを持ってくる必要がある
pygame.draw.rect(bg, BLACK, [x_yesno_i, y_yesno_i, x_yesno_w, y_yesno_h], 0, 5) # 枠
pygame.draw.rect(bg, col, [x_yesno_i, y_yesno_i, x_yesno_w, y_yesno_h], 2, 5) # 枠
draw_text(bg, "{}".format("はい"), x_yesno_i_t, y_yesno_i_t, fnt, col)
draw_text(bg, "{}".format("いいえ"), x_yesno_i_t, y_yesno_i_t+30, fnt, col)
if tmr%5 != 0: # 点滅
draw_text(bg, "{}".format("▶︎"), x_yesno_i_t-50, y_yesno_i_t+30*talk_yesno_i, fnt, col)
talk_yesno = True
break
elif talk_mes[talk_line] == "#yesno":
pygame.draw.rect(bg, BLACK, [x_yesno_i, y_yesno_i, x_yesno_w, y_yesno_h], 0, 5) # 枠
pygame.draw.rect(bg, col, [x_yesno_i, y_yesno_i, x_yesno_w, y_yesno_h], 2, 5) # 枠
draw_text(bg, "{}".format("はい"), x_yesno_i_t, y_yesno_i_t, fnt, col)
draw_text(bg, "{}".format("いいえ"), x_yesno_i_t, y_yesno_i_t+30, fnt, col)
if tmr%5 != 0: # 点滅
draw_text(bg, "{}".format("▶︎"), x_yesno_i_t-50, y_yesno_i_t+30*talk_yesno_i, fnt, col)
talk_yesno = True
break
人が発する言葉に
「#yesno」が出てきたら
「はい」「いいえ」を表示します。
また、「talk_yesno」を
Trueにして質問中にします。
※「はい」「いいえ」を選択中。
続いて、「はい」「いいえ」を
選択できるようにします。
def move_player(key, player, people):
global tmr, food, potion, blazegem, treasure, area, talk_flag, talk_mes, talk_end, talk_start, talk_yesno, talk_yesno_i
# talk_end, talk_yesno, talk_yesno_i を追加
(省略)
if not talk_flag: # 会話中でない時は動ける
if key[K_UP] == 1:
(省略)
elif key[K_DOWN] == 1:
(省略)
elif key[K_LEFT] == 1:
(省略)
elif key[K_RIGHT] == 1:
(省略)
elif key[K_a] == 1: # 人がいたら話中になる(talk_flag=Trueになる)
(省略)
else: # 会話中
if key[K_a] == 1:
if talk_end: # 会話の最後でaを押したら会話終了(会話情報をリセット)
talk_end = False
talk_mes = []
talk_flag = False
talk_start = 0
talk_yesno_i = 0 # yesnoの▶︎をはいの位置に戻す
talk_yesno = False
else: # 会話の途中でaを押したら続きの会話を表示する
talk_start = talk_line + 1 # #pageの次の行から表示する
グローバル変数
talk_end, talk_yesno, talk_yesno_i
を追加します。
前回、talk_endは
draw_message関数で
変更しましたが、
move_player関数で
変更するようにします。
if key[K_a] == 1:
if talk_end: # 会話の最後でaを押したら会話終了(会話情報をリセット)
talk_end = False
talk_mes = []
talk_flag = False
talk_start = 0
talk_yesno_i = 0 # yesnoの▶︎をはいの位置に戻す
talk_yesno = False
また、「talk_yesno_i」「talk_yesno」
も会話が終わったら
デフォルトに戻します。
def move_player(key, player, people):
(省略)
if not talk_flag: # 会話中でない時は動ける
(省略)
else: # 会話中
if key[K_a] == 1:
(省略)
#####追加#####
if talk_yesno: # yesnoクエスチョン中
if key[K_UP] == 1:
talk_yesno_i = 0
elif key[K_DOWN] == 1:
talk_yesno_i = 1
elif key[K_a] == 1:
talk_start = talk_line
if talk_yesno_i == 0:
while True:
talk_start += 1
if talk_mes[talk_start] == "#yes":
talk_start += 1
break
elif talk_yesno_i == 1:
while True:
talk_start += 1
if talk_mes[talk_start] == "#no":
talk_start += 1
break
talk_yesno = False
「はい」「いいえ」の選択です。
if key[K_UP] == 1:
talk_yesno_i = 0
elif key[K_DOWN] == 1:
talk_yesno_i = 1
2択なので
↑キーを押下したら0(はい)
↓キーを押下したら1(いいえ)
にします。
※↑キーを何回押下しても0
↓キーを何回押下しても1
elif key[K_a] == 1:
talk_start = talk_line
if talk_yesno_i == 0:
while True:
talk_start += 1
if talk_mes[talk_start] == "#yes":
talk_start += 1
break
elif talk_yesno_i == 1:
while True:
talk_start += 1
if talk_mes[talk_start] == "#no":
talk_start += 1
break
talk_yesno = False
aキーを押下したら
「はい」「いいえ」を
決定します。
「はい」を選択したら
talk_startを「#yes」の
次の行まで進めて、
「いいえ」を選択したら
talk_startを「#no」の
次の行まで進めています。

会話はtalk_startから
表示するようにしています。
def draw_message(bg, fnt):
(省略)
i = 0
talk_line = talk_start # talk_startから表示
while True:
draw_text(bg, "{}".format(talk_mes[talk_line]), x_i_t, y_i_t+30*i, fnt, col)
i += 1
talk_line += 1
(省略)
「はい」を選択

「いいえ」を選択

最後に、
「はい」を選択した時は
「いいえ」を選択した時の
言葉を表示させないようにします。
def draw_message(bg, fnt):
(省略)
while True:
(省略)
elif talk_mes[talk_line] == "#yesno": # 会話の途中を表示している(会話の続きがある)、yesnoの後には必ず#pageか#endを持ってくる必要がある
(省略)
#####追加#####
elif talk_mes[talk_line] == "#no": # yesを選択した時は#noの内容を#pageか#endまで飛ばす
while True:
talk_line += 1
if talk_mes[talk_line] == "#page":
if tmr%5 != 0: # 点滅
draw_text(bg, "{}".format("▼"), x_i_t, y_i_t+30*i, fnt, col)
i += 1
break
elif talk_mes[talk_line] == "#end":
talk_end = True
break
break
「はい」を選択したら
「#no」〜「#page」もしくは
「#no」〜「#end」の内容を
飛ばします。
なので、「#yesno」の後には
「#page」か「#end」の
どちらかが必要になります。

質問に対する
「はい」「いいえ」の回答は以上です。
台を挟んで話す
少し細かいところを修正します。
45回目で台を挟んで
話せるようにしました。
台の画像は
120.pngと121.pngで
120と121を使って
人との間に台があるか
判定しています。
これを定数(リスト)にします。
STAND = [120, 121] # 台の画像(台の先の人に話せる)
リストSTANDに
台の画像の情報を入れます。
STANDを使って
人との間に台があるか
判定します。
変更前
def move_player(key, player, people):
(省略)
if not talk_flag: # 会話中でない時は動ける、会話できる
(省略)
elif key[K_a] == 1:
if player.d == 0: # 上向きの時
(省略)
if int(n_map[player.y-1][player.x][2:]) == 120 or int(n_map[player.y-1][player.x][2:]) == 121: # 自分がいるところより一個上に台がある時
if people.y[i] == player.y-2 and people.x[i] == player.x: # 自分がいるところより2個上に人がいれば話す
print(people.talk[i])
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
変更後
def move_player(key, player, people):
(省略)
if not talk_flag: # 会話中でない時は動ける、会話できる
(省略)
elif key[K_a] == 1:
if player.d == 0: # 上向きの時
(省略)
if int(n_map[player.y-1][player.x][2:]) in STAND: # 自分がいるところより一個上に台がある時
(省略)
下左右についても同様です。
今後、台の画像が
変わるかもしれませんが
その時はSTANDの値を変更します。
という感じで、今回は以上です!(`・ω・´)
最後に
今回は町の人々の質問に対して「はい」「いいえ」を返すようにしました。
次回は宿屋に泊まります。
【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。