2014年8月5日火曜日

福島GameJam 2014宮城・仙台サテライト会場に参加しました

8月2、3日に開催された東北ITコンセプト 福島GameJam 2014に参加してきました。

東日本大震災からの福島の復興を願い、2011年から開催されてきた福島GameJamは、今回、東北各地からの参加者とその他の地域の方たちとの交流を促進し、産業の発展の基盤の構築を目指して開催されました。
今回は、仙台ではじめて「宮城・仙台サテライト会場」が設置されたので、そちらに参加してきました。

宮城・仙台サテライト会場は、仙台の人には有名な仙台模型の数軒手前。今度オープンするというコワーキングスペースを、オープン前に特別にお借りすることができたとか。おしゃれすぎて大変です。壁がでかい黒板! ころがれるスペース! なんかのカウンター! こんなスペースでハッカソンやったことないよ状態。





参加者募集開始が開催の直前だった割には参加者も集まり、学生4人+社会人2人となりました。スタッフは、過去の福島GameJamの参加者3人、そして国際ゲーム開発者協会代表の小野憲史さん。ああ、この中では、ぼくが最年長ですね。


ネット中継で開会式を見ていると、今回のテーマは「continue」と発表! 早速企画会議に入りました。
まず、「continue」という言葉から連想されるものをみんなで考えて付箋紙に貼り出しました。


それを元に、一人一人でゲームの企画を考え、昼食を食べながらプレゼン大会。

ぼくが考えたのは、次のようなゲーム。

七夕が近づく仙台の街。
しかし、激しい災害により、人々が夢を失ってしまい、夢の結晶だった天の川のカササギが砕け散ってしまった。
このままでは、七夕の再会ができない織姫と夏彦が悲しみに沈み、世界が闇に閉ざされてしまう。
仙台の街に飛び散った夢のカケラを集めてカササギを復活させよう! そして、世界に夢を届けよう! 人々の心に夢のアカリがともるように。


ゲームは、ロードランナーやスーパーマリオのような2Dのアクションゲーム。
夢のカケラは、小さいカケラの状態では、どんどん崩壊してしまうので、崩壊するよりも早く集め続ける必要がある。
集めた夢のカケラがある程度の量を越えると、崩壊しなくなり、カササギが復活する。

このゲームを説明するのに、「ミンキーモモ」を例に挙げたけど、知っている人がいなかったよ。しょぼーん。みんな若い。
「ツバサ-RESERVoir CHRoNiCLE」というべきだったのだろうか?

あ、青森県立美術館では、9月7日まで「美少女の美術史」展を開催しています。ミンキーモモも展示されているよ!

みんなで自分の作品以外に投票した結果、東北ずん子ちゃんが飛んでくるずんだ餅を撃ち落としながら進むゲームとウシの反芻をテーマにしたゲームの2つが残りました。
決着がつかないので、ためしに2つ作ればいいんじゃないか?ということになり、開発に入りました。

ウシの反芻チームは、ぼくと下山樹くんと馬目ゆきのりさん。
まず、ゲームの画面遷移を考え、具体化していきました。
制作ツールは3人が使えるenchant.jsを採用。
制作パートを分担して、制作に入りました。
ぼくは主にエサを与える画面の制作。
Illustratorで画面のパーツをサクサク作っていく。
ここまでは全く問題なかったのですが、大豆、塩、ビール、...といったアイコンを入れようとして、どう描いたらいいんだ状態でかなり困った。
ぼくはスキル的にはWebアプリ開発者であって、デザイナーではないということで…。

なお、今回、ウシやトウモロコシなどのイラストは、運営スタッフの菅浪伊吹さんに助けていただきました。ありがとうございます。


画面のプロトタイプができて、発表会を実施して、1日目は終了。


 仙台会場は夜間がなく、再開は翌朝となりました。
ぼくはもう40代後半なので、正直、徹夜で開発すると、翌日はほとんど役に立たない。
今回のように夜間がしっかり休めると、最後まで最適な体調で開発できて、大変快適でした。

2日目は、ほとんどのメンバーがオフィシャルな開始時間前に集合して、開発を再開。
残ったイラストの制作や、コードのマージや、プレゼン資料を作りながら、エサとウシの胃を使用するパターンをゲーム中でどう評価するかというロジックを開発しました。



