CODE Python RPG

独学でPythonでRPGを作成する(第24回)呪文表示のページ遷移

更新日:

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

前回は呪文の表示について、
1ページに表示する呪文の数を4つから8つに変更しました。

今回は覚えている(使える)呪文が9つ以上の時は
2ページ目、3ページ目に表示できるように変更します。

 

目次

  1. 呪文表示のページを分ける
  2. 各ページの表示
  3. リストを途中から表示
  4. ページの遷移
  5. 位置のリセット
  6. 最後に

呪文表示のページを分ける

覚えている(使える)呪文が9つ以上でも、
現在は8つの表示しか出来ません。

覚えている呪文
ホイミ, ベホイミ, ベホマ, メラ, メラミ, メラゾーマ,
ギラ, ベギラマ, ベギラゴン, ヒャド, ヒャダルコ, ヒャダイン, マヒャド

※覚えている呪文はchara.pyの
 リストself.chara1_mas_spell
 に格納されるので以下の状態です。
 self.chara1_mas_spell = ['ホイミ', 'ベホイミ', 'ベホマ', \
   'メラ', 'メラミ', 'メラゾーマ', 'ギラ', 'ベギラマ', 'ベギラゴン',\
   'ヒャド', 'ヒャダルコ', 'ヒャダイン', 'マヒャド']
 今回はself.chara1_mas_spellが
 この状態を前提にしています。

ベギラゴン, ヒャド, ヒャダルコ, ヒャダイン, マヒャド
が表示されないので、2ページ目に表示されるようにします。

 

2ページ目が表示されるタイミングは
左右のキーを押下した時にします。
2ページ目が表示されている時に
1ページ目を表示するのも同様です。

↓の画面の時に左を押下すると2ページ目(最大ページ)が表示される
※覚えている呪文が17以上ある場合は3ページ目に移ります。

↓の画面の時に右を押下すると2ページ目が表示される

↓の画面の時に左を押下すると1ページ目が表示される

↓の画面の時(最大ページの時)に右を押下すると1ページ目が表示される
※3ページ目がある時は3ページ目が表示されます。

 

 

各ページの表示

各ページを表示します。
最初に今が何ページ目なのかを
格納する変数sel_spell_pを用意します。

それからsel_spell_pを使って
各ページの呪文を表示します。

sel_spell_pは0始まりの為、
0の時に1ページ目を表示します。

sel_spell_p = 0 # コマンドで選択する呪文のページ
(省略)

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)
    elif idx == 21: # 呪文の表示
(省略)

#####追加ここから#####
        if (sel_spell_p+1)*8 > len(player.chara1_mas_spell): # 表示されているページが最大ページの時
            end_i = len(player.chara1_mas_spell)
        else:
            end_i = (sel_spell_p+1)*8
#####追加ここまで#####
        for i, spell in enumerate(player.chara1_mas_spell[sel_spell_p*8:end_i]):
            if i%2 == 0: # 1列目
                draw_text(bg, "{}".format(spell), x_i_t, y_i_t+y_h*int(i/2), fnt, col)
            else: # 2列目
                draw_text(bg, "{}".format(spell), x_i_t+int(x_w/2), y_i_t+y_h*int(i/2), fnt, col)
        if tmr%5 != 0:
            draw_text(bg, "▶︎", x_i_t-50+int(x_w/2)*sel_spell_x, y_i_t+y_h*sel_spell_y, fnt, col)

余談ですが、追加した箇所は3項演算子で書けます。
if (sel_spell_p+1)*8 > len(player.chara1_mas_spell):
  end_i = len(player.chara1_mas_spell)
else:
  end_i = (sel_spell_p+1)*8

3項演算子
end_i = len(player.chara1_mas_spell)\
  if (sel_spell_p+1)*8 > len(player.chara1_mas_spell)\
  else (sel_spell_p+1)*8

ただ、私は3項演算子に
なかなか馴染めずにいます。。(^_^;)

 

話を戻して
ページ内の呪文の表示について
まず、最初と最後に表示する呪文を
取得します。

変数end_iはchara.pyのリストchara1_mas_spellの添字であり、
ページ内に表示する最後の呪文です。

表示されているページが最大ページの時は
覚えている呪文の全数が
ページ内に表示する最後の呪文になります。

if (sel_spell_p+1)*8 > len(player.chara1_mas_spell):
  end_i = len(player.chara1_mas_spell)

