LIFF + TIC-80

こんにちは、LINE FukuokaのAndroidエンジニアでLINEのメッセンジャーアプリの開発を担当している吉田清亮 (@seisuke)です。この記事は LINE Advent Calendar 2018 の1日目の記事です。

先月開催された社内Hackathonで、Fantasy Consoleと言われる聞きなれないジャンルのプロダクトであるTIC-80をLIFFで動かしてみました。
せっかく得た知識などを共有できればと思い、この記事を書くことにしました。

LINE Fukuokaでは毎年Hackathonを開催しており(去年のレポート)、何人かのプレゼンターが開発企画の提案を行い、それに興味をもった4,5人のチームで2日間開発を行うのが、基本の形となります。その際に普段自分の業務ではあまり縁のない技術を使うチームも少なくないです。 自分はTIC-80を、WebAssemblyを利用することによって、LIFF の中で動作させるという企画を行い、開発することになりました。

TIC-80、そしてFantasy Consoleとは

TIC-80 はC言語で作られたFantasy Consoleというプロダクトになります。Fantasy Consoleは日本語に訳すなら「架空のゲーム機」となります。最近も pyxel というpythonで作られた物が話題になりました。
まず、なぜ架空という言葉を使うのでしょうか?この場合のリアルに当たるものはMSXやMS-DOSなどのシングルタスクOSを搭載したホームコンピュータになります。自分とは世代が少しずれるのですが、こういったコンピュータでBASICなどを使いゲームを作ることによって、プログラムの世界に入ったという人も多いのではないでしょうか?
Fantasy Consoleは実在のコンピュータをエミュレートすることは目的ではありません。ゲームを作るということに集中して取り組めるための”環境”を用意しようという目的を持って開発されています。そのため昔のコンピュータのような解像度・表示色数・音源数などの制約された環境を用意し、その制約に適したAPI、プログラムするためのコードエディター、ドット絵作成ツール、音源作成ツールなどが提供されています。しかもゲームを遊ぶ環境と作る環境が合わせて一つとして提供されています。そのため自分が遊んでいるゲームがどのようなコードや素材で作られているか、その場で簡単に確認することができるのです。
TIC-80では通常Luaを使ってプログラムを組みますが、JavaScriptやPythonなどの複数言語で開発を行うこともできます。

TIC-80の仕様の一部を抜粋すると以下のように非常にミニマムなスペックとなっています。

  • 画面サイズは240×136ピクセル
  • スプライトは16色8×8ピクセルの前面スプライトと背景スプライトをそれぞれ256個
  • 音源は4チャンネル 16個の波形を組み合わせる
  • コードサイズは64KBまで

この仕様上cartと呼ばれるゲームそのもののサイズも非常に小さく、cartのシュアなども簡単に行うことができます。
そこでLIFF上でゲームをプレイでき、なおかつ自分で作ったcartをLINEの友だちなどに簡単にプレイしてもらえるという仕組みは、Fantasy Consoleの目的と相性がいいのでないかと思い、Hackathonの題材としました。

Hackathonで作ったサービスの概要

Sinatraで作ったシンプルなウェブアプリをHerokuで運用しました。
TIC-80のコンソールからcartをuploadを行えます。uploadが完了するとトーク画面にdownloadするURLが表示され、それを友人にシェアすれば、友人はLINEのLIFF上でゲームをプレイすることができます。

LIFFでTIC-80を動かす工夫

LIFFはLINEのメッセンジャーアプリ内で動作するウェブアプリのプラットフォームで、トーク画面上でLINEのユーザーIDなどを連携することができます。
TIC-80はもともとWebAssemblyでビルドできるようになっているため、一応ブラウザ上で動かすことは元からできています。
しかし携帯のブラウザからプレイすることはあまり考慮されておらず、なおかつ本物のゲームパッドやキーボードを接続してプレイすることが期待されています。

そこでLIFFで快適にTIC-80を操作するため、いくつか注意することがあります。

画面の幅

WebAssemblyでは起動時に指定したCanvasに描画が行われますが、このCanvasの大きさは元のバイナリの描画サイズが自動で適用されるようです。
TIC-80の場合は設定でドット一つの大きさを変えられるので、横幅を512px(240×2 + 左右マージン16×2)で描画されるように設定を行い、viewportを以下のように512pxに設定して描画するようにしました。