そうこうするうちに、おおよそ動作するようになったので、iPadで試遊環境を準備しました。iOSの[設定]から、[一般]→[アクセシビリティ]→[アクセスガイド]で、ホームボタンや画面のタッチできる範囲を制限できます。これを活用すると、来場者にデモをする環境が簡単に作れます。



見学者に試遊していただき、インターフェイスのわかりにくいところなど、意見を反映させていきました。




そして、開発終了時刻。残念ながら、エンディングを付けるところまでいかなかったけれど、以下で公開中です。

http://157.7.235.138/dokuwiki/doku.php?id=sendai2

福島GameJam 2014のTweetは以下にまとまっています。

https://twitter.com/fgj13_bot/favorites

仙台駅近くで、家族と打ち上げを兼ねた夕食を食べながら、2011年5月に開催された「"9leap" Game Programming Camp@仙台」を思い出しました。

2013年12月7日土曜日

[AWAC2013]今年一番ヒットだったツールは「RICOH THETA」

いきなり世界が真っ白になった青森の2013年12月7日。Aomori Web Adevent Calendar 2013 7日目のこくぼあつしです。

今年一番ヒットだったツールは、RICOHの全天球カメラTHETA(シータ)です。
いわゆるパノラマ写真を撮影できるカメラです。



このカメラのすごいところは、シャッターを1回切るだけで全周囲撮影できるところ。これがなんとおよそ4万円。

欠点は、画素数が3584x1792と少ないことと、暗所でのノイズが多いこと。しかし、それを補って余りあるお手軽さ。

シャッターを切って急いでぐるりんと回って撮影する必要もなければ、パシャパシャと分割して撮影したものをパノラマ合成ソフト(スティッチングソフト)でつなぐ必要もありません。
その秘密は、2つの超広角の魚眼レンズ。これが前後に2つついていて、本当に1シャッターで全周撮影できます。そして、カメラの中で、正距円筒図法(Equirectangular)の画像に合成してくれます。



 今まで、このような写真を撮影しようとすると、ある程度広角なレンズ、カメラをのせて回転させる雲台といった機材を使って、ちょっとずつ角度を変えて分割撮影し、それをHuginなどのパノラマ合成ソフトで合成していました。また、表示するにはパノラマ画像表示ソフトが必要で、よく知られた実例はQuickTime VRです。

たとえば、以下のような本にその方法が解説されています。


あるいは、Googleストリートビューのように、全天球が1シャッターで撮影できるように、カメラを何台も組み合わせたシステムが必要でした。

RICOHの全天球カメラTHETAは、これらをシャッターを1回切るだけでできるようにしてくれました。

最初に書いたように、画素数は3584x1792。もしも普通のカメラで横1周ぐるりんと8分割して撮影したとすると、1ショットあたりの横幅は3584/8=448画素に相当します。かなり粗い画像だと言えるでしょう。

また、暗いところで撮影すると、ノイズが目立ちます。

しかし、なんと言ってもお手軽です。

撮影するには直接シャッターボタンを押してもいいし、iPhoneやAndroid用の専用アプリなどからリモート撮影も可能です。

THETAは無線LANの親機になることができます。iPhoneやAndroidから、THETAに無線でつなぎ、専用アプリを起動すると、リモートで撮影したり、カメラ内の画像を取り込むことができ、全天球画像を楽しめます。また、PCにUSB接続すれば、普通のカメラに見え、正距円筒図法の画像を取り出すことができます(Macの場合、iPhotoなどを経由)。

また、Webで公開するための手段も用意されています。
必要なのは、Facebookアカウントと専用アプリ。専用アプリに画像を取り込んで、Facebookアカウントでtheta360.comにログインします。すると、画像を投稿して共有することができます。


この画像はPCやスマホなどから、そのまま閲覧することができます。
また、FacebookやTwitter、Tumblrに投稿することもできます。

現状、theta360.comのサイトでは、サーバーサイドにはRuby on Railsを使っているっぽく見えます。そして、RICOH THETAで撮影された正距円筒図法画像をAmazon S3に保存しているようです(似たようなシステムの構築方法は、栗田由菜、『RailsとiPhoneではじめるアプリケーション開発』、インプレスジャパン、2013年あたりに)

その画像をPCなどからはFlashを使って見ることができるようになっています。
また、スマホなどから見る場合には、画像を立方体に投影し、CSS Transforms Module Level 1を用いて、表示しているようです。