chara1_mas_spellは以下を前提にしているので
end_iは13が入ります。

self.chara1_mas_spell = ['ホイミ', 'ベホイミ', 'ベホマ', \
  'メラ', 'メラミ', 'メラゾーマ', 'ギラ', 'ベギラマ', 'ベギラゴン',\
  'ヒャド', 'ヒャダルコ', 'ヒャダイン', 'マヒャド']

 

表示されているページが最大ページではない時は
ページ数 × 8
がページ内に表示する最後の呪文になります。

else:
  end_i = (sel_spell_p+1)*8

1ページ目の時は8つ目が表示する最後の呪文です。
2ページ目の時は16、3ページ目の時は24です。
また、sel_spell_pは0始まりの為、+1にしています。

 

これで表示する最後の呪文が分かりました。

次に、最初に表示する呪文は
sel_spell_p*8 + 1
です。

1ページ目の時
0 × 8 + 1
で1つ目です。
2ページの時は9、3ページ目の時は17です。

繰り返しになりますが、sel_spell_pは0始まりの為、
sel_spell_pが0の時は1ページ目になります。

ただ、self.chara1_mas_spellはリストの為、
添字が0始まりになります。
なので、プログラム上では最初に表示する呪文は
sel_spell_p*8
になります。

1ページ目の時は0、2ページ目の時は8です。
chara1_mas_spell[0]は「ホイミ」、
chara1_mas_spell[8]は「ベギラゴン」
となります。

self.chara1_mas_spell = ['ホイミ', 'ベホイミ', 'ベホマ', \
  'メラ', 'メラミ', 'メラゾーマ', 'ギラ', 'ベギラマ', 'ベギラゴン',\
  'ヒャド', 'ヒャダルコ', 'ヒャダイン', 'マヒャド']

 

ページ内に表示する呪文(リストの添字)が分かったので
これを使って表示させます。

変更前
for i, spell in enumerate(player.chara1_mas_spell):

変更後
for i, spell in enumerate(player.chara1_mas_spell[sel_spell_p*8:end_i]):

リストを単純に最初から表示する時は
変更前のようにしますが、
リストの途中から表示する必要がある為、
変更後のようにスライスしました。
※他は変えていません。

リストplayer.chara1_mas_spellの
sel_spell_p*8 〜 end_i-1 を表示します。
※end_iは表示されません。

これで各ページ内に呪文が表示されるようになりました(^_^)

 

 

リストを途中から表示

enumerateについて少し。

リストを途中から取得したい時は
スライスすると出来ます。

li = ["A", "B", "C", "D", "E", "F"]
for i, s in enumerate(li[1:5]):
    print(i, s)

# 結果
# 0 B
# 1 C
# 2 D
# 3 E

li[1:5]ですと、結果のコメントのように
1番目から4番目(B,C,D,E)を取得します。

ただ、インデックスは0始まりです。
インデックスの開始番号も途中から始めたい時は
enumerateの2つ目に開始番号を指定します。

li = ["A", "B", "C", "D", "E", "F"]
for i, s in enumerate(li[1:5],1):
    print(i, s)

# 結果
# 1 B
# 2 C
# 3 D
# 4 E

 

今回の呪文の表示ではインデックスの開始番号は0からで
良かったので開始番号は指定しませんでした(^_^)
for i, spell in enumerate(player.chara1_mas_spell[sel_spell_p*8:end_i]):

 

ちなみにインデックスの開始番号だけを
指定したい時は以下になります。

li = ["A", "B", "C", "D", "E", "F"]
for i, s in enumerate(li,1):
    print(i, s)

# 結果
# 1 A
# 2 B
# 3 C
# 4 D
# 5 E
# 6 F

 

 

ページの遷移

次に選択している呪文を取得して
ページを遷移します。

↑と↓は変更なし、
←と→を押下した時の動作が変わります。

