Python初心者講座 60行でタイピングゲームを作ろう!

はじめに

Pygameで60行ぐらいでタイピングゲームを作ります。以下が完成したときのソースコードです。このぐらいの量なら初心者でも行けると思います。この記事は、各見出しごとに、機能を追加し、解説、ソースコードと実行結果を載せています。機能を追加した時点のちゃんと動くソースコードを載せているので、もし自分で書いて動かない場合は比較して参考にしてください。

それでははじめていきましょう。

 

※Pygameはpipでインストールしておいてください

タイピングゲームの基本動作を確認

  1. 単語帳からランダムに単語を選ぶ
  2. キー入力と単語の先頭文字が同じなら、単語の先頭文字を削除
  3. 単語が空かチェックして、空なら1に戻る

上に書いたように、タイピングゲームの基本動作は単純です。まずは赤文字の部分を作ってしまいます。

単語帳からランダムに単語を選ぶ

select_wordを追加したソースコード

解説

単語(word)、選ぶ(select)で、select_word関数を作ります。

単語帳(word_list)を配列で作ります。

len()関数は、配列の中身の数が分かるので、len(word_list)で、個数を求めます。上記の例では5個です。

random.randintでランダムな数を求めます。random.randint(0, 5)なら、0,1,2,3,4,5のどれかが取得できます。word_listは、中身が5個あって、配列は以下のように0から4で取得できます。word_list[5]とするとエラーになってしまうので、random.randint(0, num_of_elements – 1)のように-1します。

最後に、0から4のどれかがiに保持できたので、return word_list[i]で、呼び出し元に、選んだ単語を返します。

実行

スクリプトの最後に3つテストを書いているので実行したら、実行毎にランダムな単語が3つ表示されます。

単語の先頭文字を削除

解説

Pythonはスライス機能があるので、文字列[開始インデックス:終了インデックス] で文字列から一部分を取得できます。開始インデックス、終了インデックスは省略もできます。例えば”abcde”[1:]と書いたら、1番目の文字以降の文字列”bcde”を取得できます。配列のインデックスと同じで、ゼロ始まりなので、aは0番目の文字、bは1番目の文字です。

cust_head_charを追加したソースコード

実行

テスト2でpple, anana,herryのように、先頭文字を削除できているのがわかります。

単語が空かチェック

Pythonではnot演算子で、空””かどうかチェックできます。not演算子は、文字列が”abcde”のようにある場合は、Falseを返します。空””の場合はTrueを返します。

is_empty_wordを追加したソースコード

実行

テスト3の最後のテストが、Trueになっているのが分かります。

ここまでの作業のまとめ

  1. 単語帳からランダムに単語を選ぶ
  2. キー入力と単語の先頭文字が同じなら、単語の先頭文字を削除
  3. 単語が空かチェックして、空なら1に戻る

ここまでで3つの関数を作りました。残りは画面に単語を表示して、キー入力に対応するだけです。残り20行ぐらい。

画面を用意して塗る(fill,フィル)

いきなりいろんな作業をすると、分からなくなるので、まずは720×480の画面を作って背景を塗りつぶします。うまくいってから、文字列表示やキー入力を実装していきます。

解説

run_game関数を作ってそれを実行することで、ゲーム画面を表示します。

pygame.init()でゲームライブラリーを初期化します。

pygame.display.set_mode((720, 480))で、720×480の画面用意しscreen変数に保持します。今後はここに単語を表示させます。

screen.fill((200, 200, 200))で、淡いグレーでscreenを塗ります。

pygame.display.update()で、実際に画面が更新されます。

イベントについて

「閉じるボタンを押した」「キー入力」「マウスクリック」「マウス移動」「ウィンドウ最大化」などはすべてイベントとして扱います。何か発生するたびに、pygame.event.get()でイベントを取得して処理できるようにします。ちょうどfor文のとこです。

まずはpygame.QUITイベントに対応します。「閉じるボタンを押した」ときにこのpygame.QUITイベントが発生します。発生したときはsys.exit()でアプリを終了します。これを書かないとアプリが終了できなくなるので必ず必要です。