あまりにおもしろいので、WebGLを使って正距円筒図法のパノラマ画像を表示するアプリTheta Viewerを作ってみました。jQueryのプラグインなので、Web屋さんには簡単に使えると思います。


 ちなみに今日までのAomori Web Adevent Calendar 2013は、以下のみなさんでした。


明日は、すどうまさゆきさん!

2013年8月22日木曜日

福島GameJam 2013に参加しました

2013年8月3、4日に開催された東北ITコンセプト 福島GameJam2013に参加してきた。 これは、プロや若い人たちが一緒になって即席のチームで30時間でゲームを開発するイベントだ。

東日本大震災では、津波により大きな被害が東日本沿岸に発生し、特に福島県では原発事故が起こり復興を困難にした。 ITで復興を支援することを目的にはじまった福島GameJamは、今年3年目をむかえ、さまざまな広がりを見せている。

昨年度は地元(南相馬)の高校生が参加した。「女子高生とゲームが作れるのは、福島GameJamだけ!」みたいな。そして、今年度はそれに加えてITの研修を受講した地元の技術者も参加した。更に、当日に開発見学や制作体験ワークショップも開催された。また、福島GameJamがきっかけとなり、昨年度から郡山でFUSEというゲーム開発イベントが立ち上がり、毎月のように開催されている。仙台でもCORONAというゲーム開発イベントが立ち上がっている。

今回は、本会場として南相馬に加えて郡山も加わり、サテライト会場も国内各地に海外の台湾、コロンビア、チリなど多数になり、参加者も500人を越える大きなイベントになった。また、参加者向けに事前にゲーム開発ツールのセミナーも開催された。即興のチームで開発手法をゼロから相談してゲームを作るのもいいけれど、それは大変でもあるので、こういう事前セミナーがあると、開発しやすくなると思う。ぼくは青森に住んでいるので、参加しなかったけれど。

今回、ぼくは、思い出深い南相馬会場に参加した。南相馬会場は、これまでと同じ、市役所の向かいの「ゆめはっと」という施設だった。これまでは、近くに買い物ができる場所がなかったため、30時間過ごすためにさまざまなものを持ち込む必要があり、荷物が増える傾向があった。今年からは、近くにコンビニも開店したおかげで、参加しやすくなった。

現地でチーム分けとテーマが発表となり、開発に入った。南相馬のチーム7「Kine Kine 7」。1回目でも一緒だった山口さんや、学生時代に読んでいた「ゲーム批評」の小野さんほか、なかなか濃いメンバーだった。Kinectを持ち込んだ方がいて、テーマが「Jump」だったので、Kinectでジャンプするゲームを作ることになった。

悪のフランチャイズ菓子チェーンが攻めてきて、さらわれた姫が赤ベコに姿を変えられてしまった。天空に囚われた姫を救いに行くというゲームだ。

開発ツールは、Unity。Unityは使ったことがなかったので、その場でオライリーの『Unityによる3Dゲーム開発入門』のPDFをネットで購入。と言っても、ぼくは実際にはUnityは触らなかった。今回は(前回に引き続き今回も?)、プログラマ系の人ばっかりだったので、IGDA東北の菅浪さんとぼく(授業でコンピュータグラフィックスの制作も教えていたり…)はグラフィック素材を作ることにした。

メイングラフィックスは菅浪さんに担当していただき、ぼくはもっぱら子供たちの描いた絵を、Kinectで操作する人形のモデルにはるためのテクスチャーに変換するプログラムや「ゆめはっと」の3D CGを作成した。

福島GameJamでは伝統的に、地元の子供たちが描いてくれた絵を、素材として使うように推奨されている。今回、これらの絵は、WebのAPIから取得できるようになった。
そこで、まず、shellスクリプトで、curlを使ってすべての画像を取得するプログラムを作成した。

子供たちは円と長方形の枠線が描かれた型紙の中に顔と胴体を描いている。また、腕のパーツもある。

福島GameJamのサイトより

これらを切り抜いて別パーツにするプログラムをProcessingで作成した。Processingは、Javaをベースとしたオープンソースのアーティスト向けのプログラミング環境で、短いコードでインタラクティブなアプリや画像処理ソフトを作ることができる。ゲームを作るのにも向いている。青森大学では、ソフトウェア情報学部の1年生のプログラミングの入門の授業で利用しているが、初心者でもゲームが作れるようになったりする。

