GBプレイヤーで縦画面のテストをしていたら動作が妙にガクガクするので気 になった。4〜5秒に一度、一瞬止まる感じがする。 NTSCが59.94Hz、GBAが59.72Hzなので、1秒間に0.22フレームずれる計算に なり、ということは5秒に一度、フレームスキップが入るのかもしれない。 今度キャプチャして確認してみようかと思う。 ところで0.22フレームで合ってる? あれれ、どうなっているんだこれは?
GCCで使用できる指定初期化子(C99にも取り込まれている)はenumと組み合 わせると、キャラクター配列を作るときに便利だね。後になって新しいパターンをあいだに挿入したくなったとき、いちいち番号 を書き換えなくても済むのが素晴らしいのだ。enum { chr_walk_pattern, chr_run_pattern, chr_sleep_pattern, }; const struct { ANIME_CHR *anime_dat; int anime_number; int anime_wait; } Charactor[] = { [chr_walk_pattern] = {&chr_walk, 4, 2}, [chr_run_pattern] = {&chr_run, 4, 1}, [chr_sleep_pattern] = {&chr_sleep, 2, 6}, };
中ボスキャラが一定のダメージを受けると攻撃手段を変える、という処理を 作っていて、それまで保持していた攻撃タスクを捨てて新しい攻撃タスクを 生成するという風に実装した。 捨てるときは、子タスクの死亡フラグを立てて勝手に死んでもらうようにし ていた。(更に子供・兄弟がいるときは勝手に連鎖して死んでもらう)まあ、こんな感じで。 んで、新しい子供の動作が出来上がったところでテストプレイしてみると、 いざ新攻撃だ!と思ったところでボスの攻撃がピタリと止まってしまった。 なぜだ! 坊やだったからさ。 まあネタは置いといて何度かテストしてみると、ちゃんと攻撃してくるとき と来ないときがあることが判明した。で、よくよく調べてみると新しく作っ た子タスクの生存状態を初期化し忘れていてenemy->child->status = DEAD;のままだったという……。たまたま他のタスクが、攻撃タスクで言うところ の status == ALIVEのまま破棄されて、その要素を使いまわしたときに攻撃 してきていたようだ。そういうわけでちゃんと攻撃してくるのはバグだった。 うん。ポカどころか渾身のミスだね。こうして晒すことによって、バンバン 信用を失っていくのもそれはそれで。 全然関係ない話になるけど、GBAのちっこい画面でテストプレイして目が慣れ てしまうと、ゲーセンのでっかい縦画面が全然目に入らなくて困る。つまり どういうことかと言うと『虫姫を 二面で終える 昼下がり』enemy->child->status = DEAD;
ゲームループが1フレームに間に合わなかったときに、ループの最後でHALT すると次フレームを丸々損してしまう。ひょっとしたら次フレームで必要な ループは残された時間内に収まるかもしれないし。 なら、おっかけで処理すれば、とか思うのだけど、残された時間に収まらな かった場合を考えると自転車操業になってしまうので、どうしたもんかなー とか考えてた。 先行処理しとくって手もあるけど、すると今度は入力遅延ですよ。 要するにHALTにこだわらなくてもいーじゃん?という意識変革が俺の中で起 こりつつあるのだけど、処理落ちしてもいいならHALTしたっていーような気 もするじゃん?どっちだよ!俺の明日はどっちだよ! ちなみに、今のところ間に合ってるから。こんなこと考えなくても十分だか ら。二つで間に合ってるから。
水を得た魚のようにアセンブリを書きまくっていたが、結局はコンパイラに 勝てなかったので翼を折られた天使であった。 そこで、ふと手を休めて自分を見直してみると、手段と目的が逆転している ことに気づいてしまった。ゲームを作るために環境を整備していたはずが、 いつの間にか環境を作ることのみに夢中になっていたというアレ。 そういうわけでアレの続きを開始したが、モリモリ進んでいるような、設計 を見直したくなるような、そのなんだ、アレだ。アレが多くなってきたので 俺にはPSPのアレが必要だ。脳を鍛えるアレ。 それはさておき、本日のポカミス。メインループをこう記述して、毎フレーム一回ずつTaskExec()が実行されて いた。今までVBLANK割り込みしか使ってなかったので、それで正常に動いて いたのだが、HBLANK割り込みで画面エフェクトを作ってみたら、1ライン毎 の割り込みでHALTが解除されて早回しがかかってしまったという。 止めたいと思っても止まらないので──そのうち男はHALTを使うのをやめた。int main(void) { while (1) { asm("swi 0x0002"); // Halt TaskExec(); } }
を買ってきた。「ARMアセンブラ・コードを理解しよう」という記事が目的 だったのだけど、ARMメモとARM7TDMIの部屋を一通り読んで頭に入れてから gccに最適化無しで吐かせたコードを眺めれば済んでしまう内容だったので 立ち読みしてから買うかどうか決めれば良かったかもしれない。 そこから先に進みたければやはり、それなりのアレをナニしなけりゃならん ね。
gcc の吐くコードを眺めると条件実行がさほど使われて無いことに気づく。 じゃあ条件実行を使いまくればいーじゃんという素人考えでリファレンスと 格闘しながら書いてるんだけど、結局のところコンパイラに勝ててない。 というか、条件付き命令の使いどころがあんま思いつかないよ。4ニーモニッ ク以上にまたがる様なら分岐した方が速い様な気もするし。
asm文一つに複数の命令を書きたい場合のように一命令ごとにダブルクォーテーションで括って、しかも命令の最後 は\nで締めないといけないと思ってたんだけど、実はasm ( "add r0, r0, r1 \n" "subs r1, r0, #0xff \n" );セミコロンで区切ればいちいちダブルクォーテーションで括ったり改行記号 を入れたりしなくていいようだ。今までこのような書き方をしてるところを 見たことが無いんだけど、何か副作用でもあるんだろうか? あ、無いけど、あるね。 -Sでアセンブリコードを吐かせると……。asm (" add r0, r0, r1; subs r1, r0, #0xff; ");
それが終わってしまって残念に思っている。辛い。
最近の俺はドリキャスづいていて、今はトライジールとスペースチャネル5 をやっているのだが、スペチャンをやっていたら何故かCaptain EOが見たく なったのでGoogle Videoで検索してみたら全く引っかからなかったのでGoo- gle Videoは駄目だな!でもGoogleで検索してみたらすぐ出てきたよ。ネット は千葉大だわ……。 中身を殆ど覚えてなかったけど、観たらなぜスペチャンをやってCaptain EO が見たくなったのかがよく分かった。マイコー先生はマジかっこいいなぁ。
もうちょいなんとかするかと思って、なんとかしてるんだけどなんともなら ないよ。とにかくミキサをどうにかしないと話が進まないので、そればっか 弄ってる。つーかひらがなが多いよ。 で、弄って一番効果が大きかったのはサチュレーションだった。 これまでがこんな感じ。分岐が二回も入っていや〜んなので、飽和演算でググってひっかかったアレ、 というかくりあき先生のところに書いてあった飽和演算のアレを試してみる。if (m0 > 127) { m0 = 127; } else if (m0 < -127) { m0 = -127; }すると、約1%も速くなったよすげええええええええええええええええ11 という夢を正月に見ました。m0 += 128; if (m0 & 0xffffff00) m0 = (m0 >> 24) ^ 0xff; m0 -= 128;
NDSで計ったら、今のところ約59.83Hzっぽい。
GBA用の測定ツールも作っているのでそのうち。 (2006/01/30 15:59:58)
VSYNCカウント中
NDS(ARM9)138万回、 59.82Hzまで確定。
GBmicro 25万回、 59.7Hzまでは確定。 (2006/01/30 18:30:33)
経過フレーム数を表示して1ドットずつスクロールするだけのテスト
ツールを、GBPからS端子経由にて 640*480 29.97fpsでキャプチャし
たのちに、aviutlで59.94fpsとして読み込んで奇数・偶数フィールド
に分離してみたのですが、稀に連続して4フレーム落ちてました。
(4フレームも止まったら目に見えてガクガクするよなあ)
一応そのときの様子と、テストに使ったソースをアップしておきます。
動画の方は容量が大きいため最初の60フレームだけを切り出しました。
http://www.liarsoft.org/data/gbp_test.zip
http://www.liarsoft.org/data/gbp_test_rom.zip (2006/01/30 18:48:54)
>59.7Hzまでは確定
お疲れ様です。
GBAは1ドット表示するために4サイクル必要で
H(240+96) * V(160+68) * 4 = 280,896
GBAのクロックをそれで割って
16MHz / 280896 = 59.7275...
と、机上計算でもそういう数字が出るみたいですが、
実機で確認出来たのは安心しますね。
ところで http://www.bottledlight.com/ds/index.php/Video/Screens
によると、NDSの場合6サイクル必要で
32MHz / ( H(256+99) * V(192+71) * 6 ) = 59.8983...
という計算になるようですが59.82Hzですか。
0.07くらいだったら誤差の範囲だろうけど……。 (2006/01/30 19:21:58)
クロックの話はここで書いてます
http://www.pat.hi-ho.ne.jp/sata68/200601.html#26_gogo2
そして、テストプログラムです。
http://www.pat.hi-ho.ne.jp/sata68/200601.html#30_yoru
GBA,GBASP,GBm,NDSはあるけど
GBPは手元にないので気になりますね。 (2006/01/30 22:33:49)
なるほど、1000*1000ですか!それなら59.82でピタリですね。
テストプログラムなのですが、私が使っているカートはRTC無しの
F2A ProなのでGBPで計測が出来ません。GBPはミクロと違って
GB/GBCもプレイできるので、GBAと同じなのでは無いかなあ。
……あっ、なんでミクロで計測してるのかやっと分かった(^^;
クロック周波数が16.756MHz * 1の可能性があるわけですか。
ああなるほどなぁ。だから計ってたんですか。 (2006/01/31 00:17:11)
ひとまずこんな状況
http://www.pat.hi-ho.ne.jp/sata68/200601.html#31
GBm,NDS,NDSのGBAモードでバラバラ。 (2006/01/31 15:16:26)
そのフレームレートをPCMのサンプリングレートに換算してみると……
(GBAを16,776,000Hzとして1フレームあたりのサンプルバッファ528バイト
=サンプリングレート31533.83Hzを基準にする)
GBm: 31533.74Hz
NDS: 31496.26Hz
コレを聴き分け出来る人は流石にいないだろうな。 (2006/02/01 01:20:33)