工学じじいの縁側日記

工学じじいの縁側日記

引退間際の工学じじいがきままに、プログラミングやデバイス、工学について呟きます。

【pygame】pythonでヒット&ブローゲーム作る #04 数字の入力【簡単】

pygamepythonでヒット&ブローゲーム作る #04 数字の入力【簡単】

f:id:gomta777:20191115111505p:plain

前回までのまとめ

【簡単?】初心者がpython3とpygameでヒット&ブローゲーム作ってみる【習作?】 - 工学じじいの縁側日記
【簡単?】初心者がpython3とpygameでヒット&ブローゲーム作ってみる #02【習作?】 - 工学じじいの縁側日記
【簡単?】初心者がpython3とpygameでヒット&ブローゲーム作ってみる #03 画面作るよ【習作?】 - 工学じじいの縁側日記



前回は、画面構成を整えてみました。
今回は、プレイヤーの数字の入力を実装していきます。
もっと良い画面構成や、入力法もあるかと思いますが、初心者の考えたもんですので、大目に見てください。



タイトル画面の追加

現在、ゲーム開始前の画面はこんな感じです。

f:id:gomta777:20191117132356p:plain
図 ゲーム開始待ち

It's so dull...
画面が殺風景ですね。
数字の入力を追加する前に、なんか物足りないので簡易的なタイトル画面を追加してみます。

まずフォントを準備します。現在自分のシステムで使えるフォントの一覧を表示してみます。

    # フォントの用意
    print(pygame.font.get_fonts())  # 使えるフォントの一覧を表示する

これを実行すると、コンソールに現在インストールされていてpygameから読み込み可能なフォントの一覧が表示されます。

