STGの敵の出現パターンとか、敵の飛行曲線とか、弾幕とかを安直に書くための言語STGL作った

上のページ行って、「START」ボタン押せば遊べます。左に書いてあるのがSTGL。

大昔に弾幕を書くための言語としてBulletMLってのを作ったけど、これは弾幕専用なので、敵の飛行曲線とかは書けなかった。あとXMLなので記述が冗長。この辺がかねてから不満だった。

飛行曲線、もっといえばステージパターンも含めて、STGの基本動作を安直に書ける方法があればいいのになー、ってのは前から思ってたんだけど、なかなかうまい方法が見つからなかった。いろいろ考えた結果、とりあえず今回のSTGLっていうのに落ち着いた。これがベストではないだろうが、それなりに簡易な言語仕様でまあまあいろいろ書けるというバランスにしたつもり。

STGLの特徴としては、

  • 1関数 = 1アクター

なので関数呼び出し=アクターの生成。

  • アクターってのは敵の出現場所、敵、砲台、弾のどれか

動作の記述方法はどれでも同じ。@xとかいうアクター変数をいじるとアクターの状態が変わる。

  • 毎フレーム変数を書き換え続ける<=とかいう謎の演算子

「@x <= cos(@y * 0.001) * 0.4 + 0.5」と1回言っておけば、あとは@y座標の変化に応じて自動的に@x座標はcosで波打ってくれる。

0.1__0.9で0.1〜0.9の間の小数が、2..5で2〜5の間の整数が作れます。

  • アクター間通信はほとんどできないけど、子を消したり待機状態を解除したりはできる

ザコの早回しとか、ボスを早めに倒した後の追加ザコの補充とかは無理やり書けます。

といったところ。BulletMLと比べると変数とか演算子とかいろいろ書けるようになってしまっているので、DSLとしての面白味は若干低め。論理演算はほんとは入れたくなかったんだけど、これ無いと自機の反対側から敵が出現するとか書けなかったので、しょうがなく入れた。

BulletMLの時はプロギアっぽい弾幕がそこそこ実現できるってのが目標だったけど、STGLはスターフォースゼビウスっぽいザコがそこそこ実現できるのを目指してます。今の言語仕様でたぶん大体書けると思うんだけど、どうかなあ。ゾシーとかは厳しいかなあ。

2012年作ったゲーム遊んだゲーム

今年自分で作ったゲームと遊んで面白かったゲームを書いてみた。

作ったゲーム

ミニゲームばかり30個少し。ほとんどFlashプチコン少し。wonderflにはお世話になりまくりです。Haxeにも対応いただけませんかね。

一応自分で気に入っている順に書いた。上の方がお気に入り。

プチコン

2011年もたぶん同じくらい作っているので、だいたいこんくらいが妥当なペースなのかなあ。ミニゲームばかりなのは、新しいルールをいろいろ考えるという、ゲーム作りのプロトタイピング部分が個人的に好きで、そこばかりかじっているからなんだけど。小物ばかり作ってると、ちゃんとした体裁のゲームを作れなくなっていくので、あまり良くない気もする。まあフリーゲーム作りは自分が好きなもの作ってればいいか。

面白かったゲーム

ぶっちきりでこれだぜ!ってのがあるわけでもないので適当に並べてみた。

こちらも大作よりはちょっと遊べる系の方が増えてるなあ。Forza Horizonのゲーム達成率もぜんぜん伸びてないんですけど。ゲーム体力の枯渇を感じる。

Flashでの2Dイメージ描画はStarlingフレームワークで高速化できるけど注意点もある

Flashで2Dイメージを高速に大量に書きたいときは、GPUを使った2D描画を実現してくれるStarlingフレームワークを使えばいい。Flashの従来の2D描画と似たようなAPIで、Stage3Dを使ったGPUでの描画をしてくれる。

でも、Flashは従来からBitmapDataを使えばそこそこ速く2Dイメージを描画できる。わざわざStarlingフレームワークを導入する価値はあるのだろうか、と思って簡単なベンチマークアプリを作ってみた。Haxeで書いたけど、描画性能はAS3で書いた場合とそんなに変わらない、と思う。

大量の文字を上から降らせて、いろんな描画方式でFPSが確認できるようにした。マウスをクリックするたびに、以下の描画方式を切り替える。

RenderTexture.drawBundled()を使う方式

StarlingでのBitmapDataに相当するものがTextureだ。ここではその動的書き換え可能版のRenderTextureにImageをdrawすることで文字を描画した。

注意すべきは、単に毎回drawするとひどいパフォーマンスになるので、複数のdrawをまとめてGPUに送るdrawBundledメソッドを利用すること。詳しいことは以下の記事にまとまっている。

この方式の特徴は以下となる。

  • drawBundledを使っても結構低速
  • 半透明、回転、拡大縮小、色付け可能

QuadBatchを使う方法

Starlingで最速の2D描画方式がQuadBatchだ。QuadBatchインスタンスにimageを追加していって一気にGPUに送り描画する。

