こんにちは。
「Pythonでつくる ゲーム開発 入門講座」の
Chapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。
前回は町マップに町の人々を表示しました。
今回はプレイヤーが条件を満たした時に
その町の人々が言葉を発するようにします。
他にも少し細かいところを変更します。
目次
人物シート
最初に、スプレッドシートの
「人物」シートに町の人々の
言葉を追加します。

E列に言葉の列を追加しました。
町の人々に接している状態で
ボタンを押下すると
E列の言葉が表示されるようにします。
シートは以上です。
charaの変更
町の人々の言葉を
chara.pyで読み込みます。
(省略)
person_place = ws_person.col_values(1) # A列 場所
person_x = ws_person.col_values(2) # B列 x
person_y = ws_person.col_values(3) # C列 y
person_pic = ws_person.col_values(4) # D列 画像
person_talk = ws_person.col_values(5) # E列 言葉 ←追加
(省略)
# 人物シート
class People():
def __init__(self):
self.x = []
self.y = []
self.pic = []
self.talk = [] # ←追加
def get_posi(self, area):
self.x.clear()
self.y.clear()
self.pic.clear()
self.talk.clear() # ←追加
for i in range(1, len(person_place)): # 1行目はカラムの為、とばす
if int(person_place[i]) == area:
self.x.append(int(person_x[i]))
self.y.append(int(person_y[i]))
self.pic.append(int(person_pic[i]))
self.talk.append(person_talk[i]) # ←追加
人物シートで追加したE列の言葉を
変数person_talkに格納します。
あとは他の変数と同じようにします。
charaの変更は以上です。
moveの変更
続いてmove.pyの変更です。
ここで町の人々の言葉を
表示します。
talk_flag = False # 会話中か
talk_mes = []
グローバル変数を2つ追加します。
talk_flag:会話中かどうかを判断する
talk_mes:会話中なら表示する言葉を格納
今回メインとなるmove_player関数です。
def move_player(key, player, people): # 主人公の移動
global tmr, food, potion, blazegem, treasure, area, talk_flag, talk_mes # talk_flag, talk_mesを追加
(省略)
if key[K_UP] == 1:
(省略)
elif key[K_DOWN] == 1: # if → elifに変更
(省略)
elif key[K_LEFT] == 1: # if → elifに変更
(省略)
elif key[K_RIGHT] == 1: # if → elifに変更
(省略)
elif key[K_a] == 1: # 追加
global変数に
talk_flag, talk_mesを追加します。
あと、キーのif文ですが、
全部ifになっていたのを
elifに変更しました。
最後の
elif key[K_a] == 1:
で「a」を押下した時に
プレイヤーと人が隣接しているかを
判定します。
elif key[K_a] == 1:
if player.d == 0: # 上向きの時
for i in range(len(people.x)): # その町にいる人の位置を全て確認
if people.y[i] == player.y-1 and people.x[i] == player.x: # 1マス上に人がいる場合
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
if player.d == 0: # 上向きの時
for i in range(len(people.x)): # その町にいる人の位置を全て確認
if people.y[i] == player.y-1 and people.x[i] == player.x: # 1マス上に人がいる場合
プレイヤーが上向きの時に
1マス上に町の人がいるかを
確認します。
※chara.py
※self.d = 0 # プレイヤーの向き 0:上 1:下 2:左 3:右
プレイヤーが上向きの状態