切り抜いた画像のうち、顔の部分は加工が必要だった。人形のモデルの顔の部分に相当するのは球形だ。円の中に描かれた顔をテクスチャーとしてはるため、画像の投影法を正射影から正距円筒図法に変換する必要があった。そこで、変換式を紙に書いて計算して、プログラムをProcessingで作成した。座標変換はまじめにやっているが、画像のピクセル補間はかなり適当にした。

「ゆめはっと」の3D CGは、ロケを行なって写真を撮影し、ネットで「ゆめはっと」の図面を探した。これらを元に、3D CGツールでモデリングし、写真をテクスチャーとして使用した。

一方、Unityでゲームのプログラムを書いていたメンバーは苦戦していたようだ。課題となったのはバージョン管理で、今回はDropboxを使っていた(Unityにはアセットサーバーというバージョン管理ツールがある。こちらを使うと以下の問題は発生しないのかもしれない)。Dropboxの場合、画像などのバイナリデータの共有には向いている。また、一応、履歴も取ってくれる。でも、差分やマージ機能があるわけではないので、プログラムなどを共有するのには必ずしも向いていない。また、Unityとの相性もあまりよくなく、更新していない3Dオブジェクトが上書きされたりして、作業が煩雑になっていたように見えた。
それでも、子供たちが遊びにくる、2日目午前中までにはなんとか動くようになった。そして、子供たちの反応を見て、ゲームを改良していく。

また、作品制作ルールになるべく適合するように、チューニングしていく。「会場周辺の情景」を取り入れるという項目があったので、近隣のお菓子屋さん(お菓子がテーマのゲームを作成したので)を背景に使用しようと、撮影に出かけた。日曜日だったが、ほとんどのお菓子屋さんが営業していなかった。地方都市ではありがちな光景だが、震災の影響もあるのかもしれない。撮影中に大きな地震が発生し、電信柱がグラグラ揺れる事態に遭遇した。幸い、ぼくにも会場にも大きな影響はなく、ゲーム制作は続けられた。

そうして完成した作品が「福島Game de Watch〜赤べこ救出編」。当初の構想のすべてが反映されたわけではないが、Windows版のバイナリをダウンロードしてKinectを接続すると、プレイすることができる。また、Web版(現在のUnityのバージョンだとMacだと動かない不具合があるっぽい)もあるし、キーボードでも操作できる。

「福島Game de Watch〜赤べこ救出編」
ぼくは、スキルとしてはゲーム開発者というよりはWeb開発者やサーバ屋さんだ。 これまでの福島GameJamでは、ゲーム・プログラミングという、ふだんの仕事とはかなり異なるチャレンジングなタスクを担当して、エキサイトする体験だった。 今回は、シェル・スクリプトを書いたり、今年から担当している「画像処理」の授業で教えた画像処理プログラミング、研究室でやっている研究の一つである街の景観の3D CG制作、説明資料の作成など、ふだんやっている仕事に近いものを担当した。 「ああ、なんか、いつもと同じような仕事をしているよ」と思った。 日常感が満載だったが、仕事はスムーズにできた。 ゲーム開発者の人は、GameJamに参加すると、こんな感じだったのだろうか。

それから、プログラマが多い場合の即興チームでの共同作業については、いろいろ考えさせられた。昨年度の福島GameJamでも全員がプログラマというチームで、JavaScriptで書かれたenchant.jsのコードをDropboxで共有していたが、今回同様にコードのバージョン管理とマージが煩雑になった。 たぶん、このような作業には、gitなど(Unityならアセットサーバーなども)のバージョン管理ツールを使った方がいいのだろう。 たとえば、Pro Gitの「Chapter5 Git での分散作業」で紹介されている「中央集権型のワークフロー」を用いて、自分の作業はトピックブランチを作成して行ない(masterで細かい作業をしない)、ひとまとまりの作業が完了したらmasterブランチにマージするとか。

また、今やほとんどのゲーム開発ツールはオブジェクト指向言語を使っていると思われるが、そのクラスの継承や合成の機能(JavaScriptの場合は相当する方法)を使って、全体で共有するべきコードと自分で個別にいじるコードを分離するという方法もあると思う。

とは言え、ふだんから一緒に仕事をしていれば、開発ツールや開発ルールの共有は簡単だが、即興のチームで行なうのはなかなか難しいかもしれない。

でも、習得のしきいが高かったgitも、最近はSourceTreeなどのクライアントも出てきたので、もっとみんな使ってもいいような気がする。

