CODE Python RPG

初心者がPythonでRPGを作成する(第7回)文字の表示位置を変える

更新日:

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

前回はフォント(font)を変えて日本語表示できるようにしました。
ただ、フォントが変わった関係で画面から文字がはみ出てしまったので、今回はこの辺りを修正していきます。

修正方法としては文字の大きさを変えたり改行したりも良いですが、表示位置を変えてみます。
また、ついでに戦闘中のプレイヤーのパラメータの表示も変えます。

目次

  1. 全体枠のイメージ
  2. 下を空ける
  3. 戦闘メッセージ
  4. プレイヤーのパラメータ表示
  5. 文字の色を変える
  6. 最後に

全体枠のイメージ

全体枠のイメージです。

赤枠の戦闘メッセージを下へ。
黄枠の辺りにプレイヤーのパラメータ。
青枠のコマンドやモンスターの位置を少し上へ。

こんな感じで変えて行きます。

 

 

下を空ける

戦闘メッセージを下に持って行きます。
が、その前に先にコマンドやモンスターの位置を少し上に移して、戦闘メッセージの表示場所を確保する為に下を空けます。

# bg を追加
def init_battle(bg): # 戦闘に入る準備をする
    global monster, emy_x, emy_y
    typ = random.randint(1, floor+1)
    if floor >= 10:
        typ = random.randint(1, 10)
    # lev = random.randint(1, floor)
    monster = chara.Monster(typ)
    # emy_x = 440-monster.img.get_width()/2 # モンスターの横の位置
    # emy_y = 560-monster.img.get_height() # モンスターの縦の位置
    emy_x = bg.get_width()/2 - monster.img.get_width()/2
    emy_y = bg.get_height()*0.6 - monster.img.get_height() # どのモンスターも画面の7割が一番下に揃えられる
    print(f"{bg.get_width()}, {bg.get_height()}")
    # 880, 720
    print(f"{bg.get_width()/2}, {bg.get_height()*0.6
    # 440.0, 432.0

(省略)

elif idx == 10: # 戦闘開始
    if tmr == 1:
    init_battle(screen) # screenを追加
    init_message()

emy_xとemy_yがモンスターの表示位置です。
それぞれ
bg.get_width()/2
bg.get_height()*0.6
としました。

引数のbgを新たに追加していますが、これはmain関数で指定するscreenです。
画面の大きさを取得する為に渡します。
screen = pygame.display.set_mode((880, 720))

なので、先程の意味は
bg.get_width()/2 → 画面の横幅の半分
bg.get_height()*0.6 → 画面の高さの6割
です。(参考

結果を見てもあってますね。

    print(f"{bg.get_width()}, {bg.get_height()}")
    # 880, 720
    print(f"{bg.get_width()/2}, {bg.get_height()*0.6
    # 440.0, 432.0

変更前のプログラムの数字は
emy_x = 440-monster.img.get_width()/2 # モンスターの横の位置
emy_y = 560-monster.img.get_height() # モンスターの縦の位置
なので、少し上に表示さることになります。
※xは数字が小さくなればなるほど左へ、
 yは数字が小さくなればなるほど上です。(下じゃない)

 

続いて、モンスターの体力を表示するバーです。

# draw_barは消す
# def draw_bar(bg, x, y, w, h, val, max): # 敵の体力を表示するバー
#     pygame.draw.rect(bg, WHITE, [x-2, y-2, w+4, h+4])
#     pygame.draw.rect(bg, BLACK, [x, y, w, h])
#     if val > 0:
#         pygame.draw.rect(bg, (0,128,255), [x_i, y_i, w*val/max, h]) # 残り体力

def draw_battle(bg, fnt): # 戦闘画面の描画
    global emy_blink, dmg_eff
    bx = 0
    by = 0
    if dmg_eff > 0:
        dmg_eff = dmg_eff - 1
        bx = random.randint(-20, 20)
        by = random.randint(-10, 10)
    bg.blit(imgBtlBG, [bx, by])
    if monster.hp > 0 and emy_blink%2 == 0:
        bg.blit(monster.img, [emy_x, emy_y+emy_step])

    # 敵の体力を表示するバー
    # draw_bar(bg, 340, 580, 200, 10, monster.hp, monster.maxhp)
    # ここから追加
    x_i = emy_x + monster.img.get_width()/2 - 100 # 体力バーのx座標
    x_w = 200 # 体力バーの幅
    y_i = bg.get_height()*0.6 + 10 # モンスター表示の一番下(画面の7割)
    y_h = 10 # 体力バーの高さ
    pygame.draw.rect(bg, WHITE, [x_i-2, y_i-2, x_w+4, y_h+4])
    pygame.draw.rect(bg, BLACK, [x_i, y_i, x_w, y_h])
    if monster.hp > 0:
        pygame.draw.rect(bg, (0,128,255), [x_i, y_i, x_w*monster.hp/monster.maxhp, y_h]) # 残り体力

def draw_bar関数は消しました。
使うところが1回しかないので、なんとなく・・・
使いどころが増えたら復活します。

draw.rectは
pygame.draw.rect(bg, 色, [x座標, y座標, 横幅, 高さ])
ですね。詳しくはこちら

x座標
x_i = emy_x + monster.img.get_width()/2 - 100
モンスターの表示位置からモンスターの画像幅の半分だけ右に行って、100だけ左に表示です。

順にたどると次のような感じです。
x_i = emy_x の場合

 

x_i = emy_x + monster.img.get_width()/2 の場合

 

x_i = emy_x + monster.img.get_width()/2 - 100 の場合

 

それで横幅を200にしています。(x_w = 200)
どんなに大きな画像のモンスターでも横幅は200です。(高さは10。y_h = 10)

これでモンスターは少し上の位置に表示されました。

 

あとはコマンドも上に表示して、パラメータを消します。

def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)
    # draw_para(bg, fnt) # 主人公の能力を表示

def battle_command(bg, fnt, key): # コマンドの入力と表示
(省略)
        # draw_text(bg, COMMAND[i], 20, 360+i*60, fnt, c)
        draw_text(bg, COMMAND[i], 20, 160+i*60, fnt, c)

draw_battle関数の中にあるdraw_paraを消す
def battle_command関数のdraw_textのy座標を360から160に変更
です。

こんな感じになります。

 

 

戦闘メッセージ

それでは空いた下の位置に戦闘メッセージを入れて行きます。
まずは枠です。

def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)

    col = WHITE
    
    # 戦闘メッセージの枠
    x_i = 50 # x座標の開始位置
    x_w = bg.get_width() - 100 # 幅
    y_i = bg.get_height()*0.6 + 40
    y_h = bg.get_height()*0.4 - 40 # 高さ
    pygame.draw.rect(bg, col, [x_i, y_i, x_w, y_h], 2, 5)

    for i in range(10): # 戦闘メッセージの表示
        draw_text(bg, message[i], 600, 100+i*50, fnt, WHITE)
    # draw_para(bg, fnt) # 主人公の能力を表示

draw.rectを使って、枠を作ります。
ただ先程と違い引数が増えています。

pygame.draw.rect(bg, 色, [x座標, y座標, 横幅, 高さ], 線の太さ, 四隅の丸み)
です。
この辺りはVSCodeに出てくるポップアップが参考になりそうです。

線の太さ(width)を指定しなければ塗りつぶしになります。
先程は体力を表示するバーだったので塗りつぶしでしたが、今度は枠なので、塗りつぶさない四角形にします。
見るだけだと分かりにくいかもですが、色々と値を変えて実行してみると分かってくる気がします。

また、色にWHITEを直接使わずにcol変数に一度入れたのは、hpの残りによって色を変える為です。(後述します)

 

そして、戦闘メッセージの表示です。

    # for i in range(10): # 戦闘メッセージの表示
    #    draw_text(bg, message[i], 600, 100+i*50, fnt, WHITE)
    # ↓に変更
    for i in range(5): # 戦闘メッセージの表示
        draw_text(bg, message[i], x_i+10, y_i+10+i*40, fnt, col)

戦闘メッセージの表示は10行から5行に変更しました。※range(5)
メッセージの表示位置は
x座標:x_i+10 左側の枠の線から10だけ右
y座標:y_i+10+i*40 上側の枠の線から10だけ下、1行の高さを40
※y座標は大きくなる程、下に表示される
です。

 

戦闘メッセージが枠の中に表示されるようになりました。
ただ、「レベルが上がった!」の後のメッセージが表示されないです。
これは枠だけ5行にして、リスト(message)のサイズ(要素数)が10のままだからですね。
こちらも10から5に変えます。

# 変更前
message = [""]*10
def init_message():
    for i in range(10):
        message[i] = ""
    
def set_message(msg):
    for i in range(10):
        if message[i] == "":
            message[i] = msg
            return
    for i in range(9): # 下が最新のメッセージ
        message[i] = message[i+1]
    message[9] = msg
# 変更後
message = [""]*5
def init_message():
    for i in range(5):
        message[i] = ""
    
def set_message(msg):
    for i in range(5):
        if message[i] == "":
            message[i] = msg
            return
    for i in range(4): # 下が最新のメッセージ
        message[i] = message[i+1]
    message[4] = msg

表示されました!

 

 

プレイヤーのパラメータ表示

次の変更点である、プレイヤーのパラメータ表示です。
先程、draw_para関数を消しましたので、代わりのパラメータ枠を作ります。

    # パラメータ表示
    x_i = int(bg.get_width()/4) # x座標の開始位置
    x_w = int(bg.get_width()/8) # 幅
    y_i = 20 # y座標の開始位置
    y_h = 120 # 高さ
    x_i_t = x_i+x_w/2-25 # テキストのx座標の開始位置
    col = WHITE
    pygame.draw.rect(bg, col, [x_i, y_i, x_w, y_h], 2, 5)
    pygame.draw.line(bg, col, [x_i, y_i+33], [x_i+x_w-1, y_i+33], 2) # -1がないと少し出る
    draw_text(bg, "{}".format(player.name), x_i_t, y_i+6, fnt, col)
    draw_text(bg, "H{}".format(player.hp), x_i_t, y_i+36, fnt, col)
    draw_text(bg, "M{}".format(player.mp), x_i_t, y_i+66, fnt, col)
    draw_text(bg, "Lv:{}".format(player.lv), x_i_t, y_i+96, fnt, col)

    # 戦闘メッセージ表示
    x_i = 50 # x座標の開始位置
 (省略)

draw.rectは何度も出てきましたので、割愛します。
draw.lineは
pygame.draw.rect(bg, 色, 始点[x座標, y座標], 終点[x座標, y座標], 線の太さ)
ですね。詳しくはこちら

テキストのx座標の開始位置はモンスターの体力バーと同じような感じです。
x_i_t = x_i+x_w/2-25
枠の表示位置から枠幅の半分だけ右に行って、25だけ左に表示です。

※モンスターの体力バーのx座標(再掲)
※x_i = emy_x + monster.img.get_width()/2 - 100
※モンスターの表示位置からモンスターの画像幅の半分だけ右に行って、100だけ左に表示です。

名前が4文字だったり、hpの桁が変わったりしたら表示位置が崩れてしまいます。
けど、この修正はまた今度にします・・・

 

 

文字の色を変える

最後にプレイヤーの残りhpの値によって色を変えます。

最初に色の定義を追加します。
WARNINGは黄色っぽい色、DANGERは赤っぽい色です。

# 色の定義
WHITE = (255, 255, 255)
WARNING = (255, 191, 0)
DANGER = (255, 101, 101)

 

残りhpの値によって、色を変えます。

    col = WHITE
    if player.hp < player.maxhp/4:
        col = DANGER
    elif player.hp < player.maxhp/2:
        col = WARNING

WHITEをcol変数に入れたのはこの為です。
プレイヤーのhpが1/4未満になったら赤っぽい色、1/2未満になったら黄色っぽい色に変えます。

1/2以下(最大hpは30)

 

1/4以下(最大hpは30)


ちなみに条件分を逆にすると、1/4には来なくなってしまうので注意です。

    if player.hp < player.maxhp/2: # 1/2未満でもあり、1/4未満でもある
        col = WARNING
    elif player.hp < player.maxhp/4: # 上の条件文に入ってしまうのでここには来ない
        col = DANGER

この順番にしてしまうと、hpが1/4未満になっても赤っぽい色にはならなくなってしまいますので、条件文の順番には注意です。

1/4以下になっても赤っぽい色にならない(最大hpは30)

 

あと、コマンドなどの文字が白色のままですが、この辺りはこの表示自体を変える予定なので・・・
今回は以上です!(`・ω・´)

 

 

最後に

戦闘画面のイメージは某RPGです。
しばらくこの戦闘画面を弄って行こうと思っています。

まとめサイトへ

 

 

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

 

 

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

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