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()を実行することで、待機中の操作が、元のループのキーに影響しないようにします。

