前回の続きです。
C言語でスーファミ用のソフト開発(3)BGの表示 - takuya matsubara blog
今回はスプライトを表示します。
PVSnesLIbでのスプライト表示する方法は大きく分けて2つあります。「ダイナミックスプライト」というエンジンを使う方法と、それを使わない方法です。
公式ページにダイナミックスプライトを使ったサンプルがあります。
https://github.com/alekmaul/pvsneslib/tree/master/snes-examples/graphics/Sprites/
「DynamicEngineSprite」の実行画面です。64個のスプライトがアニメーションしながら同時に動いています。ピンとこないかもしれませんが、スーファミはCPUが遅いので、ここまでやって処理落ちしないのは凄いことなのです。ただし、Wikiのダイナミックスプライトのページがまだ未完成で使い方がよくわからないのが難点です。
ダイナミックスプライトを使わず、普通にスプライトを表示したいだけなら、簡単です。
・oamInitGfxSet関数を呼んで、VRAMにパターンとパレットを登録する。
・oamSet関数を呼んでスプライトを動かす。
・メインループでWaitForVBlank関数を毎回呼ぶ。
これだけです。この他、表示サイズを変更したい場合にはoamSetExを呼び出します。
スプライトでオリジナルの画像を動かす例を紹介します。
まず、スプライトの画像を用意します。512枚のパターン(タイル)を登録する場合、128×256ピクセルの画像が必要です。使える色は16色までです。自分の場合は16色のbmpファイルで保存しました。ファイル名が「resource_sp.bmp」の場合だと、makefileの書式は次のようになります。
resource_sp.pic: resource_sp.bmp$(GFXCONV) -s 8 -o 16 -u 16 -p -t bmp -i $<
これでパターンとパレットのファイルが作成されます。前回のBGの時と違って、パレット番号を指定する必要がありません。
スプライトを画面内でバウンドさせて、fps(frame per second)を測定するというプログラムを作ってみました。タイマー(snes_vblank_count)で1秒を計測して、その間にメインループが何周したかでfpsを求めています。
上記の画面だと、スプライトを32個表示しつつ、60fpsを維持しています。満足な結果です。
スプライトには、SMALLとLARGEの2種類があります。
LARGEでも全く問題なく60fpsを維持できています。SMALLでもLARGEでもCPUの負担は変わらないようです。
スプライトを48個表示すると、30fpsに落ちてしまいました。処理落ちです。静止画だと伝わりませんが、スローモーションのようにスプライトの動きがノロノロです。VSyncまでに処理が終わらないので、次のVSyncまで待ってしまうので、速度が半減してしまいます。
スーファミにはCPUの速度を変更する機能があります。デフォルト設定では「SLOWROM」ですが、これを「FASTROM」に変更します。
FASTROMにするには、makefileの先頭に「FASTROM=1」と記述するだけです。これで動作周波数が2.68MHz → 3.58MHzになります。
、、、期待したほど速くなってくれません。2年前に発売されたメガドライブが7.67MHzってことを考えると、かなり遅いと思います。
FASTROMに変更した結果、30fps → 60fpsに上がりました。
スプライトが64個だと、FASTROMでも30fpsに処理落ちしてしまいます。
やはり、たくさん表示したい場合にはダイナミックスプライトを導入したほうが良いですね。
スプライトを128個表示してみました。20fpsにまで落ちました。
一応、対策方法はあって、oamSet関数を極力呼ばないようにすれば、処理落ちを軽減できます。2フレームに1回だけ動かすとか、細かい工夫が必要です。
エミュレータによる処理落ちの再現がどこまで正確なのかが不明です。そこで、ROMに焼いて、実機で動かしてみました。
動画にしてみました。実機でもスプライトが64個になった時点で処理落ちします。エミュレータによる処理落ちの再現はかなり正確であると実感しました。
コードはGitHubで公開しています。
↓
続き