ChatGPTでジェネレーティブアートジェネレータ

ChatGPTに特定の機能を持つコードのスニペットを書くように頼むのはよくある使い方だ。ただChatGPTは回答の長さに制限があるので、あまり長いコードの出力をお願いするのは現実的ではない。プログラム全体の仕様をプロンプトで投げて、そのコードを返してもらう、みたいな使い方はまだ難しい。

でもジェネレーティブアートみたいな、比較的短いコードでプログラムが完結するものであれば、プログラムコード全体を出力してもらうのも現実的だ。

例えば以下のプロンプトで、p5.jsで書かれたジェネレーティブアートっぽいコードが出てくる。


I want you to act as a generative art programmer. Conceive an unprecedented abstract and geometric animation piece, which loops infinitely, utilizing the p5.js framework, centered around the theme of "[Theme Name]". Consider using noise, mathematical functions or fractals to achieve this task, refraining from the use of user input. Set the canvas size to 400x200. Do not write explanations. Just show me the code for it.


このプロンプトで工夫した点は、[Theme Name]を使って、こんなテーマの作品を作ってとお願いしたところ。これがある種の乱数シードのように働いて、いろんなバリエーションの作品ができることを期待した。

このプロンプトにいろんなテーマ名を与えて、さらに気にいったものが出てくるまでなんどか回答をRegenerateした結果、以下のような作品ができた。出てきたコードはいっさい加工していない。

screenshot

作品、与えたテーマ名、生成されたコードを表示している。まあまあいろんな作品ができているのではないだろうか。

ただテーマに沿った作品ができているかというと、どうだろう。'hexagons'みたいな直球のテーマはうまくくみ取ってくれる。'recursive life forms'も結構それっぽいのは驚きだ。ちなみにrecursiveは興味深い作品ができる魔法の言葉だが、無限に再帰する行儀の悪いコードがしばしばできる諸刃の剣。

悪ふざけで'digdug'とか入れたら、ChatGPTもdrawDigDugという関数を生成してきたが、君は本当にDigDugホリ・タイゾウのことを知っているのかね。プーカの赤、ファイガーの緑、ホリ・タイゾウの青が並んでいるのは、偶然だよね?

理想的にはつぶやきProcessingの作品くらいのクオリティ、バリエーションが得られるのが良いのだが、プロンプトの工夫だけでそこまでいけるかは分からない。せめて作品をつくる際のブレスト、取っ掛かりに使えるといいな。

ChatGPTに新しいロジックパズルを考えてもらう。それが本当に新しいかの保証はないけど

ChatGPTに今までに無かった新しいロジックパズルを考えてとお願いしたら、Sumpleteというゲームが提案されたという話。2次元のグリッド上に数字が、右端と下端に各行と列の数字の合計が書いてあるので、グリッド上の数字に×をつけて、書いてある合計になるようにするゲーム。

ところがこのゲームは実はすでに存在していた。Hacker Newsのスレッドで挙げられていたこのゲーム。

まあ世の中の全てのゲームを知ることは、人にもAIにも無理なので、新しいゲームを考えたけどすでにあったということは往々にしてある。なので本当に新しいかを保証するのが無理なのはしょうがないね。

それはそれとして、ChatGPTにロジックパズルを考えてもらうのは面白そう。以下のプロンプトでお願いしてみよう。


I want you to act as a logic puzzle game designer. Devise 5 novel logic puzzles. Create rules that are different from logic puzzles that already exist, such as Sudoku. The puzzle should consist of a two-dimensional grid. Several grids may be divided by walls. The initial state of the cells consists of both cells containing numerals or symbols, as well as empty cells. The player fills in the blank squares and tries to reach the correct solution.


2Dのグリッドのいくつかのマスに数字やシンボルが入っていて、空いているマスを埋めるタイプのロジックパズルを5つ考えて。グリッドは壁で区切られていてもよい。へやわけみたいなものが出てくるといいなと思って書いたプロンプト。

いくつか提案してもらった中に、以下のパズルがあった。