<meta name="viewport" content="width=512, user-scalable=0">

本当は元のTIC-80からマージンの描画自体を取り除き、全ての描画設定をCSSでするほうが望ましいと思います。

ゲームパッドの実装

TIC-80はバーチャルゲームパッドの機能を持ってるようなのですが、WebAssemblyでは動作しないように設定されています。
その部分は深入りせずに、JavaScriptでバーチャルゲームパッドを実装することによって、LIFFからゲームをプレイできるようにしました。

window.dispatchEvent(new KeyboardEvent(name,{'keyCode':code}));

このように通常のKeyboardEventを実行すれば、すんなりとTIC-80にキー入力が伝わります。
ただゲームの場合、長押し同時押しなどにしっかり対応しなければいけないため、その部分の実装は少し工夫がいります。
実際ゲームを快適にプレイするためには斜め押しなどが必要になるのですが、それについては今回は諦めることにしました。

キーボードからの入力

TIC-80では、多くのオープンソースなマルチプラットフォームのゲームプログラムのようにSDL2を利用してキーボード入力を処理しています。前項のゲームパッドも同様です。

TIC-80でのキーボード入力は別フレームでキーボードの押し下げ、押し上げを取得すること前提でコードが書かれています。
しかし、iPhoneなどのバーチャルキーボードは押し下げ、押し上げが一瞬で発生するため、キーボードの入力を正常に取得することできていませんでした。
押し下げ、押し上げがたまたまフレームを跨いだ時のみしか取得できないのです。
この部分はTIC-80自体に修正を加えて解決しました。

スペースキーの対応

スペースキーの入力があるとLIFF自体がスクロールしてしまうため、JavaScriptでWindowへの入力を止める必要があります。

WebAssemblyとJavaScriptの連携

WebAsseblyではCとJavaScriptで相互に関数を実行して連携することができます。
https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html

今回はCからJavaScriptを呼ぶだけで十分ですので、Cの中にInline JavaScriptを書くことができる、EM_JSを使いました。
LIFFのウェブアプリ上でグローバルなJavaScript関数を用意しておけば、簡単にC言語からそれを呼ぶことができます。

cartをアップロードする機能はTIC−80のコマンドで実行しますが、実際の中身はJavaScriptからHackathonで作成したサーバーAPIを叩いているだけです。通常のXMLHttpRequestを使い、APIは成功時にアップロードしたゲームをダウンロードするURLを返します。
callback関数でLIFFの機能を使いトーク上にメッセージを表示します。
callback関数を呼ぶところまではWebAssemblyのInline JavaScriptとして実装して、LIFFのメッセージ表示部分はウェブアプリ部分に実装しています。

今後の展望

2日間という限られた時間のため、最低限の機能をなんとか実装するという状況でHackathonを終えました。
ただいろいろ手を加えていけば、面白いものになるかもしれないという手応えは感じることができました。

今回実現できませんでしたが、LINEのユーザーIDを利用した得点のアップロード機能や、ランキング機能の実現などもアイデアとして存在しました。LIFFで取得したLINEのユーザーIDをTIC-80の起動時にコマンドライン引数として渡すことができます。あとはTIC-80のAPIとして提供しておけば、ゲーム作成者が必要なパラメーターを渡して実行すれば、サーバー側にランキングデータとして蓄積されるというの物です。

また個人的にFantasy Consoleは子供がプログラミングに興味を持ち、Scratchなどのビジュアルプログラミングを体験した後のステップとして適していると思っています。そのためには日本語対応や、機能をシンプルにするなどの対応が必要になります。
実際TIC-80に日本語ドットフォントを追加してみたりなどの機能追加を試していますが、もともとのUIの特性上ある程度の機能は実現できても、後付けではなかなか難しい部分も多いです。
そもそもHackathonの企画を考える時、Kotlin/NativeとWebAssemblyで何か作れないかと調査しているうちにTIC-80に行きついたという経緯がもあるため、Kotlin/Nativeで自分の理想のFantasy Consoleにチャレンジしてみるのも面白いと考えています。

最後に

明日は Taro Takaguchi さんによる「統計指標の信頼区間を評価する Delta method とその応用(論文紹介)」です。お楽しみに!

Related Post