人がいる場合は
talk_flagをTrueにして
会話中にします。
また、talk_mesに
その人の言葉を格納します。
この時、町の人々の言葉(人物シートのE列)を
改行("\n")で分割します。
※splitの詳細はこちら。
人物シートのE列は
以下のようにtalk_mesへ
格納されます。
こんにちは
→ talk_mes = ['こんにちは']
ようこそ
さようなら
→ talk_mes = ['ようこそ', 'さようなら']
その他の向き(下左右)も
同様に確認します。
elif key[K_a] == 1:
if player.d == 0: # 上向きの時
(省略)
elif player.d == 1: # 下向きの時
for i in range(len(people.x)):
if people.y[i] == player.y+1 and people.x[i] == player.x: # 1マス下に人がいる場合
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
elif player.d == 2: # 左向きの時
for i in range(len(people.x)):
if people.y[i] == player.y and people.x[i] == player.x-1: # 1マス左に人がいる場合
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
elif player.d == 3: # 右向きの時
for i in range(len(people.x)):
if people.y[i] == player.y and people.x[i] == player.x+1: # 1マス右に人がいる場合
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
次にdraw_message関数を作成します。
町の人々の言葉を表示する枠です。
def draw_message(bg, fnt):
col = WHITE
if player.hp < player.maxhp/4:
col = DANGER
elif player.hp < player.maxhp/2:
col = WARNING
# 枠
x_i = bg.get_width()*0.1/2
x_w = bg.get_width()*0.9
y_i = bg.get_height()*0.6
y_h = bg.get_height()*0.4-10
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_i_t = x_i + 30
y_i_t = y_i + 30
for i, tmp in enumerate(talk_mes):
draw_text(bg, "{}".format(tmp), x_i_t, y_i_t+30*i, fnt, col)
def draw_para(bg, fnt, player): # プレイヤーの能力を表示
X = 30
Y = 100 # 600 → 100
col = WHITE
if player.hp < player.maxhp/4:
col = DANGER
elif player.hp < player.maxhp/2:
col = WARNING
プレイヤーの残りHPによって
枠や言葉の色を変えます。
あとは枠の位置と
言葉の位置を指定して
表示します。
また、draw_para関数で
プレイヤーの能力を
表示していますが、
Y座標の位置を変更しています。
言葉の枠と被ってしまうからです。
最後に会話中の時に
draw_message関数を呼び出して
町の人々の言葉を表示します。
def draw_map(bg, fnt, player, people):
(省略)
if talk_flag:
draw_message(bg, fnt)
draw_para(bg, fnt, player) # プレイヤーの能力を表示
キー「a」を押下した時
プレイヤーが向いている方向に
町の人々がいると、その言葉が
表示されるようになりました。

台を挟んで話す
町の人々の言葉について、
プレイヤーと人々が隣接している時に
表示できるようにしましたが、
台を挟んでいる状態でも
表示できるようにします。
以下の位置でも
言葉が表示されるようにします。


キー「a」を押下した時の
条件を追加します。
elif key[K_a] == 1:
if player.d == 0: # 上向きの時
for i in range(len(people.x)):
if people.y[i] == player.y-1 and people.x[i] == player.x: # 1マス上に人がいる場合
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
if int(n_map[player.y-1][player.x][2:]) == 120 or int(n_map[player.y-1][player.x][2:]) == 121: # プレイヤーの1マス上に台がある時
if people.y[i] == player.y-2 and people.x[i] == player.x: # プレイヤーの2マス上に人がいれば話す
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
台の画像は
120.pngと121.pngです。

if int(n_map[player.y-1][player.x][2:]) == 120 or int(n_map[player.y-1][player.x][2:]) == 121: # プレイヤーの1マス上に台がある時
if people.y[i] == player.y-2 and people.x[i] == player.x: # プレイヤーの2マス上に人がいれば話す
プレイヤーが上向きの時に
この台があり、
さらに2マス上に人がいる時に
会話状態にします。
※ifではなく、
elifで良い気がします(^_^;)
その他の向き(下左右)も
同様に条件を追加します。
elif key[K_a] == 1:
if player.d == 0: # 上向きの時
(省略)
elif player.d == 1: # 下向きの時
for i in range(len(people.x)):
if people.y[i] == player.y+1 and people.x[i] == player.x:
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
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:
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
elif player.d == 2: # 左向きの時
for i in range(len(people.x)):
if people.y[i] == player.y and people.x[i] == player.x-1:
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
if int(n_map[player.y][player.x-1][2:]) == 120 or int(n_map[player.y][player.x-1][2:]) == 121:
if people.y[i] == player.y and people.x[i] == player.x-2:
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
elif player.d == 3: # 右向きの時
for i in range(len(people.x)):
if people.y[i] == player.y and people.x[i] == player.x+1:
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
if int(n_map[player.y][player.x+1][2:]) == 120 or int(n_map[player.y][player.x+1][2:]) == 121:
if people.y[i] == player.y and people.x[i] == player.x+2:
talk_flag = True
talk_mes = people.talk[i].split("\n")
break
以下のような感じです。