"Magnet Blocks"

In this puzzle, the grid contains magnets of opposite polarity (north and south). The player must fill in the grid with blocks of positive and negative polarity, such that each block attracts or repels adjacent magnets according to their polarities. A block can only be placed if it fits in with the surrounding magnets, and no two blocks of the same polarity can touch each other.


Magnet Blocksという、磁石を題材にしたパズルらしい。ChatGPTに日本語への翻訳もしてもらうと以下の通り。


このパズルでは、グリッドには異なる極性(北極と南極)を持つ磁石が含まれています。プレイヤーは、各ブロックが隣接する磁石の極性に応じて引き付けまたは反発するように、正および負の極性のブロックでグリッドを埋める必要があります。ブロックは周囲の磁石に合わせて配置され、同じ極性のブロックは互いに触れてはいけません。


パズルのルールとしてはあまりに漠然としているが、要は磁石をNとN、SとSが触れないように配置するゲームだと解釈した。なので以下のゲームにした。

screenshot

ブラウザ上で遊べます。ルールは以下。

  • グリッド上に棒磁石と壁が配置されている
  • NとN、SとSが隣接しないように空いているマスに棒磁石を置く。棒磁石は3マス以上の任意の長さで置ける
  • 全ての空いているマスに棒磁石が置ければクリア

レベル生成ロジックがイマイチのこともあって、パズルとしての深みは出せていないが、一応パズルとして成り立っている。

で、このパズルははたして新しいのか。Twitter上で聞いたところ、以下のMagnetsというパズルを教えてもらった。

磁石が題材のところは同じ。だけどルールはかなり異なる。

  • 棒磁石が置ける場所、方向はあらかじめ決まっていて、長さは2で固定
  • +とーが行と列に何回出現するかの制約がグリッドの外周に書いてある
  • 全ての空きマスを埋める必要はない

なので一応現時点では同じルールのパズルは見つかってない。けど磁石モチーフではない同じルールのパズルとかがあるかもしれない。分からない。

ロジックパズルは様式が定まっていることもあって、その様式の制約をとっかかりに、ChatGPTに新しいルールを考えてもらうモチーフとしては良いように思える。ただ、その定まった様式ゆえに、新しいと思って作ったものが既存のものと一致してしまうことも多そう。

また、パズルとして成り立つ厳密なルールをChatGPTに生成させるのは難しいので、あいまいな提案を具体的なルールにするのにはまだ人手がいる。遊べる形のプログラムコードにするなんてのはまだまだ難しい。

あと、できたパズルが解いていて楽しいか、ということを判断する、というのもまた別の難しさだ。これはルールだけでなくて、問題の生成ロジックにもかかわってくる。

厳密なルールを作る、などのChatGPTが不得意とする作業は、ChatGPTとは別の方法、プログラムで補うということができれば、チャットAIの応用範囲はさらに広がるだろう。

計算やファクトの検索に長けたWolfram|Alphaと連携する、なんてのはその一例になりそう。コーディングの観点からは、コンパイラや言語サーバー、IDEとの連携がより進むことを期待したいね。

ゲームメカニクスのタグを組み合わせて、新しいゲームをChatGPTに考えてもらおう

この前、アクションミニゲームのゲームメカニクスをタグとして列挙した。

まずはタグの組み合わせから新ゲーム考案というのが現実的かを試してみたい。

試すのは人間とは言ってない。AIにやってもらおう。

ChatGPTに以下のプロンプトを与えて、ゲームデザイナーとして振舞ってもらう。


I want you to act as a game designer. Remember the following tags related to game mechanics. The tags are written in a format of 'Category: Name, "Description"', with one line for each tag. Randomly combine those tags and come up with a new game that contains only the game mechanics corresponding to that tag. Make that game an action mini-game that utilizes only a single button. The maximum number of tags that may be combined is 5. Describe what kind of game it is and the selected tags. Try to devise 5 different games without using the same game mechanic tags as much as possible.