また、今回pygameとsysパッケージを使ったのでimport文も追加します。

ここまでのソースコード

実行

画面を灰色で塗る

単語を表示

ペイントソフトをイメージすると分かりやすいです。ペイントソフトで文字列を書く場合、フォントを用意して、文字列を書いて、それをpngなど画像ファイルとして書き出します。pygameの場合以下のようになります。

  1. フォントを用意 pygame.font.SysFont
  2. 文字列を書く font.render
  3. 書き出し screen.blit

解説

文字列を表示するためには、まずフォントを用意します。今回はNoneを指定し初期フォントを使います。

word = select_word()で、ランダムに選んだ単語を1つ用意して、それをrenderで書きます。

screen.blitで画面に書きだします。

ここまでのソースコード

実行

単語が表示できた!

キー入力と単語の先頭文字が同じなら、単語の先頭文字を削除

解説

キーが押されたら、pygame.KEYDOWNイベントが発生します。この時の入力されたキーはevent.keyで取れます。これはアスキーコードという数値なのでchr(event.key)で文字にします。そして、chr(event.eky) == word[0]で、単語の先頭文字と比較します。

もし同じなら、最初に作ったcut_head_char関数で、単語の先頭文字を削除します。

ここまでのソースコード

これで、キー入力して単語の先頭文字が同じ場合には削除されます。

単語が空かチェックして、空なら新たな単語を用意する

解説

単語が空かチェックするis_empty_word関数をあらかじめ用意していたので、空なら、word = select_word()で新たな単語を用意します。

解説:文字のセンタリング

文字列の左上頂点を求める

スクリーンサイズの半分から、文字列の幅の半分を引くとセンタリングするための文字列の左上頂点が求められます。図で理解するとよいです。

ここまでのソースコード

今回、以前書いたテストのprint文も削除しました。

実行

センタリングして、タイピングできるようになった

まとめ

60行ぐらいでタイピングソフトができました。これをどんどん改造していこう!フォントサイズ変更、色変更をした後に、スコア表示などができると思います。需要があれば、改造のしかたも書こうと思います。

カウントダウンタイマーはちょっと面倒でget_ticksを使います。以下は60秒のタイマーです。60行後、start_ticks = pygame.time.get_ticks()を呼び出してリセットする必要があります。

 

 

Python3+Tkinterでタイピングゲームを作ってみました。

 

https://github.com/dev001hajipro/typing-game-py

JavaScriptでタイピングソフトの基本部分を作ったので、Python+Tkinterに移植してみました。130行ぐらいで、タイマー、スコア表示、タイピングが実装できました。まだゲーム終了とリトライ機能、音声はありませんが、初心者には参考になると思います。またPython+Tkinter課題がいくつか見えてきました。

TkinterはUI更新はメインスレッドで行う

最初、タイマー機能を実現するために、ワーカースレッドを用意して、そのスレッドでUI更新をしようとしましたが、例外が発生しました。ワーカースレッドでは、データ更新を行い、Tk.after関数で定期的にUIリフレッシュをする機能を別途設けて対応しました。

Tkinterに音声再生はない

Pythonで音声再生をする場合は、PyAudioなどを使う方法がありますが面倒そうです。

Pythonではglobalに状態変数を持ち、それを関数で呼び出す場合コードが汚くなっていく。

Pythonはグローバル変数を関数のスコープで使う場合、globalキーワードを使います。とりあえずグローバル変数を使うと、コードが汚くなるのが分かりました。状態保持用のクラスを作成するなどをしたほうがよさそうです。

ゲームライブラリーを使ったほうが良い

ゲームエンジン、ライブラリーは、入力支援、音声再生、スプライト表示などが簡単に書けるので、PyGame、PySDL2、Godot3 Engineを検討したほうがよいと感じました。

PythonでSetIntervalとSetTimeoutと同じようなことがしたい。

はじめに

JavaScriptで作ったタイピングゲームをPythonに移植しようと思いました。JavaScript版では、カウントダウンタイマーをSetIntervalで実装していますが、同等の実装をPythonでどうするか調べてみました。

