CODE Python RPG

独学でPythonでRPGを作成する(第45回)町の人々の言葉

更新日:

こんにちは。
「Pythonでつくる ゲーム開発 入門講座」の
Chapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。

前回は町マップに町の人々を表示しました。

今回はプレイヤーが条件を満たした時に
その町の人々が言葉を発するようにします。

他にも少し細かいところを変更します。

目次

  1. 人物シート
  2. charaの変更
  3. moveの変更
  4. 台を挟んで話す
  5. 町の人々の足踏み
  6. 町からフィールドへ
  7. 最後に

人物シート

最初に、スプレッドシートの
「人物」シートに町の人々の
言葉を追加します。

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:
も座標で指定した方が良いと思います。。

が、今回は以上です!(`・ω・´)

 

 

最後に

今回は町の人々の言葉を表示するようにしました。

次回も町の人々の言葉について追加・変更していこうと思います。

まとめサイトへ

 

 

【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。

 

 

-CODE, Python, RPG
-, , , , , , , , , ,

Copyright© kerublog , 2022 All Rights Reserved Powered by STINGER.