player: rotate, "The player character rotates."
player: reciprocate, "The player character reciprocates horizontally or vertically."
player: reflect, "The player character reflects upon colliding with a wall or object."


以下タグ一覧ファイルにあるタグとその概要説明が続く。プロンプト全体はここにある

すると以下のような回答が得られる。


Game 1: Scaffold Jump
Selected tags: player: scaffold, on pressed: jump

Description: In this game, the player controls a character that moves along scaffolds. The character constantly moves forward, and the player can make the character jump by pressing the button. The objective is to avoid falling off the scaffolds or hitting obstacles while collecting coins or power-ups. The game gets progressively faster and more difficult as the player advances.

Game 2: Pinball Panic
Selected tags: player: circle, weapon: bounce, field: pins, on pressed: shoot

Description: In this game, the player controls a circular character that bounces around a pinball-like field. The player can shoot projectiles by pressing the button, which bounce off the pins and destroy enemies. The objective is to survive as long as possible while racking up points by destroying enemies and collecting power-ups.

Game 3: Springy Strings
Selected tags: player: string, player: bounce, field: gravity, on pressed: jump

Description: In this game, the player controls a spring-like character that bounces around a zero-gravity field. The character can jump by pressing the button, which sends it bouncing higher into the air. The objective is to avoid obstacles and enemies while collecting power-ups and reaching the end of the level.

Game 4: Wipeout Warriors
Selected tags: player: bar, field: water, obstacle: chase, weapon: wipe, on pressed: jump

Description: In this game, the player controls a bar-shaped character that races through a water course filled with obstacles and enemies. The character automatically moves forward, and the player can make the character jump by pressing the button. The character can also use a wiping weapon to clear the way of obstacles and enemies. The objective is to reach the end of the course in the shortest time possible.

Game 5: Color Conundrum
Selected tags: rule: match, rule: time limit, field: roughness, on pressed: turn

Description: In this game, the player controls a character that must navigate a rough terrain while matching colors. The character automatically moves forward, and the player can turn left or right by pressing the button. The objective is to match as many colors as possible before the time runs out, while avoiding obstacles and enemies on the way.


ゲーム名と選択したタグ、ゲームの内容を考えてくれる。ここから面白そうなゲームをピックアップすれば、ゲームアイデアとして使えるのでは。

例えばゲーム2「ピンボールパニック」。ピンボールのようなフィールドにピンや敵がいて、ボタンを押すと発射される球で敵を破壊する。ピンで跳ね返る球をうまく制御して敵に当てる必要がある。球をピンボールのフリッパーで打ち出すようにしても面白そう。

ゲーム3「スプリンギーストリングス」。重力の無い空間を、バネの伸縮を利用して障害物や敵をかわしながら進んでいく。障害物を蹴って進んだり、AMBACめいた挙動をするゲームだろうか。

ゲーム5「カラーコンランダム」。デコボコした地形の上を、ボタン操作で左右に曲がるプレイヤーキャラクタを操作して、色をマッチさせながら進む。見下ろし型のゲームで、出っ張った地形を避けつつ、同色のカラーアイテムを集めるようなゲームが思いつく。

このままChatGPTがゲームの実装をしてくれるととても楽なのだが、さすがにそれはまだ無理っぽい。'Implement Game 1 in p5.js.'のように頼むと一応頑張って書いてはくれるのだが、これらゲームメカニクスを正しく反映したコードにはならない。というかChatGPTに書いてもらうにはコードが長すぎる。

ChatGPTにゲームメカニクスのタグを教え、それらを組み合わせてもらう。ゲームアイデアのベースを考えるには良い方法ではないだろうか。こういったブレーンストーミング的な使い方にはChatGPTはよくマッチするね。

自作ゲーム群を仕組みに分解して一覧できれば、新たなゲームを考えるのに役立つのでは?

screenshot

