4つの補助的モジュール
次のマップ画面に進む前に、タイトル画面では用意しなかった補助的なモジュールを4つ作ります。
モジュール | 内容 |
---|---|
hero.py | 主人公のデータ |
map.py | マップのデータ |
enemy.py | 敵のデータ |
dialog.py | ダイアログ表示の処理 |
ファイルは全て、main.py
と同じ階層に作ります。
hero.py map.py enemy.py dialog.py
hero.py
主人公のデータと、その処理をまとめたhero.py
モジュールです。プログラムを示します。
# 主人公 start_x = 4 # 開始X位置 start_y = 3 # 開始Y位置 x = start_x # X位置 y = start_y # Y位置 next_x = x # 次回X位置 next_y = y # 次回Y位置 move_rate = 0.0 # 移動到達比率 hp = 100 # HP hp_max = 100 # HP最大値 mp = 4 # MP mp_max = 4 # MP最大値 at = 10 # 攻撃力 df = 10 # 防御力 exp = 0 # 経験値 level = 1 # レベル iref = 0 # 画像参照 # 経験値獲得 def add_exp(n): global exp, level, hp # 代入可能に exp = min(exp + n, 999) # 経験値獲得 level_tmp = 1 + exp // 50 # レベル計算 if level != level_tmp: # レベルが更新されているか確認 # レベルアップ level = level_tmp # レベル反映 calc() # 能力値の計算 hp = hp_max # HPのみ回復 return True # レベルアップあり return False # レベルアップなし # 能力値の計算 def calc(): global hp_max, mp_max, at, df # 代入可能に hp_max = 100 + (level - 1) * 50 # HP最大値 mp_max = 4 + (level - 1) * 2 # MP最大値 at = 10 + (level - 1) * 5 # 攻撃力 df = 10 + (level - 1) * 5 # 防御力
前半は主人公のデータで、後半は成長のための処理です。
start_x
、start_y
、x
、y
、next_x
、next_y
、move_rate
は、移動のための情報です。それぞれ、開始XY位置、現在XY位置、次回XY位置、移動到達比率になります。
hp
、hp_max
、mp
、mp_max
、at
、df
、exp
、level
は、主人公の能力値です。HP/最大、MP/最大、攻撃力、防御力、経験値、レベルになります。
iref
は、chara.png
を分割したリストの参照位置です。iref
は0
なので、分割したリストの要素0を参照します。
iref
の値に、0、1、0、1、……と交互に足していくことで、画像2枚によるアニメーションをおこなえます。
関数の説明に入る前に、global
文の解説をします。
Pythonの関数外の変数は、値を利用することは可能ですが、値を代入することはできません。関数内でglobal
と書き、,
区切りで変数名を列挙すると、その名前の変数をグローバル変数としてあつかい、代入可能にします。
add_exp()
関数は、経験値の獲得です。現在の経験値から仮のレベルを計算して、現在のレベルと異なっていればレベルアップ処理をおこないます。
レベルアップした場合は、calc()
関数で能力値の計算をおこない、HPを最大値に回復させます。MPは回復しません。この関数では、最後にレベルアップしたかを真偽値で返します。レベルアップしたときはTrue
を返し、そうでないときはFalse
を返します。
calc()
関数は、能力値の計算です。レベルをもとに、HP最大値、MP最大値、攻撃力、防御力を決定します。
map.py
マップのデータをまとめたmap.py
モジュールです。
# マップ w = 30 # 横幅 h = 30 # 高さ data = [ # データ 2,2,2,0,2,0,2,0,2,0,3,0,1,0,0,3,3,3,0,0,0,1,1,0,0,1,0,1,2,2, 2,1,0,2,0,0,0,0,0,0,0,1,0,3,1,0,3,0,1,0,0,0,0,1,1,0,1,2,1,2, 2,1,2,2,2,0,0,0,0,0,0,1,0,3,1,0,3,0,1,0,0,0,0,1,1,0,1,2,1,2, 2,1,0,1,0,0,0,0,0,0,0,1,0,3,1,0,3,0,1,0,0,0,0,1,1,0,1,2,1,2, 0,0,2,0,1,4,0,2,0,3,0,3,0,0,3,1,0,0,0,1,2,0,0,0,1,2,0,2,1,2, 0,0,0,1,3,1,0,0,3,0,0,0,3,0,3,0,1,3,3,2,0,2,0,0,0,0,0,1,0,1, 0,0,0,0,1,0,0,0,0,0,3,0,1,0,0,1,0,0,2,0,4,0,2,0,0,0,1,1,0,0, 0,0,0,0,1,0,0,0,0,0,3,0,1,0,0,1,0,0,2,0,0,0,2,0,0,0,1,1,0,0, 0,0,0,0,1,0,0,0,0,0,3,0,1,1,1,1,0,0,2,0,0,0,2,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,0,3,1,1,3,3,1,3,3,0,0,2,0,2,0,1,0,0,0,0,1,0, 0,0,2,0,1,0,0,2,0,0,1,3,3,1,1,3,0,0,0,0,2,0,0,0,0,1,0,0,1,0, 0,0,2,0,2,2,0,0,0,3,0,1,3,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0, 0,0,2,0,2,2,0,0,0,3,0,0,1,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0, 0,0,2,0,2,2,0,0,0,3,0,0,0,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0, 0,2,0,2,2,2,2,0,0,0,0,3,3,3,1,4,1,3,3,0,0,1,1,1,0,0,4,0,0,1, 2,0,0,2,4,2,2,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,2,1,0,0,0,0,1,1, 0,0,2,1,0,0,2,0,0,0,0,0,0,3,0,3,0,0,0,1,1,2,1,0,0,0,0,1,1,1, 2,0,0,2,0,1,0,1,0,0,1,0,0,0,0,3,3,0,1,1,2,1,0,0,0,0,1,1,1,2, 0,1,0,0,0,0,0,0,0,1,2,1,0,3,0,3,0,0,1,2,1,0,0,0,0,1,1,1,1,2, 0,1,1,0,0,0,0,0,1,0,1,0,3,0,1,1,1,1,2,2,1,0,0,0,1,1,1,2,2,2, 0,4,0,0,1,0,2,0,3,3,3,0,0,0,1,2,1,2,1,1,1,1,0,1,1,1,1,2,2,2, 0,3,0,0,1,0,2,0,3,3,3,0,0,0,1,2,1,2,1,1,1,1,0,1,1,1,2,2,2,2, 0,2,0,0,1,0,2,3,3,3,3,0,0,0,1,2,2,2,1,1,1,1,0,1,1,2,2,2,2,2, 0,0,0,2,0,1,0,0,3,3,3,0,0,0,1,2,1,0,0,0,1,1,1,1,2,2,2,2,2,2, 0,0,0,0,0,1,0,0,1,3,0,0,1,1,2,1,1,0,4,0,1,2,1,2,2,2,2,2,2,2, 1,0,0,0,0,0,0,3,0,1,0,0,0,1,1,2,1,0,0,0,1,1,2,2,2,2,2,2,2,2, 2,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,2,1,1,1,2,2,2,2,2,2,2,2,2,2, 2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,2,1,1,1,2,2,2,2,2,2,2,2,2,2, 2,1,1,1,4,1,1,0,1,0,0,1,0,1,0,1,2,1,1,2,2,2,2,2,2,2,2,2,2,2, 2,2,1,1,1,1,0,1,0,1,0,1,0,0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,5 ] PLAIN = 0 # 平地 FOLEST = 1 # 森 MOUNTAIN = 2 # 山 WATER = 3 # 水 TOWN = 4 # 街 CASTLE = 5 # 魔王城
行数は多いですが、内容は少ないです。マップの横幅w
、高さh
、マスのデータdata
、そして各土地を表す定数です。この定数は、land.png
の画像の位置に対応しています。
data
を画像で表示すると、次のようになります。
enemy.py
敵のデータをまとめたenemy.py
モジュールです。
import map # 敵 name = "" # 名前 rate = 0 # 出現頻度 land = 0 # 土地 iref = 0 # 画像参照 hp = 0 # HP hp_max = 0 # HP最大値 at = 0 # 攻撃力 df = 0 # 防御力 exp = 0 # 経験値 boss = False # ボス ENEMIES = ( # 名前 出現頻度 土地 画像参照 HP 最大 攻撃 防御 EXP ボス ("ゴブリン", 15, map.PLAIN, 2, 40, 40, 20, 5, 30, False), ("エルフ", 10, map.FOLEST, 4, 60, 60, 30, 10, 50, False), ("ロック", 5, map.MOUNTAIN, 6, 200, 200, 40, 30, 80, False), ("魔王", 1, map.CASTLE, 8, 999, 999, 99, 99, 99, True) ) # 敵の設定 def set(i): global name, rate, land, iref, hp, hp_max, at, df, exp, boss # 代入可能に name, rate, land, iref, hp, hp_max, at, df, exp, boss = ENEMIES[i] set(0) # 仮設定
序盤は敵の能力値、中盤は各土地に登場する敵のデータ、終盤は戦闘相手を設定する処理です。土地の値を利用するためにmap
をインポートしています。
敵の能力値は主人公よりも少ないです。iref
の画像参照位置は、次のようになっています。
出現頻度rate
と土地land
は特殊な値なので解説します。敵は、土地land
の場所に生息しており、1/rate
の確率で出現します。また、ボスboss
がTrue
の場合はラスボスです。この敵を倒すとエンディングが始まります。
敵 | 生息地 | rateの値 | 計算式 | 出現率 |
---|---|---|---|---|
ゴブリン | 平地 | 15 | 1/15 | 6.6% |
エルフ | 森 | 10 | 1/10 | 10% |
ロック | 山 | 5 | 1/5 | 20% |
魔王 | 魔王城 | 1 | 1/1 | 100% |
敵のデータはENEMIES
というタプルでまとめています。set()
関数を使い、set(0)
のように指定すると、ENEMIES
の要素0の値が、敵のデータとして設定されます。
ここでは、関数外の変数に値を代入するためにglobal
文を用いています。また、ENEMIES[i]
で得たタプルを分割することで、各変数に値を代入しています。
diaglog.py
マップ画面では、敵と遭遇したときや街に着いたときにダイアログを出して知らせます。そのためのダイアログ表示処理をdiaglog.py
モジュールでおこないます。
スクリーンショットとプログラムを示します。
import pygame, data, img from data import U, W, H, COL_W, COL_G def show(text): # 土台描画 rect = (U, U, W - U * 2, H - U * 2) pygame.draw.rect(data.screen, COL_G, rect) # 四角形塗りつぶし # 文字描画 fsz = img.fsz * 2 # フォント サイズ texts = text.splitlines() # 改行でリストに分割 y = (H - fsz * len(texts)) // 2 # 行開始位置 for line in texts: rect = img.font.get_rect(line, size=fsz) # 描画四角形取得 x = (W - rect.w) // 2 # 中央揃え img.font.render_to(data.screen, (x, y), line, COL_W, size=fsz) # 文字描画 y += fsz # 行位置更新 # 画面の反映と待機 pygame.display.flip() # 画面フリップ pygame.time.wait(1200) # 待機 pygame.event.get() # イベントの消費
まず、インポート部分では、pygame, data, img
を読み込みます。また、data
モジュールから、描画単位U
、横幅W
、高さH
、白色COL_W
、灰色COL_G
を読み込みます。
描画をおこなうshow()
関数はテキストを引数に取ります。この関数は、土台の描画、文字の描画、画面の反映と待機の3つの部分に分かれます。
土台の描画では、画面より描画単位U
だけ内側を灰色で塗りつぶします。
文字の描画では、フォント サイズの2倍を変数fsz
に代入して、文字の描画サイズにします。そして、テキストをtext.splitlines()
で改行単位で分割してリストtexts
にします。
そのあとはfor
文で、texts
から1行分の文字列line
を得て、1行ずつY位置をずらして描画していきます。
文字の描画では、中央位置に描画するために描画サイズを事前に得ます。img.font.get_rect(line, size=fsz)
の部分です。get_rect()
関数は、第1引数のテキストを、引数size
の文字サイズで描画した場合のサイズをpygame.Rect
オブジェクトで返します。戻り値を代入したrect
の、rect.w
は横幅、rect.h
は高さになります。
ここでは(W - rect.w) // 2
を計算して、ウィンドウの横幅の中央に、文字が描画されるようにします。
最後の画面の反映と待機の部分は、Pygameの挙動の理解が必要です。
まずpygame.display.flip()
で描画したダイアログを表示します。次にpygame.time.wait(1200)
で1200ミリ秒(1.2秒)待機します。最後のpygame.event.get()
で、待機していたあいだの押しっぱなしのキーの記録を空費します。
Pygameでは、pygame.event.get()
とpygame.event.get()
のあいだで押されたキーは、現在押されているキーとして記録されます。ここで1回pygame.event.get()
を実行することで、待機中の操作が、元のループのキーに影響しないようにします。