先日、親指サイズのゲーム機「Thumby」が安くなっているのを見つけて買ってみた。Thumbyは超小型ながら、MicroPythonで作った自作ゲームを動かすことができる超小型ガジェットだ。WebのIDE上で開発できるのだが、開発ツールの出来が良く、本体が手元になくても、遊んでいてとても楽しい。今回は、ThumbyエミュレーターでPythonゲームを作って遊んでみよう。
-

Thumbyエミュレーターで遊んでみよう
Thumbyについて
「Thumby」は、アメリカ・オハイオ州に本拠を置くオープンソースハードウェア企業のTinyCircuitsが開発販売する親指サイズのゲーム機だ。しかし、ゲーム機というと語弊があるかもしれない。小さすぎてゲーム自体を楽しむのはそれなりに難しいからだ。そのため、自作ゲームが実行できる極小ガジェットと言えば良いだろうか。
-

100円玉と比べるとどれだけ小さいか分かる
調べてみると、2024年に「Thumby Color」という次世代モデルも発売されている。今回、筆者が購入したのは、2022年に発売された、白黒の初代モデルだが、レトロ感があって気に入っている。今回、発売から時間が経ち、次世代モデルも出たせいか価格が下落したようだ。
-

Thumbyの電源を入れたところ
Thumbyには最初から数種類のゲームがプリインストールされており、それを眺めるだけでも楽しいのだが、MicroPythonを使って自作ゲームを作って楽しむことができるのが、大きなポイントだ。
小さいながら、72×40ドットのモノクロOLEDを装備しており、CPUには「Raspberry Pi Pico RP2040 Processor」を採用、2MBのストレージを内蔵している。
Thumbyエミュレーターで遊ぼう
Thumbyを入手したなら、ThumbyとPCをUSBで接続してみよう。ブラウザでThumbyのコードエディタにアクセスすると、ストレージの中を見たり、ゲームを作って保存することができる。ファームウェアの書き換えもブラウザから可能だ。
とは言え、Thumby本体を持っていなくても、エミュレーター付きのコードエディタを使って、プログラムを作ることができる。このエミュレーター付きコードエディタだけでも、十分楽しめる。
こちらから、ThumbyのIDE/コードエディタにアクセスしてみよう。このIDEでは、MicroPythonと、ブロックを組み合わせてプログラムを作るBlocklyを選べるようになっている。本連載は、Pythonの連載なので、迷わず、MicroPythonをクリックして選ぼう。
-

誰でも無料で使えるThumbyのコードエディタ
そして、MicroPythonのエディタを有効にしたあと、画面上部の[ARCADE]ボタンを押すと、Thumby向けのゲームを読み込んで遊ぶことができる。このゲームは、公式が用意したもののほか、ユーザーから募ったものも多数あり、Thumbyファンがたくさんいることが窺える。
-

Thumby用に用意されたゲームたち
そして、気になるゲームを選んだら、ゲームにカーソルを合わせて[Open]ボタンをクリックしよう。すると、ゲームのソースコードをエディタで確認できる。そして、エディタの右上にあるEMULATIONのチェックを入れた状態で、画面右下のエミュレーターの下部にある[START]を押すと、実際にゲームを遊ぶことができる。白黒のゲームでありながら、かなり本格的なものもあり、とても面白い。
-

Thumbyのゲームを遊ぶことができる
白黒でASCIIフォントしかないが楽しい
なお、ソースコードを見ると分かるのだが、Thumbyにプリインストールされているゲームも全部、MicroPythonで書かれており、公式と同じレベルでユーザーがゲームを作ることができる。
エミュレーターの画面を見ると分かるが、白黒であり、画面サイズも小さい。しかも、内蔵されているフォントときたら、英語・数字・記号の表示が可能なASCIIフォントしかない。しかも最大8×8サイズのビットマップフォントだ。それもそのはずで、本体ストレージはシステム込みで2MBしかないのだ。とは言え、かつてのゲームボーイのゲームは、2MB未満のものもたくさんあった。何事も工夫次第だ。
画面に文字を表示するだけのHello, World!を作ってみよう
それでは、Thumbyで「Hello, World!」とテキストを表示するだけのプログラムを作ってみよう。こちらのコードエディタにアクセスしたら、MicroPythonを選択して、画面上部のメニューから[UTILITY > MAKE NEW GAME]をクリックしよう。ファイル名を求められるので「hello.py」と入力しよう。そして、以下のようなMicroPythonのプログラムを記述する。
import thumby
# 描画フォントの設定
thumby.display.setFont("/lib/font8x8.bin", 8, 8, 1)
# 画面をクリア
thumby.display.fill(0)
# テキストを出力
thumby.display.drawText("HELLO,", 0, 0, 1)
thumby.display.drawText(" WORLD!!", 0, 9, 1)
thumby.display.update()
エディタ画面の右上にある「EMULATION」にチェックを入れて、エミュレーターで[START]ボタンを押してみよう。画面に「HELLO, WORLD!!」と表示される。
-