今まで色々なアクションミニゲームを作ってきたが、作るときに一番難しく、かつ楽しいのがゲームのアイデア、ルール、内容を考える部分だ。ゲームを遊んだ、作った経験などから、行き当たりばったりにゲームアイデアを考えるのはそれはそれで楽しいが、もうちょっと系統立てて考える方法はないだろうか。

例えば、今まで作ったゲームが、どのような仕組みから出来上がっていて、その仕組みがプレイヤーにとってどのような楽しさや難しさを提供しているかを整理し、それら仕組みを組み合わせて新たなゲームを作るのはどうだろう。

試しにやってみた。

今まで作ったゲームが、どのようなプレイヤーキャラクタ、武器、障害物、フィールド、ルール、操作から構成されているかを、カテゴリごとのタグで整理した。上記ページでタグが一覧できる。各タグの詳細(Detail)ボタンを押すと、それぞれのタグの説明、およびそのタグが付加されたゲームの一覧が見られる。

例えばこれはプレイヤーキャラクタが回転するタグのページ。回転のタイミングに合わせて操作するゲームで、プレイヤーがタイミングを図る方法としてどのようなバリエーションが考えられるかが、ゲームの一覧からなんとなく分かる。

武器が放物線上に飛ぶ。投げ方や投げるもの、着弾した時の効果のバリエーションが分かる。

ペナルティのある物を混ぜる。何も考えずに攻撃を続けるのではなく、画面の状況をよく見て攻撃タイミングを図るタイプのゲーム。

到達することでゲームオーバーになる地点。ゲームオーバーになるリスクを与える方法のバリエーション。

近接ボーナス。障害物の近くにボーナス点を配置するのはリスク・リワードの基本。

ボタンを押したら属性反転ワンボタンでできることの記事でもプレイヤー操作に対する動作バリエーションについて書いたが、タグに基づいて整理することで、より分かりやすくなるのではないだろうか。

これらページの使い方としては、

  • タグ一覧ページを見てアクションミニゲームに組み込める仕組みを把握する
  • タグ詳細ページを見てその仕組みを使った別のゲームを考える
  • 複数のタグを適当に組み合わせてそれら仕組みを使ったゲームを考える

あたりを考えている。

こういったゲームの仕組みは、よくゲームメカニクスと呼ばれる。

ゲーム内でとれるプレイヤーの行動や、その行動に対応して起こるゲーム内の出来事などを整理したものがゲームメカニクスだ。あるゲームがどのようにデザインされているかを解析するためや、新たなゲームを考える際の助けとして使われたりする。ゲームプレイはゲームメカニクスの間のフローと言われたりするが、ゲームメカニクスをベースに、それらを組み合わせたゲームプレイ体験をどのようにするか、プレイヤーに対するチャレンジをどう与えるかなどを考えることができる。

ゲームメカニクスとしてどの程度の粒度のものを挙げるべきかは、特に決まった指標が無いように思える。ターン、リソース管理、リスクとリワード、など抽象的な要素をメカニクスとして挙げる場合もあれば、ジャンプ、シールド、回転、パワーアップなど細かなゲーム内アクションを挙げる場合もある。

今回は新しいアクションミニゲームを考える助けになるために、という目的のもと整理したかったので、後者の細かなゲーム内アクションに近い粒度でまとめた。あと各メカニクスに対してそれを取り入れた実例が見えることが、そのメカニクスをどのように他のメカニクスと組み合わせているか、どのようなリスク(チャレンジ)やリワードをプレイヤーに与えているかを把握することに重要だと思ったので、実例のゲームが見られて遊べるようにした。

自作ゲームを例に整理したので、アクションミニゲーム、とくにワンボタンゲームに偏重した内容になっていることは否めないが、ゲームアイデア発想法として良さそうかの実験くらいはできるだろう。まずはタグの組み合わせから新ゲーム考案というのが現実的かを試してみたい。

1次元ゲームの世界

1次元ゲームとは、ゲームフィールドが1ラインしかなく、キャラクターが左右(もしくは上下)にしか動けないタイプのゲームを指す。非常に窮屈なフィールドで、どのようなルールにすればゲームが成り立つかを考えることは、新しいゲームアイデアを考える際に役立つ、こともある。