def spell_select(bg, key, player):
    global idx, sel_spell_x, sel_spell_y, sel_spell_p
    ent = False
    tmp_sel_spell = sel_spell_x+sel_spell_y*2+sel_spell_p*8 # 選択している呪文(player.chara1_mas_spellの添字)
    max_p = len(player.chara1_mas_spell)//8 # 呪文表示の最大のページ

    # 列は2列
    if key[K_UP] and sel_spell_y > 0: # ↑キー
        sel_spell_y -= 1
    elif key[K_DOWN] and sel_spell_y < 3 and tmp_sel_spell+2 < len(player.chara1_mas_spell): # ↓キー  sel_spell_xとsel_spell_yの初期値は0(条件に=は入らない)
        sel_spell_y += 1
    elif key[K_LEFT] and sel_spell_x > 0: # ←キー
        sel_spell_x -= 1
    elif key[K_LEFT] and sel_spell_x == 0 and sel_spell_p > 0: # ←キー ページが0より大きければページを変える
        sel_spell_x = 1
        sel_spell_p -= 1
    elif key[K_LEFT] and sel_spell_x == 0 and sel_spell_p == 0: # ←キー ページが0の場合、maxにする
        sel_spell_x = 1
        sel_spell_p = max_p
        # ページ遷移後に覚えた呪文のmax数を超えたか
        # 行と列の確認・修正
        tmp_sel_spell_y = (len(player.chara1_mas_spell) % 8) // 2 # 最大ページの最大行
        if sel_spell_y >= tmp_sel_spell_y: # 元々の行より最大行が小さい場合
            sel_spell_y = tmp_sel_spell_y # 最大行にあわせる
            if len(player.chara1_mas_spell)%2 != 0: # 覚えている呪文の数が奇数の時は列を1列目にする
                sel_spell_x = 0
    elif key[K_RIGHT] and sel_spell_x < 1 and tmp_sel_spell+1 < len(player.chara1_mas_spell): # →キー sel_spell_xとsel_spell_yの初期値は0(条件に=は入らない)
        sel_spell_x += 1
    elif key[K_RIGHT] and sel_spell_x == 1 and sel_spell_p < max_p: # →キー ページが最大でなければページを変える
        sel_spell_x = 0
        sel_spell_p += 1
        # ページ遷移後に覚えた呪文のmax数を超えたか、超えていれば行を少なくする
        # 行と列の確認・修正
        if sel_spell_p == max_p:
            tmp_sel_spell_y = (len(player.chara1_mas_spell) % 8) // 2 # 最大ページの最大行
            if sel_spell_y >= tmp_sel_spell_y: # 元々の行より最大行が小さい場合
                sel_spell_y = tmp_sel_spell_y # 最大行にあわせる

    elif key[K_RIGHT] and sel_spell_p == max_p: # →キー ページが最大の場合、0にする。 奇数の時にページ遷移しないので「sel_spell_x == 1」はいらない(ページ遷移しない時の「sel_spell_x == 0」は2つ上で判定するのでここに来ない)
        sel_spell_x = 0
        sel_spell_p = 0
    elif key[K_SPACE] or key[K_RETURN]: # 決定
        ent = True
    elif key[K_b]: # キャンセル
        idx = 11
    return ent

 

選択中の呪文を変数tmp_sel_spellに入れて
上下左右のキーを押下した時の動作を判定します。

前回まではy行とx列のみでしたが、
ページ(変数sel_spell_p)が加わります。
tmp_sel_spell = sel_spell_x+sel_spell_y*2+sel_spell_p*8

なお、tmp_sel_spellは正確には
player.chara1_mas_spellの添字です。

1ページ目の1行1列はtmp_sel_spellが0になるので
player.chara1_mas_spell[tmp_sel_spell]
はホイミとなります。
※sel_spell_x、sel_spell_y、sel_spell_pは全て0始まりです。

 

また、最大ページ数を変数max_pに格納します。
max_p = len(player.chara1_mas_spell)//8

演算子「//」は商の整数部分です。
演算子の詳細はこちら

1ページあたり8つの呪文を表示する為、
覚えている呪文を8で割った整数が
最大ページ数になります。

 

次に変更を加えた判定です。

 

前ページに移動

「←」を押下した時に、「▶︎」が1列目にあって、
ページが0より大きければ前のページに移ります。

elif key[K_LEFT] and sel_spell_x == 0 and sel_spell_p > 0:
  sel_spell_x = 1
  sel_spell_p -= 1

この時、遷移後のページでは2列目を指します(sel_spell_x = 1)

 

最大ページに移動

「←」を押下した時に、「▶︎」が1列目にあって、
ページが0の場合、最大ページに移ります。