ただQuadBatchには制約があり、同一のテクスチャしか描画できない。なので普通に使うと同一の2Dイメージを大量に表示する用途にしか使えない。

その制約を何とかするためにはTextureAtlasを使う。複数のイメージを一つのテクスチャに描画し、各イメージのリージョンを切り出して描画する。こうすることで、QuadBatchを使って異なるイメージを描画することができる。TextureAtlasの詳細は以下にある。

この方式の特徴は以下となる。

  • かなり高速
  • 半透明、回転、拡大縮小はできるが、イメージの色を個別に動的に変化させることはできない

BitmapData.drawを使う方法

Starlingを使わない場合の比較用。

  • 低速
  • 半透明、回転、拡大縮小、色付け可能

BitmapData.copyPixelsを使う方法

BitmapDataの最速描画と言えばcopyPixels。

  • 高速
  • 半透明、回転、拡大縮小、色付け、全て無理。単にそのまま上書き描画するだけ
11/6追記

copyPixelsのmergeAlpha引数をtrueにすれば半透明は実現可能だった。

で、どれがいいかな

とりあえず手元の環境で調べた感じでは、回転、拡縮をしなくていいなら、爆速のBitmapData.copyPixelsを使っておけば、わざわざStarlingにお出ましいただくまでもない。

ただ、拡縮とかは、やっぱり使えたほうが色々と表現の幅も広がる。なのでそういった機能が使いたい時はStarlingのQuadBatch+TextureAtlasが便利だ。

まあこのへんの特性は、環境依存なところもありそうなので、一般的にどこまで言えるかは微妙かも。非力なCPUに比べてGPUがそこそこ強力な、昨今のモバイルデバイスだと、また事情が異なる可能性はあるね。

HaxeでAway3Dとthree.jsをラップすればFlashとHTML5で動く3Dゲームは作れるけどね


正直ラッパーを書くのが面倒すぎるのと、HTML5+three.js (WebGL)版があんまりパフォーマンスが出ないこと、Bloomシェーダーやらライティングやらを両方の環境で同じ感じに調整するのが難しいことを考えると、やる価値があるかどうかは微妙だ。

あとFlash+Away3D版をChrome22で動かした時に極端にパフォーマンスが悪いんだけど、これはなにか回避策があるのかしらん。

Haxe+NMEを使えば、FlashとHTML5とWindowsで動くゲームが一つのコードから作れる

