s_battle/draw.py
描画をおこなうs_battle/draw.py
モジュールです。主人公と敵のステータス、主人公と敵のキャラクター画像、メニュー、枠の描画をおこないます。プログラム自体は長いですが、愚直に描画をおこなうだけです。かなりボリュームがあるので、全体を掲載したあと、部分を掲載しながら説明します。
import pygame, data, hero, enemy, img from data import U, W, H, COL_W, COL_G RECT_HERO = pygame.Rect(U, U, W // 2 - U, H // 2 + U) # 領域自 RECT_ENEMY = pygame.Rect(W // 2, U, W // 2 - U, H // 2 + U) # 領域敵 RECT_MENU = pygame.Rect(U, H // 2 + U * 2, W - U * 2, H // 2 - U * 3) # 領域メニュー # 描画 def render(): t_hero = f"HP:{hero.hp}/{hero.hp_max} MP:{hero.mp}/{hero.mp_max}" # ステータス自 t_enemy = f"{enemy.name} HP:{enemy.hp}/{enemy.hp_max}" # ステータス敵 render_stat(RECT_HERO, t_hero) # ステータスの描画 render_stat(RECT_ENEMY, t_enemy) # ステータスの描画 render_char(RECT_HERO, hero.iref, data.ef_hero) # キャラクターの描画 render_char(RECT_ENEMY, enemy.iref, data.ef_enemy) # キャラクターの描画 render_menu() # メニューの描画 render_frame() # 枠の描画 # ステータスの描画 def render_stat(rect, text): # 文字 size = img.font.get_rect(text) # 描画領域四角形 x = rect.x + rect.w / 2 - size.w / 2 # 中央になるX位置 y = rect.y + U * 0.5 # Y位置 img.font.render_to(data.screen, (x, y), text, COL_W) # 文字描画 # キャラクターの描画 def render_char(rect, iref, is_ef): # 拡大画像準備 time = pygame.time.get_ticks() # ゲーム開始からの経過時間 ref = iref + time // 500 % 2 # 画像参照位置 image = pygame.transform.scale(img.chara[ref], (U * 6, U * 6)) # 拡大画像 # キャラ画像の描画 x = rect.x + U * 1.5 # キャラX位置 y = rect.y + U * 2 # キャラY位置 if is_ef: # 演出の有無 pygame.draw.rect(data.screen, (255, 0, 0), rect) # 背景塗りつぶし data.screen.blit(image, (x, y)) # キャラ画像描画 # 50ミリ秒ごとにガタガタと揺らす x += - U // 2 + int(U * (time // 50 * 11 % 13 / 13)) # X位置修正 y += - U // 2 + int(U * (time // 50 * 11 % 17 / 17)) # Y位置修正 data.screen.blit(image, (x, y)) # キャラ画像描画 # メニューの描画 def render_menu(): line_h = img.fsz * 1.25 # 行の高さ for i, text in enumerate(data.menu_texts): size = img.font.get_rect(text) # 描画領域四角形 x = RECT_MENU.x + RECT_MENU.w / 2 - size.w / 2 # 中央になるX位置 y = RECT_MENU.y + U * 0.75 + line_h * i # Y位置 if i == data.menu_sel: # 選択メッセージ背景 rect = (RECT_MENU.x, y - img.fsz * 0.25, RECT_MENU.w, line_h) # 背景の四角形 pygame.draw.rect(data.screen, COL_G, rect) # 四角形の塗りつぶし img.font.render_to(data.screen, (x, y), text, COL_W) # 文字描画 # 枠の描画 def render_frame(): line_w = U // 8 # 線の太さ pygame.draw.rect(data.screen, COL_W, RECT_HERO, line_w) # 自 pygame.draw.rect(data.screen, COL_W, RECT_ENEMY, line_w) # 敵 pygame.draw.rect(data.screen, COL_W, RECT_MENU, line_w) # メニュー
インポート部分ではpygame, data, hero, enemy, img
を読み込んでいます。またdata
モジュールから、描画単位U
、横幅W
、高さH
、白色COL_W
、灰色COL_G
を読み込みます。
3つの領域
続く定数のRECT_HERO
、RECT_ENEMY
、RECT_MENU
は、バトル画面の左上、右上、下の領域の四角形です。
RECT_HERO = pygame.Rect(U, U, W // 2 - U, H // 2 + U) # 領域自 RECT_ENEMY = pygame.Rect(W // 2, U, W // 2 - U, H // 2 + U) # 領域敵 RECT_MENU = pygame.Rect(U, H // 2 + U * 2, W - U * 2, H // 2 - U * 3) # 領域メニュー
まとめて描画
最初のrender()
関数は、それぞれの描画処理を呼び出します。
# 描画 def render(): t_hero = f"HP:{hero.hp}/{hero.hp_max} MP:{hero.mp}/{hero.mp_max}" # ステータス自 t_enemy = f"{enemy.name} HP:{enemy.hp}/{enemy.hp_max}" # ステータス敵 render_stat(RECT_HERO, t_hero) # ステータスの描画 render_stat(RECT_ENEMY, t_enemy) # ステータスの描画 render_char(RECT_HERO, hero.iref, data.ef_hero) # キャラクターの描画 render_char(RECT_ENEMY, enemy.iref, data.ef_enemy) # キャラクターの描画 render_menu() # メニューの描画 render_frame() # 枠の描画
主人公側のステータスt_hero
はHPとMP、敵側のステータスt_enemy
は名前とHPにしています。領域の幅が限られているので、全ての能力値は表示しません。
ステータスの描画
次はステータスの描画をおこなうrender_stat()
関数です。
# ステータスの描画 def render_stat(rect, text): # 文字 size = img.font.get_rect(text) # 描画領域四角形 x = rect.x + rect.w / 2 - size.w / 2 # 中央になるX位置 y = rect.y + U * 0.5 # Y位置 img.font.render_to(data.screen, (x, y), text, COL_W) # 文字描画
img.font
のget_rect()
関数で、text
を描画した場合の横幅と高さのpygame.Rect
オブジェクトを得ます。
このRect
の横幅size.w
を利用して、描画X位置が領域の中央になるようにします。
キャラクターの描画
次はキャラクターの描画をおこなうrender_char()
関数です。
# キャラクターの描画 def render_char(rect, iref, is_ef): # 拡大画像準備 time = pygame.time.get_ticks() # ゲーム開始からの経過時間 ref = iref + time // 500 % 2 # 画像参照位置 image = pygame.transform.scale(img.chara[ref], (U * 6, U * 6)) # 拡大画像 # キャラ画像の描画 x = rect.x + U * 1.5 # キャラX位置 y = rect.y + U * 2 # キャラY位置 if is_ef: # 演出の有無 pygame.draw.rect(data.screen, (255, 0, 0), rect) # 背景塗りつぶし data.screen.blit(image, (x, y)) # キャラ画像描画 # 50ミリ秒ごとにガタガタと揺らす x += - U // 2 + int(U * (time // 50 * 11 % 13 / 13)) # X位置修正 y += - U // 2 + int(U * (time // 50 * 11 % 17 / 17)) # Y位置修正 data.screen.blit(image, (x, y)) # キャラ画像描画
画像参照位置iref
に、500ミリ秒ごとに0、1、0、1、……と切り替わるtime // 500 % 2
を足してアニメーションさせます。
画像はpygame.transform.scale()
関数で拡大してから描画します。
is_ef
の値(data.ef_hero
、data.ef_enemy
)がTrue
のときは、背景を赤(255, 0, 0)
で塗りつぶして、50ミリ秒ごとにガタガタと揺らします。
メニューの描画
次はメニューの描画です。
# メニューの描画 def render_menu(): line_h = img.fsz * 1.25 # 行の高さ for i, text in enumerate(data.menu_texts): size = img.font.get_rect(text) # 描画領域四角形 x = RECT_MENU.x + RECT_MENU.w / 2 - size.w / 2 # 中央になるX位置 y = RECT_MENU.y + U * 0.75 + line_h * i # Y位置 if i == data.menu_sel: # 選択メッセージ背景 rect = (RECT_MENU.x, y - img.fsz * 0.25, RECT_MENU.w, line_h) # 背景の四角形 pygame.draw.rect(data.screen, COL_G, rect) # 四角形の塗りつぶし img.font.render_to(data.screen, (x, y), text, COL_W) # 文字描画
リストdata.menu_texts
内のテキストを1行ずつ描画します。
ステータスと同様に、img.font
のget_rect()
関数で、テキストtext
を描画した場合の横幅と高さのpygame.Rect
オブジェクトを得ます。このRect
の横幅size.w
を利用して、描画X位置が領域の中央になるようにします。
また、要素のインデックスi
がdata.menu_sel
と等しいときに、灰色で四角形を塗ります。こうすることで、選択項目であることを示します。
枠の描画
最後は枠の描画をおこなうrender_frame()
関数です。
# 枠の描画 def render_frame(): line_w = U // 8 # 線の太さ pygame.draw.rect(data.screen, COL_W, RECT_HERO, line_w) # 自 pygame.draw.rect(data.screen, COL_W, RECT_ENEMY, line_w) # 敵 pygame.draw.rect(data.screen, COL_W, RECT_MENU, line_w) # メニュー
各領域の四角形を白線で描画します。
まとめと次回
これで、短いながらも、タイトル、マップ、バトル画面を行き来するレトロ風RPGが完成しました。アイテムも会話もないシンプルなRPGですが、処理を追加すればより複雑なゲームにすることができます。
さて、最初の数回で学んだPythonの知識だけでプログラムを書いてきましたが、Pythonにはまださまざまな仕様があります。
次回はクラスを取り上げます。クラスはデータと処理をひとまとめにあつかえるデータ構造です。また、クラスを利用してPygameのスプライトもあつかいます。