CODE Python RPG

独学でPythonでRPGを作成する(第61回)構成を変える

更新日:

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

前回は移動中のコマンド「じゅもん」で
呪文を使えるようにしました。

今回は機能はあまり変わりませんが
少し構成を変えようと思います。

目次

  1. コマンド選択
  2. 呪文使用後
  3. 最後に

コマンド選択

今回もmove.pyをメインに
修正を加えていきます。

move_player関数について
もともとこれはキャラを
移動させるのが目的の
関数でした。
※方向キーを押下すると
 キャラがその方向に移動する

ただ、「じゅもん」のコマンドを
選択できるようにしてから
「▶」の移動も兼ねるように
なっていました。

ですが、この2つの機能は
別々の関数にしようと思います。

 

 

sel_cmd関数

「▶」を移動させるsel_cmd関数を
追加します。

def sel_cmd(key, player):
    global cmd_flag, cmd_x, cmd_y, spell_flag, sel_p_y

    if key[K_UP] == 1:
        if spell_flag[0]: # コマンドのじゅもん選択時
            if spell_flag[2]: # 対象者の選択中
                if sel_p_y[2] > 0:
                    sel_p_y[2] -= 1
            else:
                if spell_flag[1]: # 呪文の選択画面
                    if sel_p_y[1] > 0:
                        sel_p_y[1] -= 1
                else: # じゅもんの使用者選択時
                    if sel_p_y[0] > 0:
                        sel_p_y[0] -= 1
        else: # どれでもない時はコマンドを選択
            if cmd_y > 0:
                cmd_y -= 1
    elif key[K_DOWN] == 1:
        if spell_flag[0]: # コマンドのじゅもん選択時
            if spell_flag[2]: # 対象者の選択中
                if sel_p_y[2] < len(player)-1:
                    sel_p_y[2] += 1
            else:
                if spell_flag[1]: # 呪文の選択画面
                    if sel_p_y[1] < len(player[sel_p_y[0]].mas_move_spell)-1: # 選択されたプレイヤーが覚えている呪文の数
                        sel_p_y[1] += 1
                else: # じゅもんの使用者選択時
                    if sel_p_y[0] < len(player)-1:
                        sel_p_y[0] += 1
        else: # どれでもない時はコマンドを選択
            if cmd_y < 2:
                cmd_y += 1
    elif key[K_LEFT] == 1:
        if spell_flag[0]: # じゅもん選択時 
            pass # 横には動かない
        else: # どれでもない時はコマンドを選択
            if cmd_x > 0 :
                cmd_x -= 1
    elif key[K_RIGHT] == 1:
        if spell_flag[0]: # じゅもん選択時 
            pass # 横には動かない
        else: # どれでもない時はコマンドを選択
            if cmd_x < 1:
                cmd_x += 1
    elif key[K_a] == 1:
        if not spell_flag[0]: # じゅもんが選択されていない
            if cmd_x == 1 and cmd_y == 0: # じゅもんの位置でaを押下
                spell_flag[0] = True # じゅもんを選択済、使用者を選択中
        elif not spell_flag[1]: # じゅもんが選択されていて、使用者が選択されていない
            spell_flag[1] = True # 使用者を選択済、呪文を選択中
        elif not spell_flag[2]: # 使用者が選択されていて、呪文が選択されていない
            spell_flag[2] = True # 呪文を選択済、対象者を選択中
        elif not spell_flag[3]: # 呪文発動
            spell_flag[3] = True
    elif key[K_b] == 1:
        if spell_flag[0]: # 呪文選択中なら
            if spell_flag[2]: # 対象の選択中
                spell_flag[2] = False
                sel_p_y[2] = 0
            elif spell_flag[1]: # 呪文の選択中
                spell_flag[1] = False
                sel_p_y[1] = 0
            else: # 使用者の選択中(呪文選択中)
                spell_flag[0] = False
                sel_p_y[0] = 0
        else:
            cmd_flag = False
            cmd_x = 0
            cmd_y = 0

基本的に、move_player関数で
「▶」を動かす機能を
抜き出しています。

if cmd_flag: # コマンド選択中

