2016年8月7日日曜日

mac OS (OSX) のアプリでゲームパッドを使う方法

Windowsだとゲームパッドへの対応は簡単(DirectInputで可能)ですが、mac OS(OSX)だとかなり躓きどころが多い。

まず、GameControllerを検出する標準フレームワークがありますが、これが全く使い物にならない
対応機種が限られてしまうので。
AppleがMagic Gamepadみたいなものを出していればまだ良いのですが。

という訳で、mac OS(OSX) でゲームパッドの入力に対応する場合、HID Device Interfaceを使う方法が一般的です。

ただし、GameControllerと違って日本語の資料も無いし、ぐぐっても情報が全く出てこない。(ゼロという訳ではないですが)

という訳で、割と簡単に使える mac OS (OSX)用 のゲームパッド・ライブラリを作ってみました。
https://github.com/suzukiplan/gamepad-osx

呼び出しはC規約なのが若干面倒かもしれませんが、Objective-cのXcodeプロジェクトであれば問題無く利用できます。(開発中のOSX用STGに組み込んでみたのですが、問題なく動きました)

swiftのXcodeプロジェクトで使えるかは未確認ですが、int型とvoid*型しかインタフェースに使っていないので、まず問題ないでしょう。

[追記]
どうせなら、入力系統は全て gamepad で処理した方が良いということで、キーボードとマウスの入力も受け付けられるようにしました。
ただし、キーボードに関しては実装する NSView のサブクラスをファーストレスポンダに設定しておく必要があります(そうしないとキー入力時に警告音が出てしまうので)。
また、これはかなりベーシックなレイヤーで入力を受け取っている関係で、NSWindowなどの状態が非フォーカスでも入力が受け付けられる筈です。また、マウス座標も全体座標の筈。(要するにキーボードとマウスはどちらかといえばフルスクリーンで動作するゲームを想定したものです)

レベル3の壁超えについて

さて、あなたは以下の幾つが YES だろうか。

Level 1. ゲームを作りたいと思ったことがある
Level 2. ゲームを作ろうとしたことがある
Level 3. ゲームを完成させたことがある
Level 4. 完成したゲームを不特定多数の人に向けて公開したことがある
Level 5-1. 公開したゲームが法人から評価されたことがある
 ・例1: 雑誌に取り上げられた(掲載された)
 ・例2: コンテストで入賞した
Level 5-2. 公開したゲームで収益を得たことがある
 ・例1: 入賞賞金をゲットした
 ・例2: 原稿料をもらった
 ・例3: 有料販売して売れた
 ・例4: 広告収益を得られた
Level 6. 公開したゲームの収益が1年あたり20万円以上(確定申告が必要)になったことがある
Level 7. 公開したゲームで得られた収益を青色申告している
Level 8. 公開したゲームで得られた収益を白色申告している

細かいルールですが、レベル5とレベル6の判定ルールは以下のような感じです。
・5-1 or 5-2 何れか一方をクリア = レベル4.5
・5-1 and 5-2 両方をクリア = レベル5
・5-1 or 5-2 何れか一方をクリアしていなくても、レベル6をクリア = レベル6
要するにレベル4.5からレベル6への飛び級があり得るということ。
まぁ、どうでも良いことなのですが。

上記の「ゲーム」を「サービス」に置き換えても良いかも。
私は 1〜4 と 5.1&5.2 が YES で 6〜8 が NO。
つまり、レベル5 です。

私は2008年にゲーム作りを再開した当初から、このレベル設定を考え、最終的にレベル8を目指すという超絶難易度のクソゲーを遊んでいる訳です。

私がSUZUKI PLANを名乗るようになってからの遍歴を晒すと、2008年にSHOT01を完成させ(レベル3)、公開して(レベル4)、2009年にSHOT02で何冊か雑誌に載ったりして(レベル4.5)、2012年にSHOT04でようやく売れるようになってきた(レベル5)という感じです。

レベル4.5からレベル5への壁は、スマホ普及以前と比べれば大分低くなってきたものの、まだまだ依然として大きい。AdMobとか入れれば少しぐらいの収益ならゲットできるだろ?と思われる方も居るかもしれませんが、一定額(確か100$ぐらいだったかな?)以上ならないと振り込みはされないので、結構大変なことだと思います。

それでも、手段が皆無に等しかった昔と比べれば、レベル3の壁さえ超えればワンチャンあると言っても過言ではないでしょう。