福島GameJamで学んだことは、いろいろ学生の指導にも参考にしている。なるべく上級者の開発ではバージョン管理システムを使うようにしたり、共同開発ではオブジェクト指向言語の機能を活用して自分がいじる部分を切り分けるなどの工夫をするようにしている。

2013年7月30日火曜日

WindowsのHuginでPTBatcherGUI.exeの起動エラーの対処方法

Windows版のHuginでは、スティッチングを実行しようとすると、PTBatcherGUI.exeの起動に失敗することがある。 PTBatcherGUI.exeを起動すると、複数起動できないように起動していることを識別するためのファイルを作り、これは終了時に削除される。 しかし、何らかの原因で終了時にこのファイルが削除されないと、次回から起動できなくなる。

ファイルはWindows XPの場合、ドライブ:\Documents and Settings\ユーザー名\Application Data\.ptbt0や.ptbt1。
Windows 7の場合、ドライブ:\Users\ユーザー名\AppData\Roaming\.ptbt0や.ptbt1。

これらは隠しフォルダに入っていたりするので、隠しフォルダなどをフォルダオプションで見えるようにしないと見ることができない。

バッチファイルで削除するには、以下の内容のバッチファイルを作成して実行するとうまくいった(無保証。ご自分の責任でご利用ください)。

Windows XP用
---
@echo off
set AppData="%USERPROFILE%\Application Data"
if exist %AppData%\.ptbt0 (del %AppData%\.ptbt0)
if exist %AppData%\.ptbt1 (del %AppData%\.ptbt1)
---

Windows 7用
---
@echo off
set AppData="%USERPROFILE%\AppData\Roaming"
if exist %AppData%\.ptbt0 (del %AppData%\.ptbt0)
if exist %AppData%\.ptbt1 (del %AppData%\.ptbt1)
---

追記

Mac OS Xの場合は、~/Library/Preferences/.ptbt0や.ptbt1

2012年8月11日土曜日

福島GameJam in 南相馬2012の感想

8/4、5に開催された東北ITコンセプト福島GameJam in 南相馬 2012に参加してきた。30時間で即興のチームでゲームを作るという催しだ。

前回、技術的な話を書いたので、今回は全体的な感想を。

福島GameJamは昨年に引き続き2回目の開催。今回は、高校生も含む地元の若い人の姿も多く、ITによる震災復興という目標に少しは近づけたかもしれない。

ぼくのチームは8名で、全員がプログラマという無茶な構成。内訳は、ある程度の経験者4名、若い人4名。

SEGAの石畑さんがチームにいたが、ぼくは開発中はバーチャロン・シリーズのプログラマの人だと気づかなかった。というか、開発で頭がいっぱいだった。バーチャロンはかなり夢中になったゲームだったので、緊張しかねないので、開発中は気づかなくてよかったかもしれない。

それぞれのメンバーの経験したことがある開発環境はバラバラだった。若い人たちはC(やC++)を習っているところだが、さすがにこれでゲームを作り始めると30時間では終わらない予感。話し合った結果、enchant.jsで開発することになった。

ゲームの企画を考えて、個々のタスクに落としていく。ぼくは、各メンバーがコーディングできるように、最初にゲームのフレームの部分を作ることになった。その間、他のメンバーはコードが書けないので、絵を描くことになった。

プログラマに絵を描かせるなんて…。

そもそも絵を描くツールすらパソコンに入っていない。スッポンを描け、ヒバリを描け、馬を描け、風船を描け…。想像を絶するタスクが割り当てられる。

ゲームのフレーム部分ができたのは、1日目の夜。2D横スクロールのマップ上をスッポンが這って移動し、風船などのNPCにつかまって障害を乗り越え、それぞれのステージのゴールを目指すというもの。

あんまりJavaScriptに慣れた人はいないので、その後も、苦しい戦いが続く。というか、Cしか習っていない若い人は、オブジェクトがどうのと言われてもよくわからなかったかもしれない。また、JavaScriptの場合、クラスベースの言語と異なるし、同じものを記述する方法が何種類もあるので、最初はわかりにくいだろう。

また、設計上、コードを再利用しようとしてコンフリクトするよりも、個々のプログラマの裁量にまかせる方針にした。しかし、その辺をうまく共有しそこねて、作業は多くなるわ、コードのコミットとマージでボトルネックが発生するわ、となかなか厳しい開発となった。