コマンド選択中かどうかは
別で判定する為、
ここでは省いています。

 

 

move_player関数

続いて、move_player関数を
修正します。

def move_player(key, player, people): # 主人公の移動
(省略)

    # 方向キーで上下左右に移動
    x = player[0].x # 移動したかを確認する為に今の位置を保存
    y = player[0].y
    posi_flag = False # 行こうとしている先に人がいるかいないか(いたら移動できない)
    if not talk_flag: # 会話中でない時は動ける、会話できる
        if key[K_UP] == 1:
            player[0].d = 0
            if player[0].y > 0:
                if int(n_map[player[0].y-1][player[0].x][2:]) < 101:
                    for i in range(len(people.x)): # 人と重ならないか
                        if player[0].y-1 == people.y[i] and player[0].x == people.x[i]:
                            posi_flag = True
                    if not posi_flag:
                        player[0].y = player[0].y - 1

        elif key[K_DOWN] == 1:
            player[0].d = 1
            if player[0].y < map_h-1: # map_hになるとout of rangeになる
                if int(n_map[player[0].y+1][player[0].x][2:]) < 101: # player[0].y+1なので、player[0].y=map_h-1の時out of rangeになる
                    for i in range(len(people.x)):
                        if player[0].y+1 == people.y[i] and player[0].x == people.x[i]:
                            posi_flag = True
                    if not posi_flag:
                        player[0].y = player[0].y + 1
        elif key[K_LEFT] == 1:
            player[0].d = 2
            if player[0].x > 0:
                if int(n_map[player[0].y][player[0].x-1][2:]) < 101:
                    for i in range(len(people.x)):
                        if player[0].y == people.y[i] and player[0].x-1 == people.x[i]:
                            posi_flag = True
                    if not posi_flag:
                        player[0].x = player[0].x - 1
        elif key[K_RIGHT] == 1:
            player[0].d = 3
            if player[0].x < map_w-1:
                if int(n_map[player[0].y][player[0].x+1][2:]) < 101:
                    for i in range(len(people.x)):
                        if player[0].y == people.y[i] and player[0].x+1 == people.x[i]:
                            posi_flag = True
                    if not posi_flag:
                        player[0].x = player[0].x + 1
        elif key[K_a] == 1:
            talk_flag, talk_mes = talk_judge(player, people)
            if not talk_flag:
                cmd_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 = False
            else: # 会話の途中でaを押したら続きの会話を表示する
                talk_start = talk_line + 1 # #pageの次の行から表示する
        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_i = 0 # ▶︎をはいの位置に戻す(複数回、回答する時用)
                talk_yesno = False

    
    player[0].a = player[0].d*2 + tmr%2 # 0:上 1:下 2:左 3:右
    if player[0].x != x or player[0].y != y: # 移動したら食料の量と体力を計算
        if int(n_map[player[0].y][player[0].x][:2]) != 99: # モンスターエリアが99は敵が出ない
            if random.randint(0, 99) < appear_rate: # 敵出現
                tmr = 0
                return 10
    if area == 0: # マップ
        if int(n_map[player[0].y][player[0].x][2:]) == 13 or int(n_map[player[0].y][player[0].x][2:]) == 14:
            area = 1
            return 11
    elif area == 1:
        if player[0].y == 23 and player[0].x == 3:
            area = 0 # マップ
            return 11
    return 1

基本的に、sel_cmd関数へ
持っていった機能を削除しました。

 

 

コマンド選択中

新しく追加したsel_cmd関数を
呼び出します。

コマンド選択中であれば
sel_cmdを呼び出しますが
それはidxが4になった時にします。

def main(screen, clock, font, fontS, use_map, player, people):
(省略)

        if idx == 1:
            idx = move_player(key, player, people)
            draw_map(screen, fontS, player, people)
            if rest_flag:
                idx = 2
                tmr = 0
(省略)

        elif idx == 4: # コマンド選択中
            draw_map(screen, fontS, player, people)
            draw_para(screen, fontS, player) # 主人公の能力を表示
            idx = sel_cmd(key, player)
elif idx == 4: # コマンド選択中

を追加しています。
※idx==1(キャラ移動中)の
 処理は変えていません。