しかし、レベル3の壁を超えられないという人は意外と多い。
恐らく、最初っからハイレベルなものを狙い過ぎているんじゃないですかね。
レベル3に達せない人は、まずレベル3を超えるだけのことを考えれば良いと思います。
例えば、ドラクエ3みたいなゲームを作りたいけど、プログラムは書けるが絵や音楽は無理なら、絵や音楽はキャプチャするなりROMから抜くなり(^^;)してでも作れば良いのではないかなと。
もちろん、キャプったり抜いて作った場合は公開してはいけませんが、まずはレベル3をクリアすることだけ専念すれば良くて、どうしても公開したければ、完成後に権利上問題ない素材を作るなりフリー素材から集めるなりして差し替えれば良いでしょう。
動くものがあれば、「じゃぁ、素材は俺が作ってやんよ」みたいな友達が見つかり易いかもしれません。

2016年7月29日金曜日

ポケモンgoの各国評価を見たら割と面白かった

ポケモンgoの人気凄いですね。
私もやっていますが、あまりやり込んではいなくてLv18, 集めたモンスターは43種ほど。

スマホゲームは、パズドラ、モンストが長年AppStore, GooglePlayの売上1位を独占し続けていた事からも分かるように、一発当てれば息が長い。果たしてポケモンgoはどうなるのか。

各国の売上ランクはAppAnnieで確認した限り1位キープという状態。パズドラやモンストが1位キープを続けたのは日本限定ですが、ポケモンgoの場合全世界(※一部地域を除く)で1位キープを(今のところ)続けているという違いがあります。

それはさておき、各国の評価を見てみると結構面白いことになっていました。