elif key[K_LEFT] and sel_spell_x == 0 and sel_spell_p == 0:
  sel_spell_x = 1
  sel_spell_p = max_p

この時、遷移後のページでは2列目を指します。
※遷移前が2行目の場合はヒャダイン、遷移前が1行目の場合はヒャドを指す


ただ、遷移後に「▶︎」の位置が呪文の最後になる場合
覚えている呪文が奇数だと、2列目には呪文が無い為、
1列目を指す必要があります。

また、遷移前の行数が最大ページの最大行より大きい場合
最大行にあわせる必要があります。
※遷移前が3行目もしくは4行目の場合はマヒャド(3行1列)を指す

 

最大ページの最大行を取得します。
tmp_sel_spell_y = (len(player.chara1_mas_spell) % 8) // 2

今回の例を使います。
self.chara1_mas_spell = ['ホイミ', 'ベホイミ', 'ベホマ', \
  'メラ', 'メラミ', 'メラゾーマ', 'ギラ', 'ベギラマ', 'ベギラゴン',\
  'ヒャド', 'ヒャダルコ', 'ヒャダイン', 'マヒャド']

演算子「%」は商の余りの為、
len(player.chara1_mas_spell) % 8
は13÷8で、余りは5となります。

演算子「//」は商の整数部分の為、
(len(player.chara1_mas_spell) % 8) // 2
は5÷2で、整数部分は2となります。

よって、tmp_sel_spell_yは2になる為、
最大ページの最大行は3行目となります。
※tmp_sel_spell_yは0始まり

 

遷移前の行が遷移後(最大ページの最大行)より
大きい場合、tmp_sel_spell_yにあわせます。
if sel_spell_y >= tmp_sel_spell_y:
  sel_spell_y = tmp_sel_spell_y
  if len(player.chara1_mas_spell)%2 != 0:
    sel_spell_x = 0

さらに覚えている呪文が奇数の場合は
1列目を指すようにします(sel_spell_x = 0)

 

後ページに移動

「→」を押下した時に、「▶︎」が2列目にあって、
ページが最大ページより小さければ後のページに移ります。

elif key[K_RIGHT] and sel_spell_x == 1 and sel_spell_p < max_p:
  sel_spell_x = 0
  sel_spell_p += 1

この時、遷移後のページでは1列目を指します(sel_spell_x = 0)

 

ただ、遷移後が最大ページの場合(if sel_spell_p == max_p)、
遷移前の行数が最大ページの最大行より大きいと
最大行にあわせる必要があります。
※遷移前が3行目もしくは4行目の場合はマヒャド(3行1列)を指す

 

if sel_spell_p == max_p:
  tmp_sel_spell_y = (len(player.chara1_mas_spell) % 8) // 2
  if sel_spell_y >= tmp_sel_spell_y:
    sel_spell_y = tmp_sel_spell_y

最大ページに移動」とほぼ同じです。
違うのは常に1列目になる点です。(sel_spell_x = 0)

 

先頭ページに移動

「→」を押下した時に、「▶︎」が2列目にあって、
最大ページにいる場合は先頭ページに移ります。

elif key[K_RIGHT] and sel_spell_p == max_p:
  sel_spell_x = 0
  sel_spell_p = 0

この時、遷移後のページでは1列目を指します(sel_spell_x = 0)

 

 

位置のリセット

以上で上下左右のキーを押下すると
(条件によって)ページが
遷移するようになりました。

あと、キャンセルした時や
(今は出来ませんが)呪文を選択した時などに
元の位置(ホイミ)に戻るようにします。
戻さなくても良い気もします(^_^;)

def main(screen, clock, font, fontS, player):
(省略)
    global sel_spell_x, sel_spell_y, sel_spell_p
(省略)
            if battle_command(screen, key) == True:
(省略)

                # コマンドの位置のリセット
                btl_cmd_x = 0
                btl_cmd_y = 0
                # 呪文位置のリセット
                sel_spell_x = 0 # 追加
                sel_spell_y = 0 # 追加
                sel_spell_p = 0 # 追加

 

と、いうわけで今回は以上です!(`・ω・´)

 

 

最後に

今回は覚えている(使える)呪文が9つ以上の時は
2ページ目、3ページ目に表示できるように変更しました。

これで、呪文は選択できるようになりました。

次回も引き続き呪文を変更しようと思います。

まとめサイトへ

 

 

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

 

 

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

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