既存の2次元ゲームを1次元ゲームに落とし込むことで、元のゲームの基本ルールだけを際立たせた、よりプリミティブなゲームを作るという方法もある。この前はパックマンの1次元ゲーム化をやってみた。

左右にあるワープトンネルを使ってモンスターを避ける、パワーエサを食べてイジケモンスターに反撃する、すべてのエサを食べると次の面へ行く(シームレスに移行するパックマンCE方式)、というルールだけでゲームにした。左右にしか動けないことを利用して、ボタンを押すと移動方向が反転する、1ボタンゲーム化もした。パックマンらしさをミニマムに表現できたのでは、と思う。

こういった1次元ゲームを探したかったらポケコンゲームを見ると良い。ポケコンとはポケットコンピュータの略で、小型の液晶ディスプレイとキーボードから成る、いにしえの持ち運べるコンピュータのことだ。

ポケコンのディスプレイは、電卓のような1行のテキストのみ表示できるものが主流だった。なのでポケコンゲームは必然的に1次元ゲームとなる。複数行表示できるポケコンや、1行に縦複数ドットのグラフィックスが表示できるポケコンは2次元ゲームも作れたが、それは例外としよう。

ポケコン版1次元パックマンはいろいろある。

シャープのポケコンPC-1245用パックマン。これは今回作ったのと同じようなルール。ノーマルエサは無いけど。

カシオのポケコンPB-100用パックマン、の移植版。パワーエサが爆発する変わり種。

ナムコのゲームだと、他にはメトロクロスとかも1次元ゲーム化できそう。

. / ___ o

のような画面を作って、.がプレイヤー、/がジャンプ台、_がスリップゾーン、oがジャンボ缶、のような1ラインだけメトロクロスを模擬すれば良い。ジャンプ中のプレイヤーは'で。

こういったアーケードゲーム無理やり1次元ゲーム化、昔のポケコンでいろいろやられてそうだけど、なにぶんポケコン自体がかなり昔のハードなので、今のネットで情報を探すのが難しい。この辺が見つかればミニゲームのアイデア元としてとても良さそうなのだが。

そういえば前にフォゾンの1次元ゲーム化もしたな。

これはかなり無理があった。あと完成形が同時表示されていることが重要なので、1行での表示で完結させるのは難しそう。

今まで作ったほかのミニゲームの中にも、実質1次元ゲームのものがいくつかある。

グレネードを投げて地面に穴をあけて戦車の弾をよけるゲーム。これはPC-1500用として掲載されていたゲームが元ネタ。グレネードが画面上方向に飛ぶ演出をカットすれば1次元ゲームになる。

R-TYPE波動砲だけ抜き出したもの。BEAM表示相当の情報をなんとか1行に押し込めれば1次元ゲームになる。

これは極めて分かりにくいと思うのだが、ディグダグで岩の下からプーカを太らせながら上に掘り進み、まとめて岩でつぶす場面を1次元ゲームにしたものなのだ。本当に分かりにくい。

たけのこと竹の表現を1行に収まるように工夫すれば、これも1次元ゲームになるな。

これも薙ぎ払い表現を工夫すればベースのルールは1次元だ。

1次元のフィールドでできるゲームを考えること、既存の2次元ゲームの1次元化をすること、ポケコンゲームのアイデアを参考にすること、この辺は制約に基づき新たなミニゲームを考える方法としてアリかもしれない。

ポケコンの1行液晶ディスプレイもそうだけど、1次元ゲームという特性を活かしたハードウェアを考えることもできる。

Line WobblerはLEDチューブを使った1行どころか1ドットの1次元ゲームを実現している。こういった専用ハードウェアを使った1次元ゲームを考えるのも面白いね。

C言語を使ったPlaydate向けゲーム開発(エア実装編)

screenshot

crisp-game-lib-portableのポータビリティを検証するために、Playdate用実装を作ることにした。実機を持ってないのに。