結論

  • PythonはJavaスレッドモデルをベースにしたthreadingパッケージがある
  • 一定時間後に、関数を呼び出したい場合は、threading.Timer。
  • 定期的に関数を呼び出したい場合は、threading.Threadを継承し、スレッドモデルで実装すればよい。

インターネットを調べていくと、質問が「SetIntervalのような定期実行をしたい」という質問のため、回答が関数を再帰的に呼び出し、スレッドを毎回生成しているコードを見つけました。(Python Equivalent of setInterval()?) これがPythonとして良いのかどうかはわかりませんが、毎回スレッドを生成するのに違和感があったので、もう少し調べたところ、threading.Threadを継承したサンプルを多く見つけました。

SetTimeoutのように、一定時間後に処理を実行する場合は、threading.Timer

threading.Timer(delay, task)で、待機時間を指定します。また、スレッドプログラミングなので、joinも使えます。

 

Pythonで定期的に関数を実行したいのでSetIntervalを調べる

標準ライブラリーでは用意されていないようです。実装するにはthreading.Event(),event.set(),event.wait()の知識が必要なようです。

少し調べていると、PythonのスレッドはJavaのスレッドモデルを参考にしているので、JavaScriptのSetIntervalで定期的に実行するのではなく、スレッドモデルの書きかたで実装すればよいだけでした。

もう少し具体的に言うと、threading.Threadクラスを継承したクラスを作成し、runメソッドを好みに書き換えればよいだけです。Pythonには、スレッド間通信するための便利なEventオブジェクトがあります。これでwaitの管理などをします。

ちなみにJavaはThread.sleep,Thread.join,Thread.interruptのようにEventオブジェクトではなく、Threadもしくはそのインスタンスでwaitなどを管理します。

基本的なコード

 

カウントダウンタイマー

上記ソースコードをベースに、カウントダウンタイマーを作りました。Countdownクラスを初期化するときの引数にcountで残り秒数を設定できるようにしました。

 

一定間隔で関数を呼び出す

厳密ではないですが、ひとまず一定間隔で呼び出せる。

厳密な間隔で呼び出したいとき

runメソッドのwhileループのチェックで、time.time()を導入します。以下をまずはコピペしてprintでいろいろ出力しながら試すのが簡単だと思います。

https://stackoverflow.com/questions/2697039/python-equivalent-of-setinterval/48709380#48709380

 

 

 

 

Python2と3がインストールされている環境で、venv仮想環境を用意してvscodeで開発をする方法

はじめに

Windows10で、Python3+venvを使い、環境を汚さずにプロジェクトの仮想環境を作りvscodeで開発するための初期設定メモです。

私は、Windows10に、Python2.7とPython3がインストールされている環境で、pythonを実行したらPython2が実行されpy.exeで切り替えられる環境になっています。

仮想環境venvと起動終了について

Pythonはpipコマンドでインターネット上のライブラリーを取得し使えます。ある程度使うと、PCごとのライブラリー管理ではなく、プロジェクトごとに管理したくなります。

以前は様々な仮想環境がありましたが、現在は標準でvenv仮想環境がインストールされます。以下のように1つのコマンドで簡単に仮想環境が用意できます。-m venvでvenvモジュールを使って、pyコマンドでpythonを実行します。また<name>に任意の名前を付けれますが、venvとする場合が多いようです。

ちなみに、py.exeで2か3どちらをデフォルトで起動するかは、PY_PYTHONで変更できます。py.iniファイルを記述する方法もあります。

venv仮想環境を用意した後、使うにはacivateし、使い終わったらdeactivateをします。仮想環境を用意したら<name>/Scripts/Activate.ps1とDeactivate.ps1が用意されるのでこれを実行すれば良いです。

実際にやってみる

hello_myprojectという名前でフォルダーを作成し移動

venvという名前で仮想環境作成

vscode起動

vscode上で CTRL+@ でPowershellを起動し、vscode上のPowershellで仮想環境を使えるようにする。

venvフォルダーにtest.pyを作成する。