※図面+データはAppAnnie(https://www.appannie.com)から引用してます

まずは、日・米・英

だいたい同じような形です。
米英は 5 > 1 > 4 > 3 > 2 という並びに対して
日本は 5 > 1 > 3 > 4 > 2 という並び(3と4が逆)だったりと、
細かい違いはありますが。

余談ですが、これは私のアプリの評価を見ていても同じ傾向がある(日本人は3を付ける確率が他国と比べて若干多い)ような気がするので、これは国民性かな?「良い」「普通」「悪い」の選択肢で迷ったらとりあえず「普通」を選べ的な感じのアレです。

日本の評価1の指摘内容を見てみると、地域格差を指摘する声が多いので、各国だいたい同じような状況で評価1が集まっているのではないかと思います。(Ingressのポータルの情報がポケストップになっているので、Ingressが流行していた地域なら田舎でもそれなりに充実しているかもしれませんが)

ドイツ、オーストラリア、カナダ、オランダ、スウェーデン、スイスでもだいたい同じ評価分布になっています。世界各国だいたい同じような都市構造になっているんでしょうね。

しかし、イタリアは大分違う形をしている。
★1が圧倒的に多い。
これは一体・・・
Ingressポータルが全般的に少なかったとか?

逆にフランスは★1が圧倒的に少ない。
なお、フランスの評価件数が少ないのは、日本と同じく配信開始が遅かったためのようです。

世界各国で同じようにヒットしているので、評価分布は世界各国でだいたい同じ形(逆コの字型)になると推測していましたが、何故こんな差が出たのかな?色々と想像が湧いてきて面白いのですが、如何せん私はイタリアとフランスには実際に行ったことが無い(陽気なイタリア人と適当なフランス人といった漠然としたイメージぐらいしかない)ので、空想の域を出ません。

2016年7月26日火曜日

vgsdrun で ステップ実行

vgsdrun(vgs-cpu付属のデバッグ実行コマンド)にステップ実行機能を追加してみました。
これは実際に動かしてみると楽しい。
楽しい?
...いや、私だけかもしれません。
ポケモンgoの方が楽しいですね。

インストールから動かすまでの手順は下記の通り。

$ git clone https://github.com/suzukiplan/vgs-cpu.git
$ cd vgs-cpu
$ make build
$ ./vgsdrun src/test/asm_mul.asm  -s
assembling: src/test/asm_mul.asm on memory
starting debug run.
00000000: ----- start-a -----
00000000: 08 E8 03               : line#00006 > LD   A, 1000
00000003: 6F 64                  : line#00007 > MUL  A, 100
00000005: A7 A0 86 01 00         : line#00008 > CMP  A, 100000
0000000a: F8 08 03 00 00         : line#00009 > JNE  $308 (test-failed)
> h
command usage:
- h     ... help
- r     ... show registers
- q     ... quit
- other ... execute next line
> r
registers:
c->r.a = 000186A0, c->r.b = 00000000, c->r.c = 00000000, c->r.d = 00000000
c->r.p = 0000000A, c->r.s = 00000000, c->f.z = 00000000, c->f.q = 00000000
> q
$

vgsdrunを実行すると以下のようにコマンド入力待ちになります。

00000000: ----- start-a -----
00000000: 08 E8 03               : line#00006 > LD   A, 1000

上記は1行上の命令(08 E8 03)をこれから実行するという意味です。
enter キーを押せば実行して以下のように表示されます。

00000000: ----- start-a -----
00000000: 08 E8 03               : line#00006 > LD   A, 1000
00000003: 6F 64                  : line#00007 > MUL  A, 100

ちゃんとエスケープで綺麗に表示してます。
復帰(\r)や改行(\n)とかは割とよく使うかもしれませんが、1行上に戻るという中々普通に生活(プログラミング)していると使わないエスケープを使っています。
printfで書くと以下のような感じ。

printf("\033[1A");

ぐぐっても1発では出てこかなかったけど、C/C++言語で作るコマンドインタフェース(CLI)のプログラムで「1行上の行に戻りたい」みたいなニーズは少ないのだろうか。
なお、WindowsのMS-DOSプロンプトでちゃんと動くかは未確認です。

2016年7月24日日曜日

vgsdrun (デバッグ実行コマンド)

vgsasmのテスト(アセンブル+実行テスト)をもりもり実施中なのですが、アセンブリ言語自体のコーディングミスでテストがコケるというケース(=テストケースの間違い)が割と多い。

まぁ、それ自体は仕方のないことですが、どういう経路を辿ってエラーになったのかを特定するのが割とツライ。

という訳で、vgsdrun というデバッグ用コマンドを作ってみました。
https://github.com/suzukiplan/vgs-cpu/pull/10

これでアセンブリ言語のソースを実行すると、以下のように実行経過の情報をズラズラと出力していきます。

$ ./vgsdrun src/test/asm_add_a.asm 
assembling: src/test/asm_add_a.asm on memory
starting debug run.
00000000: 08 E8 03               : line#00006 > LD   A, 1000
00000003: 5D 00                  : line#00007 > ADD  A, 0
00000005: A6 E8 03               : line#00008 > CMP  A, 1000
00000008: F8 02 01 00 00         : line#00009 > JNE  $102
0000000d: F5 02 01 00 00         : line#00010 > JZ   $102
00000012: 5D FF                  : line#00011 > ADD  A, 255
00000014: A6 E7 04               : line#00012 > CMP  A, 1255
00000017: F8 02 01 00 00         : line#00013 > JNE  $102
0000001c: F5 02 01 00 00         : line#00014 > JZ   $102
00000021: 5E 00 01               : line#00015 > ADD  A, 256
00000024: A6 E7 05               : line#00016 > CMP  A, 1511
00000027: F8 02 01 00 00         : line#00017 > JNE  $102
0000002c: F5 02 01 00 00         : line#00018 > JZ   $102
00000031: 5E FF FF               : line#00019 > ADD  A, 65535
00000034: A7 E6 05 01 00         : line#00020 > CMP  A, 67046
00000039: F8 02 01 00 00         : line#00021 > JNE  $102
0000003e: F5 02 01 00 00         : line#00022 > JZ   $102
00000043: 5F 00 00 01 00         : line#00023 > ADD  A, 65536
00000048: A7 E6 05 02 00         : line#00024 > CMP  A, 132582
0000004d: F8 02 01 00 00         : line#00025 > JNE  $102
00000052: F5 02 01 00 00         : line#00026 > JZ   $102
00000057: 5F 1A FA FD FF         : line#00027 > ADD  A, -132582
0000005c: F6 02 01 00 00         : line#00028 > JNZ  $102
00000061: 09 78 56 34 12         : line#00031 > LD   A, $12345678
00000066: 12 00 00 00 00         : line#00032 > ST   A, [0]
0000006b: 07 00                  : line#00033 > LD   A, 0
0000006d: 63 00 00 00 00         : line#00034 > ADD  A, [0]O
00000072: A5 78                  : line#00035 > CMP  A, $78
00000074: F8 02 01 00 00         : line#00036 > JNE  $102
00000079: F5 02 01 00 00         : line#00037 > JZ   $102
0000007e: 5F 88 FF FF FF         : line#00038 > ADD  A, -120
00000083: F6 02 01 00 00         : line#00039 > JNZ  $102
00000088: 64 00 00 00 00         : line#00040 > ADD  A, [0]H
0000008d: A6 78 56               : line#00041 > CMP  A, $5678
00000090: F8 02 01 00 00         : line#00042 > JNE  $102
00000095: F5 02 01 00 00         : line#00043 > JZ   $102
0000009a: 5F 88 A9 FF FF         : line#00044 > ADD  A, -22136
0000009f: F6 02 01 00 00         : line#00045 > JNZ  $102
000000a4: 65 00 00 00 00         : line#00046 > ADD  A, [0]
000000a9: A7 78 56 34 12         : line#00047 > CMP  A, $12345678
000000ae: F8 02 01 00 00         : line#00048 > JNE  $102
000000b3: F5 02 01 00 00         : line#00049 > JZ   $102
000000b8: 5F 88 A9 CB ED         : line#00050 > ADD  A, -305419896
000000bd: F6 02 01 00 00         : line#00051 > JNZ  $102
000000c2: 1E 00 00 11 11         : line#00054 > LD   B, $11110000
000000c7: 32 11 11               : line#00055 > LD   C, $00001111
000000ca: 48 11 11 11 11         : line#00056 > LD   D, $11111111
000000cf: 60                     : line#00057 > ADD  A, B
000000d0: A7 00 00 11 11         : line#00058 > CMP  A, $11110000
000000d5: F8 02 01 00 00         : line#00059 > JNE  $102
000000da: F5 02 01 00 00         : line#00060 > JZ   $102
000000df: 61                     : line#00061 > ADD  A, C
000000e0: A7 11 11 11 11         : line#00062 > CMP  A, $11111111
000000e5: F8 02 01 00 00         : line#00063 > JNE  $102
000000ea: F5 02 01 00 00         : line#00064 > JZ   $102
000000ef: 62                     : line#00065 > ADD  A, D
000000f0: A7 22 22 22 22         : line#00066 > CMP  A, $22222222
000000f5: F8 02 01 00 00         : line#00067 > JNE  $102
000000fa: F5 02 01 00 00         : line#00068 > JZ   $102
000000ff: 46 01                  : line#00070 > LD   D, 1
00000101: 00                     : line#00071 > BRK 

[registers]
c->r.a = 22222222, c->r.b = 11110000, c->r.c = 00001111, c->r.d = 00000001
c->r.p = 00000101, c->r.s = 00000000, c->f.z = 00000000, c->f.q = 00000000
$

最初は、普通のgdbやxdbなどと同じようなステップ実行コマンドを用意しようと思ったのですが、それを作ろうとするとディスアセンブラを作らなければならず、ディスアセンブラ自体、後々必要になるかもしれませんが、今のところ必要になりそうな気配が無い。

という訳で、vgs-asm と vgs-cpu のコードをベースにして簡単に作ってみたのが、このvgsdrun コマンドです。

仕組みは物凄く単純で、vgs-asmは行バッファという領域にオペコードに変換したデータを持っているので、その情報をvgs-cpuの命令実行サイクル時にコールバックしてプログラムレジスタから該当する行バッファの内容を表示してあげるというもの。

ディスアセンブラをガチで作ると多分2000行の開発コストが掛かりますが、この方式ならだいたい200行ぐらいの改造(要するに労力的には1/10の作業量)で作れました。

まぁ、こういう所で削っていかないと、いつまで経ってもモノが完成しないので。

今回のCPU開発(というかVGS mk-III開発)のゴールは、
1. CPU(vgs-cpu)を自作する
2. アセンブラ(vgs-asm)を自作する
3. VGS mk-III の SDK をWindows + Mac + Linuxでザックリ使えるレベルで仕上げる
4. Invader Block を VGS mk-III で作って何処かにリリース
という風に想定していて、現在はとりあえず1と2が一区切りついた段階です。
前記事で完成したと言いましたが、アレは初期目標段階に達した(マイルストーンをクリアした)という意味で、まだまだ実際にゲームを作るのには不足した機能が割とあります。

あまり最初から完璧なモノを仕上げるより、とりあえず次フェーズに進めそうな形にしておき、次フェーズを進めながら随時細かいエンハンスを繰り返していくという開発モデル(だいたいアジャイル)です。

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

コンパイラ?

コンパイラは甘え

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

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