うまく基本を設計しようとすると、作業分担できるようになるまでに、時間がかなり必要となる。30時間内で、基本設計と個々のコーディングの時間配分はなかなか難しいものを感じた。

昨年参加したときは、チーム構成はプログラマ2名+グラフィッカ3名だった。ある程度の経験者のプログラマ2名だと、プログラムを完全に分業できるように分担することは容易で、ほとんどこの問題は発生しなかった。

半分が若い人で、全員プログラマだと、どう分担するかは悩ましい問題だ。経験者1名+若い人1名のサブチーム4つに分けて、個々に完全に分業できる形で開発するなど、特殊なチーム構成に応じた対応が必要だったかもしれない。

作ったゲームは、以下のリンクから遊ぶことができる。ところどころバグっていて、音が出なかったり、地面に埋もれたりする。

なお、プログラマ8名というありえないチャレンジに対して、Unity社からUnity賞をいただきました。どうもありがとうございます。

いずれにせよ、とてもチャレンジングな環境で苦しい戦いを戦ったチームのみんなに感謝します。 もちろん、運営や他のチームや関わったみなさんにも。

また、ふだんチームで開発しないので、いろいろと参考になることが多かった。

帰ってきて、リリース版のコードを読み直してみた(バグを修正しちゃおうか、敢えてこのままにしようかちょっと悩んでいる。というか、実はほとんどリファクタリングもしちゃったコードが手元にある)。若い人たちの書いたコードを見て思ったことなど。

  • コーディング規約に対する留意
    コーディング規約を決めていたわけではないが、変数、定数の命名方法などは、周りに合わせた方がいい。また、インデントは適切に行なった方がいい。
    というのも、バグを見つけて直すのは、下手をするとコードを捨てて1から書き直した方が楽なくらい激しく大変なので、読みやすく間違いを見つけやすく書いた方がいいということ。
  • 状態の管理があやしいところがある
    状態遷移図を書いてから、コードを書いた方がいい。
    というのも、状態も、バグりやすく直しにくいので、きちんと最初の段階から管理する必要があるので。
  • 他人に影響するコードの追加・修正
    コードを追加・修正するときは、他人に影響しないように行なった方がいい。難しい場合は、相談した上で。

若い人の書いたコードを見て、学校でプログラムの書き方を教えているが、そこで何が不足しているのかについて、いろいろ参考になることが多かった。今後、是非、役立てたいと思う。これは、ぼくにとっては、本当に大きな経験となった。

2012年8月7日火曜日

福島GameJam in 南相馬2012の技術的教訓

東北ITコンセプト 福島GameJam in 南相馬2012に行ってきた。

今回は、8人のチームで全員がプログラマという構成だった。その中で、結果として、前半にベースのフレームとなるプログラムを作り、後半は主にはプログラム相談に応じたような形となった。

そこで、技術的な教訓を書いておこうと思う。

今回は、enchant.js(JavaScript+HTML5なゲームフレームワーク)でゲームを開発して、次のものが必要だと思った。

1.クラスベースの言語のプログラマ向けのJavaScriptの説明資料

『Ajaxイン・アクション』の「付録B オブジェクト指向プログラマのためのJavaScript講座」でもいいかもしれない。しかし、そのために厚くて情報が古くなっている本を買うのはちょっと厳しいような。
あと、JavaScriptのデバッグ方法書いたものも欲しいかも。たとえば、たにぐちまことさんの『よくわかるJavaScriptの教科書』のFireBugの使い方の説明は詳しくていいかも。

2.enchant.jsで多人数でコーディングするときの設計とコーディング指針

3.はじめての人向きのGitなどの分散バージョン管理システムの説明資料

前回の福島GameJamでは、2人でenchant.jsでコーディングし、完全に独立に書けるように分担した(更に、わたしは途中で具合が悪くなってあんまり役に立たなかったという話も)。
今回は、8人でenchant.jsでコーディングしたところ、分担するためのベース(含む検証)のコーディングに1日目を使ってしまい、だいたい2日目から分担してコーディングに入った。
それでも、あんまりうまく設計できなかった部分があり、コード間の結合性が高くなってしまった。そして、分担時の説明がJavaScriptをやったことがない人にはあまりうまくできなかったような気がする。

また、8人でコーディングしたところ、コミットとマージで時間ロスがあった。

