0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonAdvent Calendar 2024

Day 25

【typehandler】最短9行で実装!タイピングゲーム用のPythonモジュールを作ってみた

Last updated at Posted at 2024-12-23

PyPI Downloads

はじめに

 今回は、タイピングゲームのためのPythonモジュールを作ったので、紹介したいと思います。そもそも作ろうと思ったきっかけですが、筆者が高校生のころから寿司打ヘビーユーザーというのもあり、タイピングゲームに興味があったこと。Pythonで、複数パターンの入力に対応したタイピングゲームを作ってる人が、見られなかったこと。この2つになります。

コンセプト

 とにかく使いやすさを重視していますprint('HelloWorld!!')レベルの手軽さが理想ですが、ゲーム画面の描画と、キーイベントの検知もこちらで実装すると、あまりにも自由度が低すぎます。したがって、これらの機能をどのモジュールで実装するかは、各自に委ねる形にしました。音声なども扱えますし、個人的にはpygameがおすすめです。(単に筆者の好みです。typehandlerの機能的に、pygameと相性が良いという事ではありません。)

参考にしたサイト

こちらのサイトを真似させてもらい、チャンクというのを使った方法を採用しています。どうやって判定していくのかについては、こちらのサイトに載っているので、割愛させてもらいます。筆者がメインにやったことは、それらをPythonに落とし込んで、機能ごとに使いやすくまとめるってだけです。とりあえずタイピングゲームを作りたいだけだから、モジュールがあるならそれでいいや、という方はこのままお進みください。自分で実装したいんだ!という人はこちらのサイトへどうぞ。

インストール方法

以下の名前でpipできます。

pip install typehandler

最新版は0.3なので、もしも0.1や0.2がインストールされていたら、以下のようにしてください(0.1と0.2はPyPIに不慣れ故に動かなかったやつです)

pip install typehandler==0.3

メソッドの一覧

とりあえず使いたいだけの人は、次の項目にサンプルコードを置いてあるので、この項目は飛ばしてください。あと細かい使い方はREADMEの方に載せてあります。

READMEこちら

divide(hurigana: str) -> List[str]

ひらがなだけの文字列を受け取って、入力パターンのリストを返します。自分で別の判定方法などを実装したい場合に、こちらを活用していただけます。

他のメソッドも見る

set_new_sentence(words: Dict[str, str] = None) ->None

別の文章に変更するためのものです。例えば時間制限に引っかかったり、文章を打ち終わったら、これを呼び出すみたいな使い方を想定しています。引数に辞書を渡すと、その辞書から新しい文章を選びます。

set_new_words(words: Dict[str, str]) ->None

別の辞書をセットします。これを呼び出すと、その時点で文章も再設定されます。

check_correct_input(key: str) ->bool

キーの名前を受け取って、そのキーが入力パターンにあればTrue, なければFalseを返します。ifの条件として使うことを想定しています。

check_chunk_completion() ->bool

こちらもifの条件として使うことを想定しています。check_correct_inputTrueを返した後、こちらでひらがなを打ち終わったかどうか判定します。ひらがなを打ち終わっていたらTrue、いなければFalseを返します。

check_sentence_completion() ->bool:

こちらもifの条件として使うことを想定しています。check_chunk_completionTrueを返した後、こちらで文章を打ち終わったかどうか判定します。文章を打ち終わっていたらTrue、いなければFalseを返します。

update_show_roman() ->str

現在入力してあるところまでを基に、入力パターンの一例を返します。常に最新の状態にするために、ゲームループ中で毎回呼び出すことをお勧めします。

main() ->None

特に音声などを付けないのであれば、これを呼び出すだけで、正誤判定から文章の打ち終わりまで判定して文章の更新もしてくれます。

その他変数

input

既に入力済みのローマ字

show_roman

入力パターンの一例

sentence

お題の文章

これらにアクセスできますので、画面にこれらの情報を描画したい時にお使いください。

使用例

minimum.py
import tkinter, typehandler
words = dict(リンゴ = 'りんご',バナナ = 'ばなな',ブドウ = 'ぶどう',レモン = 'れもん')
root = tkinter.Tk()
game = typehandler.Process(words)
def key_pressed(event):
    game.main(event.keysym)
    print(f'{game.input}\n{game.sentence}')
root.bind('<Key>', key_pressed)
root.mainloop()

↑最小でこんな感じで実装できます。(wordsを変数として宣言しなければ8行になりますが、見づらいので止めました)

sample.py
import pygame, sys
from typehandler import Process

pygame.init()
screen = pygame.display.set_mode((600, 500))
pygame.display.set_caption('example')

font =  pygame.font.SysFont("MSP Gothic", 32)

def vocalize(se):
    #音声を再生する
    pygame.mixer.init(frequency=44100)
    pygame.mixer.set_num_channels(32)
    sound_key = pygame.mixer.Sound(se)
    sound_key.play()

words = dict(リンゴ = 'りんご',
             ブドウ = 'ぶどう',
             レモン = 'れもん',
             バナナ = 'ばなな',
             )

def main():
    clock = pygame.time.Clock()
    process = Process(words)
    while True:
        process.update_show_roman()
        screen.fill((255, 255, 255))
        text_roman = font.render(process.show_roman, True, (192, 192, 192))
        text_input = font.render(process.input, True, (0, 0, 0))
        text_sentence = font.render(process.sentence, True, (0, 0, 0))
        pygame.draw.line(screen, (0, 128, 255), (0, 50), (600, 50), 5)    #青い線を描画
        pygame.draw.line(screen, (255, 128, 0), (0, 150), (600, 150), 5)    #オレンジの線を描画
        screen.blit(text_roman, (30,60))
        screen.blit(text_input, (30,60))
        screen.blit(text_sentence, (30, 100))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                correct_input = process.check_correct_input(pygame.key.name(event.key))    #ミスタイプを判定
                if correct_input:
                    vocalize('input.ogg')
                    chunk_conpleted = process.check_chunk_completion()    #文の打ち終わりを判定
                    if chunk_conpleted:
                        sentence_completed = process.check_sentence_completion()
                        if sentence_completed:
                            vocalize('next.mp3')
                            process.set_new_sentence()    #新しい文を用意
                else:
                    vocalize('miss.ogg')
        pygame.display.update()
        clock.tick(50)

if __name__ == '__main__':
    main()

もうちょっとまともな例を用意しました。音声の再生とかをするならこのようになります。音声ファイルを用意するのがめんどくさい方は、コメントアウトして、動きだけどんな感じか見てください。先ほどはtkinterで今度はpygameを使っている通り、キー入力の判定さえできれば、何のモジュールを使っていただいても構わないです。
 ちなみにですが、fpsは50くらいあった方がいいと思います。30も試しましたが、筆者の入力速度でも、たまに追いついてきてくれませんでした。筆者より速い人は60くらい必要だったりするんでしょうか...?世の中には化け物みたいに速い人もいますからね....

参考までに筆者のレベルが分かるものを置いておきます

スクリーンショットを見る

image.png

最後に

 ここまで読んでいただきありがとうございました。PyPIに登録してpipできるようにするのが初めてだったので、ちょっと大変でした。ひらがなの辞書の部分を除けば150行くらいしかないので、ブラウザゲームを作りたいから、外部モジュール使えないなーって人は、以下のページからprocess.pyの中身をコピペして使っちゃってください。

ちなみにブラウザゲームの公開方法の記事も出しているので、タイピングゲームを自作して公開までを行いたい方は、この記事と併せてご覧いただけると嬉しいです。(ちゃっかり宣伝)

実際に筆者が公開してみたタイピングゲームはこちらから遊べます

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?