この時に、Python3.6.x(venv)をvscodeが見つけて、pylintのインストールを促すので、Installします。以下のようにpylintが失敗する場合もありますが、

ターミナルは、(venv)のようにすでに、Python3のevnvが有効にされた状態なので、「python -m pip install –upgrade pip」を実行し、その次に「pip install pylint」を実行します。

あとは、このまま開発を続けられます。仮想環境はアクティベートが必要なことを忘れないようにしましょう。OSを起動し直したら、当然仮想環境は停止した状態なので、再度アクティベートする必要があります。

まとめ

Windows10で、Python3+venv+vscodeの環境を構築しました。

venv仮想環境は、アクティベート、ディアクティベートで起動、停止を行います。

プロジェクトフォルダーに、venv仮想環境(今回はvenvという名前にした)を用意して作業します。仮想環境名=プロジェクト名にして管理したくなりますが、そうするとvscodeが単純に認識しなくなるようです。

 

 

GTK+でボタンを右下に持っていき、ウィンドウ拡大に追随させる方法

GTK+のウィンドウの拡大縮小時に、ボタンを追随させる方法が分かってきました。以下のGladeのように、まずGtkBoxをウィンドウに貼り付けて、「ウェジットの間隔」にある「広げる」と「アライメント」を調整します。水平アライメントを「最後」に設定すると、ボタンが右に配置されます。垂直アライメントを「最後」に設定すると、ボタンが下に配置されます。この2つを行うことでボタンが右下に配置されます。

また、ウィンドウが大きくなったり小さくなった場合に追随させるには、「広げる」項目を画像のようにラジオボタンにチェックを入れて、「オン」にします。

他にGtkAlignmentというオブジェクトもあります。これをボタンの親オブジェクトにして、同様に右下に持ってくることも可能なようです。

DebianLinuxでGTK+3.0のチュートリアルを試してみた感想

Go言語で、GUIを調べていたらGTK+3.0のバインディングがあるそうです。GTK+はバインディングが豊富でスクリプト言語などでも使えます。良い機会なのでDebian LinuxでC言語を使ったWindow表示を試してみました。

Programer’s Notes – GTK Glade C Programming

が初心者向けのチュートリアルで1つの記事の量も少なく、わかりやすいです。

開発環境構築とHelloworld

https://prognotes.net/2015/06/gtk-3-c-program-using-glade-3/

上記チュートリアルは、はaptでgtkライブラリーのインストールやビルド方法も乗っていて簡単にWindowを表示できました。pkg-config によりライブラリーのインクルードやリンケージは自動です。またビルド時に-export-dynamicが必要になります。最初これをつけていなくてビルドがうまく行きませんでした。

GTK+はGUIビルダーGladeがある

GTK+はWin32APIのように、ほぼ全てをテキストエディターで書いていくと思っていたのですが、かなり昔からGUIビルダーのGladeがあり、これでUIを作成しながら、任意のエディターでコードを書いていけます。

Geanyエディター

Geanyは、タグファイル が用意されているので、gtk-3.16.6.c.tags をダウンロードし、[ツール]->[Load Tags]で、タグファイルを読み込むことで、コード補完が出来ました。

gladeファイルの読み込み

GLADEでGUIを作成した場合は、gtk_builder_add_from_file関数で、.gladeファイルを指定できるのでそれで、ソースコードと.gladeファイルの連携が可能になります。main.cを作成して、GLADEで、window_main.gladeを作成し、無事にWindowを作成できました。

APIは、C++のようにオブジェクトがメソッドを持つわけではないため、gtk_object_xxxxのような形になりますが、補完ができたのでそこまでストレスはありませんでした。

GTK+3.0でWindowを表示して、日本語のタイトルをつけれた!

GTK+3.0の開発はかなり軽い

WindowsのHyper-V仮想環境でDebian+LXDE で動かしていますが、GUIビルダーもエディターのGeanyもホストの環境と同じように快適に動かせています。Ubuntu をデフォルトでインストールすると非常に重いので、先入観でGTKの開発は重そうなイメージを持っていましたが、超軽量でした。