なお、前回のときは、シーンの結合があんまりうまくいかなくて、結局、jQueryでオープンニングつけたりした。その後、『ゼロからはじめるenchant.js入門』が出て、これを読んだところ、今回は問題なくできるようになった。

2011年12月15日木曜日

キー同時押し対応: Processingでゲームを作るときに使うキーの状態を管理するクラス

課題

Processingでは、キーを押したり、離したりといったイベントに対応したプログラムを簡単に書くことができる(※1)。 しかし、どのキーが押されていて、離されているのかを調べることは、素直にはできない。 これはキーの同時押しなどに、ナイーブには対応できないということだ。

ゲームでは、キーの同時押しなどにも対応する必要がある。 そこで、キーの状態を管理するクラスを作ってみた。

※1: それぞれkeyPressed()とkeyReleased()メソッドをオーバーライドする。


原因

Processingには、イベントが発生したキーの値を調べるために、char型のkeyとint型のkeyCodeという変数が用意されている(※2)。 この変数には、最後にイベントが起こったキーが入っている。 それは、一般に現在押されているキーとは異なる。

※2: キーがASCIIコード表にあるものなら、keyにその文字が入る。ない場合は、keyの値がCODEDになり、keyCodeにUPなどの対応した値が入る。詳しくはリファレンスを参照。


解決方法

キーのクラスを作り、押されているか否かという状態をフィールドに用意する。

キーが押されたり、離されたりしたイベントが発生したら、どのキーでそのイベントが起こったか調べ、押されているか否かという状態を更新する。


実装例

クラス図は次のようになる。

キー
キーの名前: String
keyの値: char
keyCodeの値: int
キーが押されているか否か: boolean
引数で指定されたキーと一致するか(keyの値: char, keyCodeの値: int)
引数で指定されたキーが押された(keyの値: char, keyCodeの値: int)
引数で指定されたキーが離された(keyの値: char, keyCodeの値: int)
キーの絵を描画(表示位置のx座標: int, 表示位置のy座標: int, 横幅: int, 高さ: int, フォント: PFont, フォントサイズ: int)

キーの絵を描画するメソッドは、下の方に書いた使用例で使うために用意した。 これは必要なければ、用意しなくてもいい。

具体的なコードは以下である。

// Processingでキーの状態を管理するクラス
class Key {
  String name; // キーの名前
  char key; // keyの値
  int keyCode; // keyCodeの値
  boolean isPressed; // 押されているか否か

  // コンストラクタ
  Key(String tempName, char tempKey, int tempKeyCode) {
    name = tempName;
    key = tempKey;
    keyCode = tempKeyCode;
    isPressed = false;
  }

  // 引数で指定されたキーと一致するかどうかを判定
  boolean equals(char tempKey, int tempKeyCode) {
    if (tempKey != CODED) {
      if (key == tempKey) {
        return true;
      } else {
        return false;
      }
    } else {
      if (keyCode == tempKeyCode) {
        return true;
      } else {
        return false;
      }
    }
  }

  // 引数で指定されたキーが押された
  void pressed(char tempKey, int tempKeyCode) {
    if (equals(tempKey, tempKeyCode) == true) {
      isPressed = true;
    }
  }

  // 引数で指定されたキーが離された
  void released(char tempKey, int tempKeyCode) {
    if (equals(tempKey, tempKeyCode) == true) {
      isPressed = false;
    }
  }

  // キーの絵を描画する
  void draw(int xOffset, int yOffset, int width, int height, PFont font, int fontSize) {
    int textColor, backgroundColor;

    if (isPressed == true) {
      textColor = 255;
      backgroundColor = 0;
    } else {
      textColor = 0;
      backgroundColor = 255;
    }

    stroke(0);

    fill(backgroundColor);
    rect(xOffset, yOffset, width, height);

    textAlign(CENTER);
    textFont(font);
    fill(textColor);
    text(name, xOffset + width / 2, yOffset + height / 2 + fontSize / 2);
  }
}

使用例

ゲームでよく使うキー(上下左右スペース)の状態を画面に表示するプログラムを作ってみた。

ゲームのキーのコントローラー

まず、ゲームでよく使うキーをコントロールするコードを、メインプログラムに直接書くとぐちゃぐちゃする。 よって、ゲームのキーのコントローラーのクラスを用意した。 このクラスは、ゲームに必要なキー(この例では上下左右スペース)によって、変更を受ける。 クラス図は以下のようになる。