['arial', 'arialblack', 'bahnschrift', 'calibri', 'cambriacambriamath', 'cambria', 'candara', 'comicsansms', 'consolas', 'constantia', 
(省略)
ゴシックcodejpmitalic源ノ角ゴシックcodejpr', 'bizudgothicbizudpgothictruetype', 'bizudgothicbizudpgothicboldtruetype', 'bizudminchomediumbizudpminchomediumtruetype', 'meiryomeiryomeiryouimeiryouiitalic', 'meiryomeiryoboldmeiryouiboldmeiryouibolditalic', 'msminchomspmincho', 'uddigikyokashonbuddigikyokashonpbuddigikyokashonkb', 'uddigikyokashonruddigikyokashonpruddigikyokashonkr', 'yumincho']

。。。いっぱい出ちゃった。
この中から使いたいフォント名をピックアップします。フォントの形状がわからない場合は、ワープロソフトやノートパッドなどで確認してみるといいです。
今回は、英文字のフォントでなるべくタイトルっぽくて太いものを使いたいので、'arialblack'を指定します。

pygameでフォントを使って文字を描画しいときには、以下のようにします。

    title_font = pygame.font.SysFont("arialblack", 50) # フォントの読み込みと作成
    title = title_font.render("Hit & Blow !", True, (255, 0, 0)) # 描画するテキストの作成
    titlepos = [150, 100] # 表示位置
    
    screen.blit(title, *titlepos) # 作成したテキストの描画

実行してみます。

f:id:gomta777:20191119133131p:plain
図 タイトル画面

何もないよりはましになったかも!

数字の入力

現在は*が表示されている入力欄に実際に数字を入力していきます。
現在の入力桁を表す枠を表示して、その枠のある桁に数字を入力していきます。
実は、ボタンの表示用にすでに枠になる矩形は作ってあります。これを再利用します。

入力位置の提示1 赤枠の表示
     margin = [100, 100] # *を表示する位置までのマージン(前回設定済み)
     imagesize = [100,100] # 画像1個当たりの大きさ(前回設定済み)
     for i in range(4): #marginの位置から4つ横に画像を並べるためのもの
         qbuttonrect.append(Rect(margin[0] + i * imagesize[1], margin[1], *imagesize))
   
    for i in range(4):
       pygame.draw.rect(screen, (255,0,0), qbuttonrect[i], 3)  
  • pygame.draw.rect(Surface, Color, Rect, Width)
  • Surface
  • Color
    • 描画色をRGBで指定
  • Rect
    • 描画する矩形領域Rect(左上x、左上y、幅、高さ)
  • Width
    • 線の太さ、デフォルトは0

これを実行すると、4桁すべてが赤枠で囲まれます。

f:id:gomta777:20191119144242p:plain
図 赤枠の描画

入力位置の提示2 赤枠の移動

数字が入力するたびに入力位置を、ずらしていきます。
画像で見るとこんな感じ

f:id:gomta777:20191119152223p:plainf:id:gomta777:20191119152227p:plainf:id:gomta777:20191119152231p:plainf:id:gomta777:20191119152216p:plainf:id:gomta777:20191119152220p:plain
図 入力枠の移動

今入力しようとしている桁を表す変数 input_pos を作ります。
input_posの値は、一番左の桁の時0で一番右の桁の時3になり、その次また0に戻ってループするようにします。
つまり、ボタンが押されるたびに+1されて、3の時は0に戻る。
これを、0~9の画像がクリックされるたびに行います。
イベント処理の部分に以下を追加します

    input_pos = 0  # これは前の方で宣言しておく 
    # 現在の入力位置 左0123右 0,1,2,3の後は0に戻りループ

   if (event.type == pygame.MOUSEBUTTONUP) and (event.button == 1):
      for i in range(len(buttonrect)):   # すべての入力用数字画像でイベントをキャッチする
           if buttonrect[i].collidepoint(event.pos):
                if input_pos == 3:
                    input_pos = 0
                else:
                    input_pos += 1

あとは、描画の部分でinput_posの値に従って赤枠を描画します。
先ほどの赤枠の表示部分を以下の様に修正します。
ちなみ、pythonらしく、以下のように書いてもよかったんですが、

      for btn in buttonrect:   # すべての入力用数字画像でイベントをキャッチする
           if btn.collidepoint(event.pos):
                if input_pos == 3:
                    input_pos = 0
                else:
                    input_pos += 1

これでもいいんですが、後で繰り返しに使っているインデックスのiを使いたくなってしまったので、古き良きループにしました。

     margin = [100, 100] # *を表示する位置までのマージン(前回設定済み)
     imagesize = [100,100] # 画像1個当たりの大きさ(前回設定済み)
     for i in range(4): #marginの位置から4つ横に画像を並べるためのもの
         qbuttonrect.append(Rect(margin[0] + i * imagesize[1], margin[1], *imagesize))

       pygame.draw.rect(screen, (255,0,0), qbuttonrect[input_pos], 3)  

これで赤枠が移動して、現在度の桁を入力しようとしているのかプレーヤーに伝えることができます。


数字の入力処理

次はついに入力された数字を表示していきます。
また、同時にプレイヤーが答えた4桁の数字を表す変数を更新していきます。
まず、プレイヤーの入力した4桁の数字を表す変数を用意します。
テキストバージョンの時は毎回からのリストに4桁の数字を入力していましたが、今回は4つの要素を持つリストを作っておきます。

    players_input = [-1,-1,-1,-1]

この辺数に、input_posを使って、押された数字を入力していきます。
数字ボタンを押したときのイベント処理を以下の様に書き換えます。

for i in range(len(buttonrect)):
    if buttonrect[i].collidepoint(event.pos):
        players_input[input_pos] = i # ここでプレイヤーの入力を更新する
        input_pos += 1
        if input_pos == 4:
            input_pos = 0
        print(players_input)

実行結果:

[1, -1, -1, -1]
[1, 2, -1, -1]
[1, 2, 6, -1]
[1, 2, 6, 7]

players_inputが更新されているのがわかります。

入力された数字を画面に反映

あとは実は簡単に、プレイヤーが入力した数字を画面に反映させることができます。

    elif gamescene == 1:
        for i in range(4): # 入力された数字を表示する領域
            screen.blit(qimagelist[10], qbuttonrect[i])

ここを書き換えていきます。
players_input[0]~players_input[3]に、プレイヤーの入力した数字が保存されています。
初期状態では
[-1, -1, -1, -1]
です。数字が入力されると、その数字がそのまま整数で保存されています。
そこで、値が-1の場合は*の画像を、それ以外は数字の画像を表示するようにします。

qimagelist[0]~[9]に0~9の画像、qimagelist[10]に*の画像が収まっています。
初期状態以外の時は、
qimagelist[players_input[0]]で、最左桁の画像
qimagelist[players_input[3]]で、最右桁の画像を設定します。

    elif gamescene == 1:
        for i in range(4): # 入力された数字を表示する領域
            if players_input[i] == -1: # 初期状態なら*の画像を表示
                screen.blit(qimagelist[10], qbuttonrect[i])
            else: # 数字が入力されていたら数字の画像を表示
                screen.blit(qimagelist[players_input[i]], qbuttonrect[i])

実行してみます。

f:id:gomta777:20191119163753p:plainf:id:gomta777:20191119163757p:plainf:id:gomta777:20191119163802p:plain
図 入力の様子1

f:id:gomta777:20191119163805p:plainf:id:gomta777:20191119163809p:plainf:id:gomta777:20191119163750p:plain
図 入力の様子2

players_inputに値が入力されると同時に、画面の入力された数字が更新されていくのがわかります。


次回

今回のソースコード一式はgithubにもあります。
https://github.com/gomta777/hitandblow/
のinputnumberが今回のものです。

次回は、履歴の表示と、正誤判定を仕上げていきたいと思います。



よかったら、ブログ村↓のクリックお願いします。