ActionScriptJavaScriptC++など、さまざまな言語向けにコンパイルできることがウリのHaxe (http://haxe.org/)と、Haxe向けゲームライブラリのNME (http://www.haxenme.org/)を使えば、一つのソースコードを書くだけで、FlashHTML5、Widnowsネイティブで動くゲームを作ることができるらしいので、作ってみた。

確かにできる。一つのコードから複数の環境向けバイナリが作れるのは素晴らしい。近代的なSDL (http://www.libsdl.org/)という感じ。

ただ、何も考えずにHaxeのコードを書いていればなんでもクロスプラットフォームになる、とまではいかない印象。最初はFlash向けに作っていて、いざHTML5向けにビルドしようと思ったら、出来上がったJavaScriptがまともに動かない。いろいろと試行錯誤して、やっとHTML5版ができたと思って、次にWindows版を作ったら、また動かない。ちょい直し。という感じ。

上の作業をやっていて気付いた、クロスプラットフォームHaxe+NMEを書く際の注意点を書いておく。

  • 変数をちゃんと初期化する。ActionScriptだと宣言して放っておいてもintは0に、Booleanはfalseになってくれたりするが、環境によってはその保証がない
  • クラスインスタンスをDynamic型で扱うとき、サブクラスに定義されている関数が呼び出される可能性を検知し損なうように見える。余分なコードを排除する'--dead-code-elimination'オプションを付けた時に、必要なコードまで削られることがある。親クラスに関数定義してoverrideすると安全
  • Haxe型推論をそこそこ信用して使う。型を全然書かないで使っていると、たまに訳分からんエラーを吐くことがある
  • UIntを使わない。環境によってはNMEがUIntを扱えない
  • Lib.stage.stageWidthとかが確定するタイミングは環境によって微妙に異なるので、可能な限り後の方で取得する
  • アルファブレンド付きのBitmapData.copyPixelsをしない。HTML5環境でうまく動かない
  • SpriteをBitmapData.drawするのもHTML5でうまく動いてない感じが
  • Windowsネイティブ上のデバッグは面倒だが、'nme test foo.nmml windows -debug'とすれば、Haxeコード上のどの行で落ちたか教えてくれるので便利

予想されたことだが、環境ごとにパフォーマンスはまちまち。手元のPCだと、Windowsネイティブがもちろん最速だがFlashも十分速くて、HTML5はChrome21だとまだなんとかなるけど、Firefox15は相当厳しい、IE9は動くのがすごいがひどいパフォーマンス、という感じ。WebGLを使った描画ができればだいぶ違うと思うのだが、NMEはまだ対応していない。

NMEはiOSAndroid向けにもビルドできるみたいなので、クロスプラットフォーム萌えの人にはとてもよい環境だと思う。Haxe自体も強力な型推論のおかげで、少ない労力で強力なエラーチェックが行える、よい言語だ。

あとは3Dのクロスプラットフォームライブラリがあればより良いのだが。Away3Dとかthree.jsとかを薄くラップした、Haxe向け3Dライブラリが欲しいところだ。

Haxeを使って、PS VitaとFlash、両方で動くゲームを作れるか

すごく頑張ればできるかもしれないけど、色々と障害が多そう。特にパフォーマンス。

一度コードを書けば、それをFlashJavaScriptC#などにコンパイルできるHaxe (http://haxe.org/)を使えば、ブラウザ上はFlashで、モバイルデバイスとしてはPS Vitaで動くゲームが簡単に作れるんじゃないかと思って、ちょっとだけ試してみた。

Flashで作ったundermine (http://wonderfl.net/c/bv3w)っていうゲームをHaxeに移植して、そこからFlashC#コンパイルした。C#コンパイルできれば、PSM SDK (http://www.playstation.com/psm/developer/index_j.html)を使ってVita上で動作させることができる。

もちろんFlash固有のAPIや、PSM SDKでのグラフィックス描画などはHaxeでは吸収してくれないので、NME (http://www.haxenme.org/)のようなマルチプラットフォーム描画ライブラリを使うか、オレオレライブラリをターゲットプラットフォーム向けに書かないとダメ。Vita向けのHaxeライブラリはなさそうなので、今回はオレオレライブラリをごくごく部分的に書いた。

問題としては、HaxeC#向けコンパイラ (http://haxe.org/doc/targets/csharp)がまだ開発中でこなれてないのと、PSM SDKVitaVM実装がこなれてないの、ダブルこなれてない効果を受けたせいか、Vita上でパフォーマンスを出すのが難しそうというところ。

Haxeから生成されるC#は、Haxeがもともと一部動的型付けを許容する言語であるためか、フィールドやメソッドへのアクセスに一段よけいにメソッドがかまされることがあるように見える。inlineとかでバリバリにチューンすれば回避可能なのかもしれないけど、それを頑張るのも大変そう。

PSM SDKVita向け実装も、フォーラムでいくらなんでも遅すぎるじゃないのとツッコミ (http://community.eu.playstation.com/t5/General/Did-Sony-limited-CPU-speed-with-PSS-SDK/m-p/16027363#M1129)受けていて、結構パフォーマンスに気を使う必要がありそう。

なので現時点では、HaxeVitaFlash間のマルチプラットフォームを狙うのは難しそうかなあ。Haxe自体は気の利いたActionScriptという感じでなかなか書きやすい印象。マルチプラットフォームの恩恵を受けなくても、単にFlashを作るために使ってみるのはいいかも。FlashDevelopからも使いやすいし。

PSM SDKも、C#Vita向けゲームが簡単に書ける環境として、使っていて非常に楽しい。せっかく高機能なC#で書けるんだし、無理して他言語でマルチプラットフォーム対応を狙わなくてもいいかもね。

プチコンで広がるおっさんプログラミングコミュニティ

ニンテンドーDSBASICが書ける夢のソフトプチコンがmkIIになった。初代と比べていろいろ機能が拡張されたけど、個人的に一番うれしいのは、QRコードで自分のプログラムが簡単に公開できるようになった点。

さっそくこの機能を使っていろいろゲームを公開してみた。あんまり長いコードを書く気力は無いので、QRコード1枚に収まる範囲でどんなゲームが作れるかにチャレンジ。その方がQRコード読み取る側も楽だしね。

だいたい100行以内くらいで書けば1QRに収まる感じ。マルチステートメント無しで。

他にもプログラムを公開している人はたくさんいるので、参考にできるプログラムはたくさんあるんだけど、

この辺のプチコンで今物作っている人のうち、「BASICは初めてです!」とかいうヤングプチコナーはどんくらいの割合でいるんだろう。ツイッターとかで見ている限り、昔にPC-6001MSXとかでブイブイいわせていた、おっさん比率がはんぱなく高い印象があるんだけど、どうなんだろう。

まあ商品コンセプトとして、「DSでのプログラミングを楽しもう!」よりは「昔良き時代の思い出をまたDSで!」を狙っているっぽいので、正しいターゲット層にミートしているとは言える。純粋にDSでの簡易プログラミング環境を作りたいなら、BASICよりも現代的な言語を選択した方がいい感じがするし。

でもBASICも捨てたもんじゃないよ。下手にクラスとか関数とかないから、あんまり設計とか深刻に考えずにプログラムの頭からつれづれなるままに適当に書けるし、予約語ステートメントも限られるからコード補完もやりやすい。ちょっとしたものを手軽に作るには、貧弱な言語仕様もある意味強みになる。

パッドやボタンなどの優秀な入力手段を備えたDSでゲーム開発ができるという点でプチコンはとってもおすすめ。DIM、LOCATE、GOSUBなどの予約語をみるとウズウズする人にはもっとおすすめ。わかる!動かせる!プログラムが組めるDSを欲しい人は、プチコンを試してみてはいかが。