一番簡単なプログラムを実行したところ
プログラムのポイントは一行目にある「import thumby」だ。これは、Thumbyを操作するライブラリを読み込むものだ。thumby.display.setFont関数でフォントを読み込み、thumby.display.drawText関数で任意の位置に文字を出力できる。
どんな命令が使えるのかは、こちらのAPIマニュアルに網羅されている。Thumbyはとても仕様が小さいので、全ての命令に目を通すのも、それほど苦ではないのが良い所だ。今のところ、英語のマニュアルしかないものの、関数名で当たりを付けたり、AIに翻訳してもらえば、よく理解できる。
ライフゲームを作ってみよう
次に、ライフゲームを作ってみよう。ライフゲームは、本連載の9回目でも紹介した、生物の誕生と淘汰をシミュレーションするゲームだ。
定期的に画面をクリアし、規則に従って正方形を描画するだけなので、ゲーム作りのチュートリアルには、ぴったりの題材と言える。
次の画像は、実機で自作のライフゲームを動かしているところだ。とても小さいがしっかりライフゲームが動くのが面白い。
-

実機でライフゲームを実行してみたところ
タイトル画面も付けてみたので少し長くなったが、作ったプログラムは100行未満。Thumbyのプログラムの雰囲気が分かるものになった。
import time
import thumby
import random
# 定数の定義
DISP_W = thumby.display.width # 72
DISP_H = thumby.display.height # 40
# セルのサイズと個数を定義
CW, CH = 3, 3
COLS,ROWS = DISP_W // CW, DISP_H // CH
# 相対座標の定義
REL_XY = [
(-1, -1), ( 0, -1), ( 1, -1),
(-1, 0), ( 1, 0),
(-1, 1), ( 0, 1), ( 1, 1),
]
# 描画フォントの設定
thumby.display.setFont("/lib/font5x7.bin", 5, 7, 1)
# FPSを指定
thumby.display.setFPS(8)
# ゲーム定数の指定
flag_title = True
cells = []
cur = {}
def clear_screen():
"""画面をクリア"""
thumby.display.fill(0)
cur["x"] = 0
cur["y"] = 0
def echo(text):
"""画面出力"""
thumby.display.drawText(text, cur["x"], cur["y"], 1)
cur["y"] += 7
def init_game():
"""ゲームを初期化"""
global cells
cells = [[random.randint(0, 1) for _ in range(COLS)] for _ in range(ROWS)]
def draw_cells():
"""セルを描画""" # --- (※1)
clear_screen()
for y, row in enumerate(cells):
yy = y * CH
for x, v in enumerate(row):
xx = x * CW
if v:
thumby.display.drawFilledRectangle(xx, yy, CW-1, CH-1, 1)
def count_life(x, y):
"""周囲八方向の生物の数を数える"""
cnt = 0
for p in REL_XY:
xx, yy = x + p[0], y + p[1]
if xx < 0 or yy < 0 or xx >= COLS or yy >= ROWS:
continue
if cells[yy][xx]:
cnt += 1
return cnt
def next_generation():
"""次の世代へ"""
global cells
cells2 = [[0 for _ in range(COLS)] for _ in range(ROWS)]
for y in range(ROWS):
for x in range(COLS):
n = count_life(x, y)
v = cells[y][x]
if v == 0:
if n == 3:
cells2[y][x] = 1
elif 2 <= n <= 3:
cells2[y][x] = 1
cells = cells2
# メインループ
while True:
clear_screen()
if flag_title: # タイトルを表示
echo("------------")
echo("* LIFEGAME *")
echo("------------")
echo(f"A:Quit B:GO")
if(thumby.buttonB.justPressed()): # --- (※2)
flag_title = False
init_game()
thumby.display.update()
continue
draw_cells()
next_generation()
# ボタンの状態を確認
if (thumby.buttonB.justPressed()):
init_game() # セルを初期化
if(thumby.buttonA.justPressed()):
thumby.reset() # ゲームを終了する
# 画面を更新(重要)
thumby.display.update()
プログラムを実行するには、画面上部のメニューから [UTILITY > MAKE NEW GAME] をクリックし、ファイル名を「LifeGame.py」として、上記のプログラムを入力しよう。そして、エディタ画面の右上にある「EMULATION」にチェックを入れて、エミュレーターで[START]ボタンを押すと、実行される。
なお、プログラムはこちら にもアップしている。
このプログラムのポイントは二つある。まず、プログラムの(※1)では、生物の生死をthumby.display.drawFilledRectangle関数を使って描き分けている。
そして、二つ目のポイントは、(※2)でthumby.buttonB.justPressed関数を使って、Bボタンが押されているかどうかを判定している部分だ。ゲーム内では、Bボタンが押されたら、生物の生死をランダムに初期化するようにしている。それで、Bボタンが押されたかどうかを毎フレーム調べるようにしているのだ。
まとめ -Thumbyでゲーム作りするのは楽しい
以上、本稿では、Thumbyについて紹介した。MicroPythonで自作ゲームが作れるので、とても楽しい。筆者は、今回紹介したライフゲーム以外も、サイコロゲームを作ったり、迷路ゲームを作ったりと、ミニゲーム作りにハマってしまった。
親指サイズのThumbyでは、できることが限られている。しかし、だからこそ、ちょっとした工夫が生きてくる。「この小さな世界で何ができるだろう」と制約のある中でアイデアを出すのもワクワクする。
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。これまで50冊以上の技術書を執筆した。直近では、「大規模言語モデルを使いこなすためのプロンプトエンジニアリングの教科書(マイナビ出版)」「Pythonでつくるデスクトップアプリ(ソシム)」「実践力を身につける Pythonの教科書 第2版」「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」など。