idxが4の時は
sel_cmd関数を呼び出して、
「▶」を動かします。

と、いうわけで
sel_cmd関数
move_player関数
を以下のようにしました。
※draw_map関数も少し変えます。
※idxを「移動中」「コマンド選択中」に
 分けたので、
 cmd_flag変数が不要になりました。

def draw_map(bg, fnt, player, people):
(省略)

    if talk_flag:
        draw_message(bg, fnt, player)
    # if cmd_flag: # 削除
    #     draw_para(bg, fnt, player) # 主人公の能力を表示  # 削除
if cmd_flag:
    draw_para(bg, fnt, player) # 主人公の能力を表示

を削除しています。

draw_para関数は
idxが4(コマンド選択中)の時に
呼び出します。

 

def sel_cmd(key, player):
(省略)

    elif key[K_b] == 1: # キャンセル
        if spell_flag[0]: # 呪文選択中なら
(省略)

        else: # コマンド選択をキャンセル(コマンド枠を消す)
            # cmd_flag = False # 削除
            cmd_x = 0
            cmd_y = 0
            return 1 # 移動(idx=1)
    return 4

コマンド選択をキャンセルした時は
idx1(移動中)に戻ります。
※cmd_flagは不要。

return 4

コマンド選択が継続の場合は
idx4のままです。

elif key[K_a] == 1:

なお、決定(aキー押下)の時も
return 1
が必要ですが、こちらは後述します。

 

def move_player(key, player, people): # 主人公の移動
(省略)

        elif key[K_a] == 1:
            talk_flag, talk_mes = talk_judge(player, people)
            if not talk_flag:
                # cmd_flag = True
                return 4 # コマンド選択(idx=4)

「a」キーを押下した時に
人がいない(会話中ではない)場合
idx4にしてコマンド選択中にします。
※cmd_flagは不要。

これでひとまず、
キャラ移動のmove_player関数と
「▶」移動のsel_cmd関数に
分けることが出来ました。

move_player関数には
まだ会話が残っていますが
会話もそのうち別の関数に
したいと思います。

 

 

呪文使用後

前回、呪文を使った後
文字がすぐに消えてしまう為
以下を追加していました。

pygame.display.update()
pygame.time.delay(DELAY_SPEED)

前回も記載しましたが
あまり良くない気がするので
変更します。

「a」もしくは「b」キーを
押下したら文字を消えるようにします。

 

 

変数追加

まず、変数を追加します。

spell_flag = [False, False, False, False, False] # フィールドで呪文画面を表示するか [true:呪文の使用者選択、true:呪文の選択、true:呪文の対象選択、true:呪文発動, true:完了(閉じても良い)]
sel_p_y = [0, 0, 0] # コマンドのじゅもん選択時の"▶︎"のy位置(横には動かない)

spell_flag[4]を追加しました。
※sel_p_yは変えていません。

spell_flag[4]がTrueの時に
「a」や「b」キーを押下すると
メッセージ枠を閉じるようにします。

 

 

sel_cmd関数の変更

def sel_cmd(key, player):
(省略)

    elif key[K_a] == 1:
        if spell_flag[4]:
            spell_flag = [False for i in range(len(spell_flag))]
            sel_p_y = [0 for i in range(len(sel_p_y))]
            cmd_x = 0
            cmd_y = 0
            return 1 # 移動(idx=1)
        if not spell_flag[0]: # じゅもんが選択されていない
            if cmd_x == 1 and cmd_y == 0: # じゅもんの位置でaを押下
                spell_flag[0] = True # じゅもんを選択済、使用者を選択中
        elif not spell_flag[1]: # じゅもんが選択されていて、使用者が選択されていない
            spell_flag[1] = True # 使用者を選択済、呪文を選択中
        elif not spell_flag[2]: # 使用者が選択されていて、呪文が選択されていない
            spell_flag[2] = True # 呪文を選択済、対象者を選択中
        elif not spell_flag[3]: # 呪文発動
            spell_flag[3] = True
if spell_flag[4]:
    spell_flag = [False for i in range(len(spell_flag))]
    sel_p_y = [0 for i in range(len(sel_p_y))]
    cmd_x = 0
    cmd_y = 0
    return 1 # 移動(idx=1)