ひとまず町の人々の言葉は
以上です。
町の人々の足踏み
町の人々は固定されていますが
足踏みしているようにします。
まず、画像を2種類用意します。

分かりにくいですが
左の画像は右手が前
右の画像は左手が前
になっています(^_^;)
他の画像も同様に用意して
evenフォルダとoddフォルダに
1種類ずつ画像を格納します。
personフォルダ

evenフォルダ

oddフォルダ

用意した画像を
move.pyで読み込みます。
変更前
imgperson = []
for i in range(3):
imgperson.append(pygame.image.load("person/" + str(i) + ".png"))
変更後
imgperson1 = []
imgperson2 = []
for i in range(3):
imgperson1.append(pygame.image.load("person/odd/" + str(i) + ".png"))
for i in range(3):
imgperson2.append(pygame.image.load("person/even/" + str(i) + ".png"))
この画像をdraw_map関数で
表示します。
変更前
def draw_map(bg, fnt, player, people):
(省略)
for i in range(len(people.x)): # 人の表示
if dy==people.y[i] and dx==people.x[i]:
bg.blit(imgperson[int(people.pic[i])], [X, Y])
変更後
def draw_map(bg, fnt, player, people):
(省略)
for i in range(len(people.x)): # 人の表示
if dy==people.y[i] and dx==people.x[i]:
if tmr%2 != 0: # tmrが奇数
bg.blit(imgperson1[int(people.pic[i])], [X, Y])
else: # tmrが偶数
bg.blit(imgperson2[int(people.pic[i])], [X, Y])
これで2種類の画像が交互に
表示されて足踏みしているように
見えるようになりました。
町からフィールドへ
もう少し。
町の人々とは関係ないですが
町からフィールドへ
出られるようにします。
今までは町に入ったら
フィールドに戻れませんでした(^_^;)
move.pyを変更します。
変更前
def move_player(key, player, people):
(省略)
if int(n_map[player.y][player.x][2:]) == 13 or int(n_map[player.y][player.x][2:]) == 14:
area = 1 # 町
return 11
return 1
変更後
def move_player(key, player, people):
(省略)
if area == 0: # フィールドにいる場合
if int(n_map[player.y][player.x][2:]) == 13 or int(n_map[player.y][player.x][2:]) == 14:
area = 1 # 町
return 11
elif area == 1: # 町にいる場合
if player.y == 23 and player.x == 3:
area = 0 # フィールド
return 11
return 1
areaはマップ番号です。
maps.pyのnumと
同じ番号になります。
class Maps():
def get_map(self, num, player):
if num == 0: # フィールド
(省略)
if num == 1: # 町
if area == 0: # フィールドにいる場合
if int(n_map[player.y][player.x][2:]) == 13 or int(n_map[player.y][player.x][2:]) == 14:
area = 1 # 町
return 11
プレイヤーがフィールドにいる時に
13か14の位置に移動したら
町へ移動します。
elif area == 1: # 町にいる場合
if player.y == 23 and player.x == 3:
area = 0 # フィールド
return 11
プレイヤーが町にいる時に
(3,23)の位置に移動したら
フィールドへ移動します。
これで
フィールドから町へ
町からフィールドへ
行けるようになりました。
なお、
if int(n_map[player.y][player.x][2:]) == 13 or int(n_map[player.y][player.x][2:]) == 14:
も座標で指定した方が良いと思います。。
が、今回は以上です!(`・ω・´)
最後に
今回は町の人々の言葉を表示するようにしました。
次回も町の人々の言葉について追加・変更していこうと思います。
【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。