Playdateは黄色い筐体と横についたクランクがキュートなコンパクトなゲーム機だ。日本からもプレオーダーできるが今から頼んでも届くのは2023年となかなか手に入らない。でもSDKはあるので、シミュレータを使った開発はできる。

Arduinoではないデバイスでもcrisp-game-lib-portableが動くかどうかを確かめるにはちょうど良い。

まずC言語でPlaydate用ゲームを作る環境を整える。オフィシャルページにやり方が載っているが、Visual Studio入れて、 GNU Arm Embedded Toolchain compiler入れて、CMake入れてと結構面倒。以下のページの情報が役に立つ。

SDKの中にあるサンプルなどを参考にCMakeLists.txtを作ってVisual Studio用のソリューションファイルを作る必要がある。あとは.slnファイルを起動すればVisual Studio上でコードが書ける。構成マネージャーを見るとZERO_CHECKというよく分からんプロジェクトができているが、それはビルドから外して、それじゃない方をスタートアッププロジェクトに設定してみたが、これが正解かは分からない。

環境ができたらコードを書く。今回書いたコードは以下。

コードの作りとしては、イベントハンドラにPlaydate用の全てのAPIが生えたポインタが渡ってくるので、そこからさまざまな機能を呼び出す。

APIリファレンスに関数は書いてあるが、いくつかの機能はLua用のドキュメントを読んでおかないと分かりにくい点も多い。

FPSplaydate->display->setRefreshRateで指定できるが、どうも上限が50のようだ。ぜひ60にしたいのだが、性能上の制約だろうか。

グラフィックライブラリ用の機能はplaydate->graphics以下に一通りそろっているし、ビットマップキャラクタもLCDBitmapを使えば簡単に扱える。playdate->graphics->pushContextでビットマップを指定すれば任意のグラフィックスをビットマップに書き込める。

Playdateは白黒画面だが、それを補うために8x8のパターンで矩形などを塗りつぶす機能がある。そのためにLCDPatternを使うのだが……なんの説明もない。どうも16個あるuint8_tの前半8つが白黒のパターン、後半8つがマスクパターンのように思える。今回はこれを使ってRGBから無理やりパターンを作るロジックを作った。

音回りはよく分かってないのだが、playdate->sound->synth->newSynthPDSynthインスタンスが取れれば、playdate->sound->synth->playNoteで任意の周波数の音を、期間と開始時間を指定して鳴らせる。ちゃんとオーディオタイマーがあってスケジューリングしてくれるのは助かる。

コードが書ければVisual Studio上で「ローカルWindowsデバッガー」ボタンを押すだけでシミュレータが立ち上がってデバッグできる。この辺はとても楽で良い。ビルドもそれほど時間かからない。

次は実機向けのビルドだ。cmakeにArmターゲット用のオプションを付けてビルドすれば、実機に転送可能なバイナリができる。

ここに一つ罠があって、実機用ビルドではsprintftimeなどいくつかの関数が使えない。なのでそれら関数はPlaydateのAPIで補わないといけない。しょうがないので今回はCMakeLists.txtPlaydate実装向け定数を定義してライブラリ本体の実装を変えた。こうしてライブラリ本体は機種依存しない、という建前が崩れていく。まあブラウザ向けにEMSCRIPTEN_KEEPALIVEが必要な時点でそれは崩れてはいたのだが。

次は実機上でのテストだが……もちろんできてない。実機が無いから。何か実機固有の問題を踏んだり、パフォーマンス上の問題が出たりしそうだよなあ。

とりあえずシミュレータを使った開発の範囲だと、Visual Studioとシームレスに連携してくれることもあり開発体験は良い。ドキュメントはまあまあ充実しているが、LuaとCの間で情報が分散していたりして分かりにくい点もある。音回りはだいぶリッチな機能がありそうなのだが、全貌がよく分からない。だれかにWeb Audio APIとの対比で説明して欲しい。