を追加しています。

spell_flag[4]がTrueの時
各変数を初期化して
idx1(移動中)に戻ります。
※先述した「a」キーの
 return 1
 はここに追加しました。

また、リストの初期化に
リスト内包表記を使いました。

 

呪文を使った後、
「b」キーを押下しても
同様にメッセージ枠を
消せるようにします。
※呪文のキャンセルではないです。

def sel_cmd(key, player):
(省略)

    elif key[K_b] == 1:
        if spell_flag[0]: # 呪文選択中なら
            if spell_flag[4]: # 完了
                spell_flag = [False for i in range(len(spell_flag))]
                sel_p_y = [0 for i in range(len(sel_p_y))]
                cmd_x = 0
                cmd_y = 0
                return 1 # 移動(idx=1)
            elif spell_flag[3]: # 呪文発動
                pass
(省略)

        else:
            spell_flag = [False for i in range(len(spell_flag))]
            sel_p_y = [0 for i in range(len(sel_p_y))]
            cmd_x = 0
            cmd_y = 0
            return 1 # 移動(idx=1)
    return 4

spell_flag[4]がTrue
(呪文を使った後)
各変数を初期化して
idx1(移動中)に
戻ります。
※spell_flag[3]は意味は無いですが
 追加しました。

 

else:
    spell_flag = [False for i in range(len(spell_flag))]
    sel_p_y = [0 for i in range(len(sel_p_y))]

コマンド選択をキャンセルした時も
変数を初期化しておきました。
一応です。

コマンド選択は以下画面のことです。

 

 

draw_para関数の変更

spell_flag[4]がTrueの時に
メッセージを表示するようにします。

def draw_para(bg, fnt, player): # 主人公の能力を表示
(省略)

        if spell_flag[3]: # 呪文発動
            # 使う:player[sel_p_y[0]]
            # 呪文:player[sel_p_y[0]].mas_move_spell[sel_p_y[1]]
            # 対象:player[sel_p_y[2]]
            if not spell_flag[4]:
                if player[sel_p_y[0]].check_mp(player[sel_p_y[0]].mas_move_spell[sel_p_y[1]]): # mpが足りていたら
                    spell_target_no = chara.get_spell_target(player[sel_p_y[0]].mas_move_spell[sel_p_y[1]])
                    spell_point, spell_message = player[sel_p_y[0]].use_spell(player[sel_p_y[0]].mas_move_spell[sel_p_y[1]], player[sel_p_y[2]], spell_target_no)
                    if spell_point != -1: # 回復系、-1は補助系
                        player[sel_p_y[2]].hp += spell_point
                        if player[sel_p_y[2]].hp > player[sel_p_y[2]].maxhp:
                            player[sel_p_y[2]].hp = player[sel_p_y[2]].maxhp
                else:
                    spell_message = "MPがたりない!"
                spell_flag[4] = True

        if spell_flag[4]:
            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) # 枠
            draw_text(bg, "{}".format(player[sel_p_y[0]].name + "は " + player[sel_p_y[0]].mas_move_spell[sel_p_y[1]] + " を となえた!"), x_i_t, y_i_t, fnt, col)
            draw_text(bg, "{}".format(spell_message), x_i_t, y_i_t+50, fnt, col)
if spell_flag[3]: # 呪文発動
    if not spell_flag[4]:

spell_flag[4]がFalseの時
呪文を使います。

if spell_flag[4]:

以降でメッセージを表示します。

この時に
「a」や「b」キーを押下すると
spell_flagがFalseになって
メッセージが消えます。

というわけで以下を
削除しました。

pygame.display.update()
pygame.time.delay(delay_speed)

 

まだ、spell_messageを
グローバル変数にする必要があるとか
ありますけど、、
今回は以上です!(`・ω・´)

 

 

最後に

今回は機能はあまり変わりませんが
構成を少し変えました。

修正が中途半端になってしまったのですが
構成をさらに変えたいと思ったので、いったんここまでにしました。

なので、次回も今回の続きを修正していきたいと思います。

まとめサイトへ

 

 

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

 

 

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

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