2016年7月18日月曜日

vgs-cpuを完成させる

昨日書いた VGS-CPU + アセンブラ (VGS-ASM) を(とりあえず)完成させた。ただし、アセンブラの方は、まだ十分にテストしていないのでまだバグがあるかもしれません。(CPUの方にはバグはありません)
https://github.com/suzukiplan/vgs-cpu

命令セットの仕様的には、8086 と 6502 がごっちゃになった感じで、尚且つ32bit CPU という、一見するとカオスな感じでありながら、実際のところかなりアセンブリ言語でのコーディングがし易い形になっているのではないかと思います。

当初VGSオペランドという特殊命令を実装するつもりでしたが、それだと VGS-CPU の用途が狭まってしまう。元々、VGS用ゲーム開発専用のCPUを開発するつもりで作っていたので、それでも目的は外れていないのですが、VGS-CPUをベースにした亜種CPUを開発し易いようにするため、8086のINT命令相当のものを実装することにしました。

INT命令といえば、MS-DOSのサービスコール INT 21h とかよく使いましたね。

INT命令で実行される命令は、以下のように簡単に(最大256個)登録できます。

int hello_world(struct vgscpu_context *c)
{
    printf("HELLO, VGS-CPU");
    return 0;
}

int main()
{
    struct vgscpu_context *c = (struct vgscpu_context *)vgscpu_create_context();
    vgscpu_regist_interrupt(c, 0, hello_world);

VGS mark-III では、この割り込みの大半が VGS-API に割り当てる形になります。
INT命令を実装したことで、VGS-CPU と VGS-ASM の責務範囲は一通り実装できたことになるので、「だいたい完成した」といって良い状態ではないかと思います。

VGS-ASMの方は、まだまだ実装したい項目が盛り沢山ですが。
とりあえず、VGS-CPUの全ての命令セットを使用したコーディングができるという状態。

テストが通っているアセンブリ言語のサンプルソース:

/*
    PUSH/POP A の テストプログラム
 */
start:
    LD      A, $deadbeef
    PUSH    A
    PUSH    AH
    PUSH    AO

    POP     AO
    CMP     A, $ef
    JNE     test-failed

    POP     AH
    CMP     A, $beef
    JNE     test-failed

    POP     A
    CMP     A, $deadbeef
    JNE     test-failed

    LD      D, 1
    BRK

test-failed:
    LD      D, -1
    BRK

中々良い感じではないでしょうか。

今は MMM; main memory mapper という、フルアセでコーディングする上で一番厄介になる主記憶のメモリマッピングをアセンブリ言語で簡潔に表現できる仕組みを脳内で設計中。(あとはテストも書かないと)

2016年7月17日日曜日

vgs-cpuがひとまず完成(cpuは...)

5月からシコシコと作り続けていた vgs-cpu がついに完成。
https://github.com/suzukiplan/vgs-cpu
まだ、VGSオペランドで実行する命令は未着状態ですが

従来のVGS(mk-II SR)では、プログラムはC/C++のネイティブコードで記述していましたが、新しいVGSでは独自の仮想CPU用のネイティブコードでプログラムを記述していくスタイルにするつもりです。

そして、無事CPUエミュレータが(ほぼ)完成した訳ですが、現状では一応プログラムを書くことはできるものの、全てハンドアセンブルしなければならない状態なので、この状態でプログラミングするのは中々キツイ(できない訳ではないけど)。

誰でもゲームを作れるようにするにはアセンブラぐらいは必要だろうということで、今度はアセンブラをシコシコ作成中。
https://github.com/suzukiplan/vgs-cpu/pull/1

コンパイラ?

コンパイラは甘え

2016年7月12日火曜日

Travis CIでC言語プロジェクトの自動ビルド+テスト

vgs-cpuのLinuxでの自動ビルド+テストにTravis CIを導入してみました。
オープンソースなのでタダ乗りです。

README.md でよく見られる下図の「build passing」というバッジをクリックすれば、vgs-cpuをTravis CIでビルドしたログとかが見れたりします。
バッジ(build: passing)
ビルド+テストログが誰でも見れる
Web版のTravis CIで、C++やclangを利用したプロジェクトの場合、コンパイラのバージョン依存が結構あると思いますが、vgs-cpuならGCCバージョン2.96という枯れ切った規格に準拠した記述をしているので全く問題ありません。

(対応するためにやったこと)
・全てのビルドとテストの手順をmakeで書く(最初からそう書いている)
・GitHub上のアカウントの設定でTravis CIのWeb hookを許可
・Travis CIでアカウント連携
・対象プロジェクト(vgs-cpu)のトグルをON
・対象プロジェクト(vgs-cpu)に .travis.yml(内容は下記) を追加

script: 
  - make --no-print-directory test

・README.mdにバッジを表示する情報を追記

# [WIP] VGS CPU [![Build Status](https://travis-ci.org/suzukiplan/vgs-cpu.svg?branch=master)](https://travis-ci.org/suzukiplan/vgs-cpu)

これだけで、あとは master へ push なり Pull Request を merge するなりすれば、Travis CIがLinux(Ubuntu)でvgs-cpuのビルド&テスト(make test)を実行してくれます。

基本的に普段はMacでビルド+テストしているので、Linuxでのビルド&テストも放っておけば(というかpushすれば)勝手にやってくれるのは中々便利。

そうそう環境依存のバグを作り込むことは無いですが、一発仕掛ければ後は勝手にやってくれるのが良いですね。どちらかといえば、環境依存バグはWindowsで作り込み易いので、Windowsの似たようなCI(Platform SDKが使える)があれば尚良いのですが...

2016年7月3日日曜日

ランダム要素+ランキングシステムが秀逸なゲーム

私が最近はまっている Nuclear Throne というゲームを紹介します。(Nuclear Throneは日本語に直訳すれば、核の玉座という感じでしょうか)

Steamで売られていて、Windows, Mac, Linux に対応してます。
http://store.steampowered.com/app/242680/
あと日本で買えるかは分かりませんが、PS4とかでも売られているらしいです。

どのぐらい面白いのかというと、ソーシャル要素の無いオフラインゲームなのに、プレイ時間が100時間を超えてもなお飽きないぐらい面白いです。

Steamだとプレイ時間が測れるから良いですね。

ゲームの内容は、ライフ制の全方向スクロール・シューティングです。
シューティングとはいっても、ゼルダの伝説みたいな感じですが。
2つの武器を持つことができるので、それらを使い分けて敵を倒していきます。

ステージ構成は、全7ステージ(15エリア)で周回ループ有りです。
奇数ステージは通常3エリア。
偶数ステージは通常1エリアのみのショートステージ(ボス無し)。
奇数ステージのエリア3にはボスがいますが、1面はエリア1でボスが出てくることが稀にあります(倒せばそのままステージ2へ)。
7-3をクリアして一定条件を満たせば2週目(ステージ0)に入ります。

全ステージクリア(1周)に掛かる時間は15〜20分ぐらいです。
1周オールに掛かる時間の例(17分24秒)
上図の場合、隠しステージに一切寄らずにストレートに15エリアクリアしていますが、隠しステージがかなり豊富にあったりします。

例えば、3-1に1つだけある金縁の車をスクリュードライバーで叩くと、ゴールデン装備が手に入る隠しステージに行けたりとか。

ゴールデン装備とは、通常ゲームスタート時はピストルを持って開始しますが、ゴールデン装備を手に入れて有効な状態にすることができれば、それを初期装備とすることができます(ただし、dailyチャレンジの場合は使用不可)。

私は近接武器(レンチ、シャベル、ハンマーあたり)をメインに使っているので、ゴールデン・レンチが取れるまで結構粘りました。
ちなみに、このゲームで近接武器をメインで使う人は少数派かもしれません。マウス+キーボードでプレイする場合は飛び道具メインでプレイした方が面白いので。ただ、ゲームパッドでプレイする場合、飛び道具が使い難いので近接メインでプレイせざるを得ないかも。(攻撃をする時の入力が進行方向と逆に入れる必要があるというかなりクセのあるものなので)
このゲームの最大の特徴は、とにかくランダム要素が多いことです。

ステージの形状や敵の配置がランダム
どういう武器が拾えるかもランダム
回復アイテムが拾えるかどうかもランダム

近接武器をメインに使う私の場合、ステージ4に入るまで(3-3まで)にシャベルが拾えるか拾えないかで、難易度がかなり揺れます。
もっとも、私が初めて1周オールした時は、ハンマーもシャベルも拾えず、ゴールデン・レンチで Nuclear Throne を殴り壊しましたが。
初回クリア時のスクショ
ゴールデンレンチで殴り壊しました
1周目なら、装備よりもどちらかというと進化の方が重要かも。

一定量の緑のアイテムを集めてレベルが上がると特殊能力を追加できるのですが、これもどれが来るかはランダムです。
近接メインで攻める場合の最重要進化は、LONG ARMS(射程が伸びる)とGAMMA GUTS(体当たりでダメージを与える)で、ステージ4までにこれらの進化が出来たか出来なかったかで難易度がかなり変わってきます。
LONG ARMS
(最重要進化)
GAMMA GUTS
(下手な内は)結構重要な進化
更に、デスエンカみたいな敵も稀に出ます。
1面の黄色いサソリとか5面の黄色いロボとか。
黄色いサソリは良いですが、黄色いロボはヤバイ。
黄色いロボ
(恐らく1周目最恐のデスエンカ)
上図のように壁に隠れながら、EYESの敵を引き付ける特殊能力で誘導しつつ、近接武器(※近接武器の場合、壁を貫通して敵を攻撃できる)で殴り壊せば怖くないですが、そういう風にできるかどうかも運ですね。
やや広い地形に3体黄色いロボが居て、ハンマーヘッド(壁を壊せるようになる進化)も無かった時は、「あ、死んだな」って感じになります。

このゲームのランダム要素以外の特徴としては、日々クリアされるデイリーランキングでしょうか。

iOSとかのゲームセンターを使った事がある人なら分かると思いますが、有名どころのゲームのランキングというのは、一部の馬鹿な人がクラッキングして出した不正なスコアで上位ランキングが埋め尽くされているので、何も面白くありません。そんなクソランキングは、むしろ無い方が良いというのが、真にゲームを楽しみたい人にとっての共通認識ではないかと思います。

このNuclear Throneのランキングですが、1日1回しか挑戦できず、しかも毎日クリアされます。
在りし日のデイリーランキング(Global)
1日1回しか挑戦できないという成約は上手いですね。
継続プレイ率をかなり上げることが出来るのではないかと思います。
実際、毎日数千人のプレイヤーが競いあっています。
更に、デイリーでクリアされることから、チートでランキングを荒らす馬鹿も湧きにくいし、仮に湧いてもすぐにクリアされます。(まぁ、ボットで毎日送り続けるようにする阿呆も湧いてくるかもしれませんが、ゲームセンターと違って毎日送り続ける必要があるから、それは相当リスキーでしょう)

総括すると、Nuclear Throneは、
・適度なランダム要素で得られる新鮮なゲームプレイ
・チート対策で純粋にゲームで競いたい人にとって嬉しいランキングシステム
あたりが秀逸なゲームという感じでしょうか。

ちなみに、難易度は結構高めです。
近接メインでクリアするのは中級者向けで、あまりゲームが上手くない人は飛び道具メイン(キーボード+マウス)でプレイした方が無難です。飛び道具メインでプレイする人向けに参考になりそうな実況動画がニコニコ動画に上がってました。
http://www.nicovideo.jp/watch/sm27848106

2016年6月27日月曜日

PxtoneJS

GitHubで何気なく「pxtone」で検索してみたら、PxtoneJSなるものを見つけた。

WebAudioで鳴らせるものなのかー
まだ、動かして確認はしていませんが。
VGSのmmlもWebで再生できないかと思っていたりします。

Flashとか使うなどの手段を採れれば技術的には出来なくもないというより、ニコニコ大百科のピコカキコで使われているFIMML等の先駆者が居るので、作ろうと思えば100%実現可能ですが、Flashは今後消えゆくのでナシです。

しかし、WebAudioはまだまだ発展途上という感が否めない。というか、以前Invader Block 5みたいなものを作ってデバックしてみたら、Chrome以外のブラウザではまともに動かないという有様でした。

WebAssemblyが動くサンドボックス環境にOSSやALSAぐらいシンプルなローレベル音声システムが実装されれば良いなと思っていたりするのですが、どうなるか分からないので、WebAudio版を作り進めておくのも悪くはないかも。

とは思いつつ、当面手を付けれそうにないですが

2016年6月5日日曜日

東方VGSの更新が止まっていますが、私は元気です

いや、色々とありまして...

まず、一番大きなところで、VGS mk-III の開発を本格的に始めたから時間がありません。

mk-IIIは、大まかにはこんな感じにするつもりです。

音源システム周りは mk-II と全く同じ。
vgs-bgm-decoder, vgs-mml-compiler, vgs-spu をそのまま使います。
若干の改良点としては、効果音関連で今まで音源ソースは .wav ファイル限定でしたが、ogg/vorbis もサポートしたり、周波数とかを自動変換できるようにしたりする予定(ROMDATA.BINの内部構造は変更しないつもりです)。
そこまでやるなら mp3 とか aac も...と言いたくなるところですが、それらは大人の事情(特許関連)により使えません。
グラフィックス面は、ソースとしてpngも使えるようにしようと考えていますが、それ以外にも同時発色数を8bitカラー(256色)から16bitカラー(65536色)にするかも。αブレンド(半透明)を使えるようにしたいかもと思っているので。
あとは、(これはまだ構想段階ですが)VGSのゲームプレイ内容を動画に録画して、ニコニコ動画やYouTubeなどに簡単にプレイ動画をアップできるようにしてみようかとか、考えたり、考えていなかったり。

色々と変わる予定ですが、一番大きな変更点は CPUの自前化 です。

vgs-cpuという独自の仮想CPUを搭載します。
https://github.com/suzukiplan/vgs-cpu

これは完全に暴挙ですね。
CPU自体は32bitですが、フルアセンブリ言語でも 6502 並にコーディングし易いCPUとして設計中です。オールマシン語でゲームプログラムを作るのは、8bit時代は結構普通だった(というよりBASICなどの入門言語を除けばそれが標準的だった)のですが、16bitで少し難しくなり、32bitで完全に無理になりました。ただ、32bit CPUだったとしてもオールマシン語で作る前提でCPUを再設計すれば、結構いい感じになるんじゃないかと。

mk-IIまでのVGSは、cocos2dやUnityなどと同じ 単なるSDK ですが、私はSDKを作ろうという気は初めからサラサラ無く、作ろうとしたのはVGSという私の脳内に実機があるコンソールゲーム機のエミュレータです。なので、これでようやくVGSが青写真通りの形になる訳です。

完全に誰得だということは確定的に明らかですが、それはさておき。

しかし、この作業の合間の時間にでも東方VGSの更新はできなくもないのですが、今はSteamのNuclear Throneというゲームをプレイするのに忙しかったりとか...(このゲームはやばい)

「テスト書け」が馬の耳に念仏になる原因

vgs-cpuをgithub上でモリモリ設計中。
https://github.com/suzukiplan/vgs-cpu

この記事執筆時点のcommit
https://github.com/suzukiplan/vgs-cpu/commit/29f8cbe684dd1489fcb3a8b3cfffbbc52a6757cd

CPUのコードを書くのって完全なる単純作業です。
こういう単純作業だと割りとバグを作りこみ易いです。
なので、こういう場合はテストを書くのが重要。

という訳で、このリポジトリを git clone して make を叩けばテストを流すようにしました。(※Mac or Linux限定で、Windowsには対応していませんが...)

プログラムを書いたことがあれば、「テスト書け」なんて耳にタコができるほど言われることで、馬の耳に念仏状態かもしれませんが。

テストを書く目的は、
1. バグの早期摘出
2. エンハンス時のデグレード防止
の2つしかありません。

1の理由は、後工程で見つけると原因を特定するのに掛かる時間(摘出コスト)が指数的に増加するためです。これは古典的なウォータフォールだろうが、アジャイルだろうが同じことです。

vgs-cpuのレジスタAに対するスタック操作(push/pop)、メモリ移動(load/store)、インクリメント、デクリメント、NOT演算のコード規模はだいたい100ステップぐらいですが、テストを書いてみて摘出できたこの部分のバグは以下の3件です。

bugfix: notの演算結果が不正
https://github.com/suzukiplan/vgs-cpu/commit/9b4f49235a60d63202a0f753d1233768284f4810

bugfix: inc, dec, not で プログラムカウンタ の インクリメント漏れ
https://github.com/suzukiplan/vgs-cpu/commit/f31ddfbf9f355a590e78448c858f905e1c81e47e

bugfix: VGSCPU_OP_POP_A4 (2byte -> 4byte)
https://github.com/suzukiplan/vgs-cpu/commit/53ca01c247086f886758a4bb7dfc3a4931849558

これらを早期に潰すことで、最小のコストで品質を担保できます。

で、スタック操作(push/pop)、メモリ移動(load/store)の命令群には、この後メモリ検査のエンハンスが入る予定ですが、これらのテストを全て自動化しておくことで、エンハンスを入れた時にデグレードが発生しないことを保障する訳です。

ちなみに、「単純作業だと割りとバグを作りこみ易い」と上述しましたが、だいたいの人が1ks(千行)のプログラムを書いた時に作り込むバグの件数というのは、統計的に10〜15件なので、100行で3件(ksあたり30件)という具合に実際多い。

ただし、ある程度作り慣れてくると、バグの作り込みパターン(バグ知見)が脳内に蓄積されることで(主に同件の)バグを作り込む確率が減ります。

プログラムを書く時、面倒臭いから 全部作ってから後でテストすれば良い という考え方の人が結構居ると思います。少し話は飛びますが、プロジェクトの特性として「新規性」というものがありますが、これは要するに「無いものを新たに作る」という事です。既にあるものなら、わざわざ新規に作らなくても既にあるものを使えば良いですからね。で、新規性という特性を持つ以上、バグ知見が十分に足りていない可能性がものすごく高いという事は自明です。(成熟度が低い組織だったり新規性が高い分野のものづくりをすると、似たようなものを作るケースも多々ありますが)

だから、今回のvgs-cpuの開発では、スタック操作(push/pop)、メモリ移動(load/store)、インクリメント、デクリメント、NOT演算のだいたい100ステップぐらいのコードが出来たところで、一旦開発を止めて徹底的にテストすることにしました。バグ知見が十分に溜まったところであれば、テストを省略しても問題無いと思います。バグ知見が十分に溜まったところでもガリガリテストを書くのは過剰品質(テストを作るコストが品質に寄与しない)という感じになります。

「テスト書け」が馬の耳に念仏になる原因はソコにあります。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...