あとはWindows上のシミュレータと実機の挙動の差が少ないのであれば全体としてよくできた開発環境であると思うのだが、そこが分からんので総合的な評価はできないね。その辺が書いてある記事とかネット上にあるかなあ。ちょっと検索した範囲だと、実機があまり出回ってないせいもあって、私と同じエア実装勢が多いような気がする。

移植性の高いミニゲームライブラリを目指すぞ

PyBadge crisp-game-lib-portable screenshot

ミニデバイス向けミニゲームライブラリcrisp-game-lib-portableがM5StickC PLUSに加えてAdafruit PyBadgeでも動くようになった!2つのデバイスで動くので移植性が高い!完成!

とは言えないのは分かっている。そもそもM5StickC PLUSもPyBadgeも同じ Arduino IDEでビルドできるし、画面周りも LovyanGFXが両デバイスに対応しているので、移植自体難しくないんだよね。せめてArduino IDEを使わないほかのデバイスで……とか考え始めるとマイコンボード沼に片足突っ込みそうで怖い。実機は無くともPlaydate SDKに移植・ビルドできるか、くらいはやってみても面白いかも。

crisp-game-lib-portableはライブラリ本体ゲームのコードはブラウザを含むすべてのデバイス向けで共通、デバイス向けには最小限の個別コードを書けば対応できる、というのを目指している。M5StickCPlus向けはcglpM5StickCPlus.ino、PyBadge向けはcglpPyBadge.inoがそのコードに当たる。

バイス個別コードで書かないといけない処理は、

  • バイスの初期化処理(Arduinoならsetup())とそこからのinitGame()の呼び出し
  • フレームの更新処理(Arduinoならloop())とそこからのsetButtonState()呼び出しによるボタン状態の通知とupdateFrame()の呼び出し
  • machineDependent.hで定義された描画や音周りの処理

だけ。なので両デバイスとも必要な実装はC言語で250行程度だ。

音回りの実装はmd_playTone(float freq, float duration, float when)で特定の周波数を、特定の期間、特定の開始時間で鳴らすことを要求していて、これが一番面倒かもしれない。PyBadgeみたいなブザー音量をanalogWrite()で設定できるだけ、みたいなデバイスだと、音のタイミング管理をしつつ、矩形波を自力で生成しないといけない。まあ面倒だったら全部Not Implementedで音が出ないようにしてしまえばいいんだけど。

md_drawCharacter(unsigned char grid[CHARACTER_HEIGHT][CHARACTER_WIDTH][3], float x, float y, int hash)でドット絵を表示して、もちょっと面倒かも。最後にハッシュ値が付いているのは、毎回ドット絵のパターン定義をパース・描画するのではなくて、ハッシュ値でキャッシュしておいてそれを使ってね、という要求なので、そのロジックを書かないといかん。LovyanGFXがあるならLGFX_Spriteハッシュ値をペアで保存しておいて、それを取り出してpushSprite()するだけなので比較的簡単。

どちらかというと各デバイス固有の開発環境を整備するほうが面倒だよね。Arduino IDEがかなり広範なマイコンボードをサポートしてくれているのはとてもありがたいが、Arduino IDE自体の使い勝手がいまいちな気がする。ビルドに必要なファイル一式が同一ディレクトリに入っていることを要求するところとか、ビルドが遅いところとか。ビルドスピードはCcacheの導入か、PlatformIO IDEへの乗り換えで改善されるようだ。

こういった移植性を考えながらコードを書くことは、いろんなデバイスを相手にしたライブラリでないとできないことなので、なかなか楽しい経験ではある。あまたあるマイコンボードに対して、Arduino IDEなどの共通な開発環境、Adafruit ArcadaやLovyanGFXなどの多デバイス対応ライブラリを駆使しつつ独自のゲームライブラリを作るのは、PCやスマホをターゲットとしたゲームライブラリとはまた違った面白さがあり、おススメします!

いや、いにしえの教えを思い出したぞ!ライブラリを作るなゲームを作れ!やっぱりおススメしません!