ゲームに使うキーのコントローラー
上キー: キー
下キー: キー
左キー: キー
右キー: キー
スペースキー: キー
使用するすべてのキー: キー[]
キーを描画する横幅: int
キーを描画する高さ: int
キーを描画するフォント: PFont
キーを描画するフォントのサイズ: int
引数で指定されたキーが押された(keyの値: char, keyCodeの値: int)
引数で指定されたキーが離された(keyの値: char, keyCodeの値: int)
キーのコントローラーを描画(表示位置のx座標: int, 表示位置のy座標: int)

具体的なコードは以下である。

// ゲームに使うキーのコントローラーのクラス
class KeyController {
  Key upKey, downKey, leftKey, rightKey, spcKey; // 使用するキー
  Key[] keys; // キーを入れる配列
  int keyWidth, keyHeight; // キーの描画サイズ
  PFont keyFont; // キーの描画フォント
  int fontSize; // キーの描画フォントのサイズ

  KeyController() {
    // キーの描画の設定
    keyWidth = 50;
    keyHeight = 50;
    fontSize = 10;
    keyFont = createFont("MS Gothic", fontSize);

    // 上下左右スペースキーを作る
    upKey    = new Key("UP",    (char)CODED, UP);
    downKey  = new Key("DOWN",  (char)CODED, DOWN);
    leftKey  = new Key("LEFT",  (char)CODED, LEFT);
    rightKey = new Key("RIGHT", (char)CODED, RIGHT);
    spcKey   = new Key("SPC",   ' ',         0);

    // 作ったキーを登録する
    keys = new Key[5];
    keys[0] = upKey;
    keys[1] = downKey;
    keys[2] = leftKey;
    keys[3] = rightKey;
    keys[4] = spcKey;
  }

  // 引数で指定されたキーが押された
  void pressed(char tempKey, int tempKeyCode) {
    // 全キーに引数で指定されたキーが押されたことを通知
    for (int i = 0; i < keys.length; i++) {
      keys[i].pressed(tempKey, tempKeyCode);
    }
  }

  // 引数で指定されたキーが押された
  void released(char tempKey, int tempKeyCode) {
    // 全キーに引数で指定されたキーが離されたことを通知
    for (int i = 0; i < keys.length; i++) {
      keys[i].released(tempKey, tempKeyCode);
    }
  }

  // キーの状態を描画する
  void draw(int left, int top) {
    /*
                  -------
                  | UP  |
      -------------------------
      | SPC |LEFT |DOWN |RIGHT|
      -------------------------
    */
    upKey.draw(   2 * keyWidth + left,             top, keyWidth, keyHeight, keyFont, fontSize);
    downKey.draw( 2 * keyWidth + left, keyHeight + top, keyWidth, keyHeight, keyFont, fontSize);
    leftKey.draw(     keyWidth + left, keyHeight + top, keyWidth, keyHeight, keyFont, fontSize);
    rightKey.draw(3 * keyWidth + left, keyHeight + top, keyWidth, keyHeight, keyFont, fontSize);
    spcKey.draw(                 left, keyHeight + top, keyWidth, keyHeight, keyFont, fontSize);
  }
}

メインプログラム

ゲーム用のキーのコントローラーのクラスを作って、そちらにコードをまとめたので、メインプログラムは以下のようにすっきり書ける。

// ゲームに使うキーのコントローラーのオブジェクト
KeyController keyController;

void setup() {
  size(400, 400);
  keyController = new KeyController();
}

void draw() {
  keyController.draw(100, 100);
}

void keyPressed() {
  keyController.pressed(key, keyCode);
}

void keyReleased() {
  keyController.released(key, keyCode);
}

メモ

この実装は、Casey Reas、Ben Fry著、『Processingをはじめよう』、オライリー、2011年程度の知識がある人が見ることを想定している。 このため、カプセル化などは行なっていないし、拡張性のある柔軟な設計にもしていない。

たとえば、KeyControllerクラスとKeyクラスには、デザインパターンのObserverパターンの一部を使っている。 しかし、KeyControllerに、柔軟にKeyを追加したり、削除したりするようなメソッドを用意していない。

Javaに関してより高度な知識があれば、KeyやKeyControllerクラスのフィールドを外部から隠蔽し、必要なsetterやgetterを付けてもいいかもしれない。 また、KeyやKeyControllerから、画面表示に関連するコードを分離してもいいかもしれない。